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

📄 diag_l0_br.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.
 *
 *************************************************************************
 *
 * Diag, Layer 0, Interface for B. Roadman BR-1 Interface
 *
 *	Semi intelligent interface, supports only J1979 properly, and does not
 *	support ISO14230 (KWP2000). In ISO9141-2 mode, only supports the
 *	ISO9141-2 address (0x33h)
 *
 *   http://www.abcwc.net/accounts/quanta/index.html
 *
 * Thank you to B. Roadman for donation of an interface to the prject
 *
 */

/*
 * Interface is 0-3 and represents serial devices connected
 * to /dev/ttyS0 -> /dev/ttyS3  - ie com0 -> com3
 *
 * SubInterface isnt used (as we have no muxing ability on one of these devices)
 */


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

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

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

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

#include "diag_iso14230.h"

static char *cvsid = "$Id: diag_l0_br.c,v 1.14 2002/06/17 21:55:57 rpalmeida Exp $";

#define DIAG_MODULE	"diag_l0_br"

struct diag_l0_br_device
{
	int dev_fd;

	int dev_features;	/* Device features */
	char dev_name[1024];	/* device name */

	diag_ttystate_t	dev_ttystate;	/* Holds OS specific tty info */

	int dev_state;		/* State for 5 baud startup stuff */
	u_int8_t dev_kb1;	/* KB1/KB2 for 5 baud startup stuff */
	u_int8_t dev_kb2;

	int dev_protocol;	/* Protocol running on this device */

	u_int8_t	dev_rxbuf[1024];/* Receive buffer */
	int		dev_rxlen;	/* Length of data in buffer */
	int		dev_rdoffset;	/* Offset to read from to */

	u_int8_t	dev_txbuf[16];	/* Copy of last sent frame */
	int		dev_txlen;	/* And length */

	u_int8_t	dev_framenr;	/* Frame nr for vpw/pwm */
};

/*
 * Device features (depends on s/w version on the BR-1 device)
 */
#define BR_FEATURE_2BYTE	0x01	/* 2 byte initialisation responses */
#define BR_FEATURE_SETADDR	0x02	/* User can specifiy ISO address */
#define BR_FEATURE_FASTINIT	0x04	/* ISO14230 fast init supported */

/*
 * States
 */
#define BR_STATE_CLOSED		0x00
#define BR_STATE_KWP_SENDKB1	0x01
#define BR_STATE_KWP_SENDKB2	0x02
#define BR_STATE_KWP_FASTINIT	0x03	/* Fast init needed */
#define BR_STATE_OPEN		0x20	/* Open and working */


#define DIAG_L1_BR_NUMDEV 4

struct diag_l0_br_device	diag_l0_br_devices[DIAG_L1_BR_NUMDEV];

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

int diag_l0_br_getmsg(int fd, u_int8_t *dp, int timeout);

int diag_l0_br_initialise(struct diag_l0_br_device *dev, u_int8_t type,
		u_int8_t addr);

int diag_l0_br_writemsg(struct diag_l0_br_device *dev, u_int8_t type,
	 char *dp, int txlen);

/* Types for writemsg - corrosponds to top bit values for the control byte */
#define BR_WRTYPE_DATA	0x00
#define BR_WRTYPE_INIT	0x40

/*
 * Init must be callable even if no physical interface is
 * present, it's just here for the code here to initialise its
 * variables etc 
 */
int
diag_l0_br_init(void)
{
	int i;
	struct sched_param p;

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

	for (i = 0; i < DIAG_L1_BR_NUMDEV; i++)
	{
		/* FD == -1 is magic "closed" flag */
		diag_l0_br_devices[i].dev_fd = -1;
		/*
		 * All interfaces support sending 3 byte ISO init msgs, old
		 * ones just ignore the extra byte
		 */
		diag_l0_br_devices[i].dev_features = BR_FEATURE_SETADDR;
	}

	/* Set real time UNIX scheduling */
	p.sched_priority = 1;
  	if ( sched_setscheduler(getpid(), SCHED_FIFO, &p) < 0)
	{
		perror("sched_setscheduler");
	}

	return (0);
}


struct diag_l0_br_device *
diag_l0_br_finddev(int fd)
{
	int i;
	struct diag_l0_br_device *dev;

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

	return (NULL) ;
}

/*
 * Open the diagnostic device, returns a file descriptor
 * records original state of term interface so we can restore later
 */
int
diag_l0_br_open(int iInterface, int iProtocol)
{
	struct diag_l0_br_device *dev;
	struct serial_struct sinfo;
	struct termios tinfo;
	int flags, rv, i;
	u_int8_t buf[1024];
	int buflenn;

	if (diag_l0_debug & DIAG_DEBUG_OPEN)
	{
		fprintf(stderr, "%s: open subinterface %d protocol %d\n",
			DIAG_MODULE, iInterface, iProtocol);
	}

	diag_l0_br_init();

	if (iInterface >= DIAG_L1_BR_NUMDEV)
	{
		fprintf(stderr, "%s: requested i/f %d is too big, max %d\n",
			DIAG_MODULE, iInterface, DIAG_L1_BR_NUMDEV);
		return(-1);
	}

	dev = &diag_l0_br_devices[iInterface];

	if (dev->dev_fd != -1)
	{
		/* Device is already open */
		fprintf(stderr, "%s: subinterface %d already open with FD %d\n",
			DIAG_MODULE, dev->dev_fd);
		return(-1);
	}
	dev->dev_rdoffset = 0;
	dev->dev_txlen = 0;
	dev->dev_framenr = 0;
	dev->dev_state = BR_STATE_CLOSED;

	(void)sprintf(dev->dev_name, "/dev/ttyS%d", iInterface);

	/*
	 * Synchronous open, so writes only return once data is
	 * sent out
	 */
	dev->dev_fd = open(dev->dev_name, O_RDWR | O_SYNC);
	if (dev->dev_fd >= 0)
	{
		if (diag_l0_debug & DIAG_DEBUG_OPEN)
			fprintf(stderr, "%s: Device %s opened, fd %d features 0x%x\n", 
				DIAG_MODULE, dev->dev_name, dev->dev_fd, dev->dev_features);
	}
	else
	{
		if (diag_l0_debug & DIAG_DEBUG_OPEN)
			fprintf(stderr, "%s: Device %s failed to open", 
				DIAG_MODULE, dev->dev_name);
		return(-1);
	}

	/* Initialise/save tty state */
	if (diag_os_tty_init(dev->dev_fd, &dev->dev_ttystate) < 0)
	{
		fprintf(stderr, "%s: tty_init failed for %s\n",
				DIAG_MODULE, dev->dev_name);
		diag_l0_br_close(dev->dev_fd);
		return(-1);
	}

	/* And set to 19200 baud , 8N1 */
	if (diag_os_tty_setup(dev->dev_fd, &dev->dev_ttystate, 19200, 8, 1,
		DIAG_L1_PAR_N) < 0)
	{
		fprintf(stderr, "%s: open: setspeed failed\n", DIAG_MODULE);
		diag_l0_br_close(dev->dev_fd);
		return (-1);
	}

	/* Read any old data hanging about on the port */
	rv = diag_os_read(dev->dev_fd, buf, sizeof(buf), 50);
	if ((rv > 0) && (diag_l0_debug & DIAG_DEBUG_OPEN))
	{
		fprintf(stderr, "%s: %d junk bytes discarded: ", DIAG_MODULE,
			rv);
		for (i=0; i<rv; i++)
			fprintf(stderr, "0x%x ", buf[i] & 0xff); 
		fprintf(stderr,"\n");
	}
	/*
	 * Initialise the BR1 interface by sending the CHIP CONNECT
	 * (0x20h) command, we should get a 0xFF back
	 */
	buf[0] = 0x20;
	if (diag_l0_br_write(dev->dev_fd, buf, 1) < 0)
	{
		if (diag_l0_debug & DIAG_DEBUG_OPEN)
			fprintf(stderr, "%s: CHIP CONNECT write failed fd %d\n",
				DIAG_MODULE, dev->dev_fd);
		diag_l0_br_close(dev->dev_fd);
		return(DIAG_ERR_BADIFADAPTER);
	}
	/* And expect 0xff as a response */
	if (diag_os_read(dev->dev_fd, buf, 1, 100) < 1)
	{
		if (diag_l0_debug & DIAG_DEBUG_OPEN)
			fprintf(stderr, "%s: CHIP CONNECT read failed fd %d\n",
				DIAG_MODULE, dev->dev_fd);
		diag_l0_br_close(dev->dev_fd);
		return(DIAG_ERR_BADIFADAPTER);
	}
	if (buf[0] != 0xff)
	{
		if (diag_l0_debug & DIAG_DEBUG_OPEN)
			fprintf(stderr, "%s: CHIP CONNECT rcvd 0x%x != 0xff, fd %d\n",
				DIAG_MODULE, buf[0], dev->dev_fd);
		diag_l0_br_close(dev->dev_fd);
		return(DIAG_ERR_BADIFADAPTER);
	}

	/* If its J1850, send initialisation string now */
	rv = 0;
	switch (iProtocol)
	{
	case DIAG_L1_J1850_VPW:
		rv = diag_l0_br_initialise(dev, 0, 0);
		break;
	case DIAG_L1_J1850_PWM:
		rv = diag_l0_br_initialise(dev, 1, 0);
		break;
	case DIAG_L1_ISO9141:
	case DIAG_L1_ISO14230:
		/* This initialisation is done in the SLOWINIT code */
		break;
	}
	if (rv < 0)
	{
		diag_l0_br_close(dev->dev_fd);
		return(rv);
	}

	dev->dev_protocol = iProtocol;

	if (diag_l0_debug & DIAG_DEBUG_OPEN)
	{
		fprintf(stderr, "%s: open succeeded fd %d features 0x%x\n",
			DIAG_MODULE, dev->dev_fd, dev->dev_features);
	}
	return (dev->dev_fd) ;
}

int
diag_l0_br_close(int fd)
{
	struct diag_l0_br_device *dev;

	dev = diag_l0_br_finddev(fd);	/* Find the dev block */
		
	if (diag_l0_debug & DIAG_DEBUG_CLOSE)
		fprintf(stderr, "%s: device %x fd %x closing\n",
			DIAG_MODULE, dev, fd);

	if (dev)
	{
		(void) diag_os_tty_restore(fd, &dev->dev_ttystate);
		close(dev->dev_fd);
		dev->dev_fd = -1;
	}
	return (0);
}

/*
 * Do BR interface protocol initialisation,
 * returns -1 on error or the keybyte value
 */
int
diag_l0_br_initialise(struct diag_l0_br_device *dev, u_int8_t type,
		u_int8_t addr)
{
	u_int8_t txbuf[3];
	u_int8_t rxbuf[1024];
	int rv;
	int timeout;
	int fd = dev->dev_fd;

	/*
	 * Send initialisation message, 42H 0YH
	 * - where Y is iniitialisation type
	 */
	memset(txbuf, 0, sizeof(txbuf));
	txbuf[0] = 0x41;
	txbuf[1] = type;
	txbuf[2] = addr;

	if (type == 0x02)
	{
		timeout = 6000;		/* 5 baud init is slow */
		if (dev->dev_features & BR_FEATURE_SETADDR)
		{
			txbuf[0] = 0x42;
			rv = diag_l0_br_write(fd, txbuf, 3);
		}
		else
		{
			rv = diag_l0_br_write(fd, txbuf, 2);
		
		}
		if (rv < 0)
			return(rv);
	}
	else
	{
		timeout = 100;
		rv = diag_l0_br_write(fd, txbuf, 2);
		if (rv < 0)
			return(rv);
	}

	/*
	 * And get back the fail/success message
	 */
	if ((rv = diag_l0_br_getmsg(fd, rxbuf, timeout)) < 0)
		return(rv);

	/*
	 * Response length tells us whether this is an orginal style
	 * interface or one that supports ISO14230 fast init and ISO9141
	 * 5 baud init address setting. This means that it is vital that
	 * a J1850 initialisation request was done before a 9141 one ...
	 */
	dev->dev_features = 0;
	switch (rv)
	{
	case 1:	
		dev->dev_features |= BR_FEATURE_SETADDR; /* All allow this */
		break;
	case 2:
		dev->dev_features |= BR_FEATURE_2BYTE;
		dev->dev_features |= BR_FEATURE_SETADDR;
		dev->dev_features |= BR_FEATURE_FASTINIT;
		break;
	default:
		return(DIAG_ERR_BADDATA);
	}

	return(rxbuf[0]);
}

/*
 * Do 5 Baud initialisation
 *
 * This is simple on the BR1 interface, we send the initialisation
 * string, which is 41H 02H and the interface responds with
 * a 1 byte message (i.e length byte of 01h followed by one of the
 * keybytes
 */
diag_l0_br_slowinit( struct diag_l0_br_device *dev, struct diag_l1_init *in)
{
	/*
	 * Slow init
	 * Build message into send buffer, and calculate checksum
	 */
	u_int8_t buf[1024];
	int rv;

	buf[0] = 0x02;
	buf[1] = in->addr;

	/* Send the initialisation message */
	if (dev->dev_features & BR_FEATURE_SETADDR)
		rv = diag_l0_br_writemsg(dev, BR_WRTYPE_INIT, buf, 2);
	else
		rv = diag_l0_br_writemsg(dev, BR_WRTYPE_INIT, buf, 1);
	if (rv < 0)
		return(rv);

	/* And wait for response */
	if ((rv = diag_l0_br_getmsg(dev->dev_fd, buf, 6000)) < 0)
		return(rv);

	/*
	 * Now set the keybytes from what weve sent
	 */
	if (rv == 1)	/* 1 byte response, old type interface */
	{
		dev->dev_kb1 = buf[0];
		dev->dev_kb2 = buf[0];
	}
	else
	{
		dev->dev_kb1 = buf[0];
		dev->dev_kb2 = buf[1];
	}

	/*
	 * And tell read code to report the keybytes on first read
	 */
	dev->dev_state = BR_STATE_KWP_SENDKB1;

	return (0);
}

/*
 * Do wakeup on the bus 
 * 
 * We do this by noting a wakeup needs to be done for the next packet for
 * fastinit, and doing slowinit now
 */
int
diag_l0_br_initbus(int fd, struct diag_l1_init *in)
{
	int rv = 0;
	struct diag_l0_br_device *dev;
	u_int8_t cbuf[1024];

	dev = diag_l0_br_finddev(fd);	/* Find the dev block */

	if (diag_l0_debug & DIAG_DEBUG_IOCTL)
		fprintf(stderr, "%s: device fd %d info %x initbus type %d proto %d\n",
			DIAG_MODULE, fd, dev, in->type,
			dev ? dev->dev_protocol : -1);

	if (!dev)
		return(-1);

	/* Empty our Receive buffer and wait for idle bus */
	(void)diag_os_read( fd, cbuf, sizeof(cbuf), 200);

	switch (in->type)
	{
	case DIAG_L1_INITBUS_5BAUD:
		rv = diag_l0_br_slowinit(dev, in);

⌨️ 快捷键说明

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