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

📄 diag_l0_me.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 Multiplex Engineering interface
 *		Supports #T16 interface only. Other interfaces need special
 *		code to read multi-frame messages with > 3 frames (and don't
 *		support all interface types)
 *
 *   http://www.multiplex-engineering.com
 *
 */

/*
 * 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_me.c,v 1.9 2002/05/01 03:28:15 bjorn_helgaas Exp $";

#define DIAG_MODULE	"diag_l0_muleng"

#define INTERFACE_ADDRESS 0x38


/*
 * Baud rate table for converting single byte value from interface to
 * baud rate. Note the single byte value is count in 2.5microseconds for
 * receiving a bit of the 0x55
 */
int me_baud_table[] = { 0, 400000, 200000, 133333, 100000, 80000,
			66666, 57142, 50000, 44444, 
	/* 10  */ 40000, 36363, 33333, 30769, 28571, 26666,
			25000, 23529, 22222, 21052, 
	/* 20  */ 19200, 19200, 18181, 17391, 16666, 16000,
			15384, 14814, 14285, 13793, 
	/* 30  */ 13333, 12903, 12500, 12121, 11764, 11428,
			11111, 10400, 10400, 10400, 
	/* 40  */ 10400, 9600, 9600, 9600, 9600, 8888, 8695, 8510, 8333, 8163, 
	/* 50  */ 8000, 7843, 7692, 7547, 7407, 7272, 7142, 7017, 6896, 6779, 
	/* 60  */ 6666, 6557, 6451, 6349, 0, 6153, 6060, 5970, 5882, 5797, 
	/* 70  */ 5714, 5633, 5555, 5479, 5405, 5333, 5263, 5194, 5128, 5063, 
	/* 80  */ 5000, 4800, 4800, 4800, 4800, 4800, 4800, 4597, 4545, 4494, 
	/* 90  */ 4444, 4395, 4347, 4301, 4255, 4210, 4166, 4123, 4081, 4040, 
	/* 100 */ 4000, 3960, 3921, 3883, 3846, 3809, 3600, 3600, 3600, 3600, 
	/* 110 */ 3600, 3600, 3600, 3600, 3600, 3478, 3448, 3418, 3389, 3361, 
	/* 120 */ 3333, 3305, 3278, 3252, 3225, 3200, 3174, 3149, 3125, 3100, 
	/* 130 */ 3076, 3053, 3030, 3007, 2985, 2962, 2941, 2919, 2898, 2877, 
	/* 140 */ 2857, 2836, 2816, 2797, 2777, 2758, 2739, 2721, 2702, 2684, 
	/* 150 */ 2666, 2649, 2631, 2614, 2597, 2580, 2564, 2547, 2531, 2515, 
	/* 160 */ 2500, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 
	/* 170 */ 2400, 2400, 2400, 2400, 2298, 2285, 2272, 2259, 2247, 2234, 
	/* 180 */ 2222, 2209, 2197, 2185, 2173, 2162, 2150, 2139, 2127, 2116, 
	/* 190 */ 2105, 2094, 2083, 2072, 2061, 2051, 2040, 2030, 2020, 2010, 
	/* 200 */ 2000, 1990, 1980, 1970, 1960, 1951, 1941, 1932, 1923, 1913, 
	/* 210 */ 1904, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 
	/* 220 */ 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 
	/* 230 */ 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 
	/* 240 */ 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 
	/* 250 */ 1600, 1593, 1587, 1581, 1574, 1568, } ;

struct diag_l0_muleng_device
{
	int dev_fd;
	char dev_name[1024];	/* device name */

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

	int dev_wakeup;		/* Contains wakeup type for next packet */

	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[14];	/* Receive buffer */
	int		dev_rxlen;	/* Length of data in buffer */
	int		dev_rdoffset;	/* Offset to read from to */
	
};

#define MULENG_STATE_CLOSED		0x00

/* 5 baud init was successful, need to report keybytes on first recv() */
#define MULENG_STATE_KWP_SENDKB1		0x01
#define MULENG_STATE_KWP_SENDKB2		0x02

#define MULENG_STATE_RAW		0x10	/* Open and working in Passthru mode */

#define MULENG_STATE_FASTSTART		0x18	/* 1st recv() after fast init */
#define MULENG_STATE_OPEN		0x20	/* Open and working */


#define DIAG_L1_MULENG_NUMDEV 4
struct diag_l0_muleng_device	diag_l0_muleng_devices[DIAG_L1_MULENG_NUMDEV];

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

int diag_l0_muleng_getmsg(int fd, u_int8_t *dp);

/*
 * 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_muleng_init(void)
{
	int i;
	struct sched_param p;

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

	/* FD == -1 is magic unused flag */
	for (i = 0; i < DIAG_L1_MULENG_NUMDEV; i++)
		diag_l0_muleng_devices[i].dev_fd = -1;

	/* 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_muleng_device *
diag_l0_muleng_finddev(int fd)
{
	int i;
	struct diag_l0_muleng_device *dev;

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

	return (NULL) ;
}

/* Put in the ME checksum at the correct place */
int
diag_l0_muleng_txcksum(u_int8_t *data)
{
	int i, cksum;

	for (i=1, cksum = 0; i < 14; i++)
		cksum += data[i];
	data[14] = (u_int8_t)cksum;
	return (cksum);
}

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

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

	diag_l0_muleng_init();

	dev = diag_l0_muleng_finddev(-1);	/* Find an unused diag block */

	if (dev == NULL)
		return (-1);			/* No free device blocks (coding error ...) */

	(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\n", 
				DIAG_MODULE, dev->dev_name, dev->dev_fd);
	}
	else
		return(-1);

	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);
		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);
		return (-1);
	}

	/* And set DTR high and RTS low to power the device */
	if (diag_os_tty_control(dev->dev_fd, &dev->dev_ttystate, 1, 0) < 0)
	{
		fprintf(stderr, "%s: open: Ioctl TIOCMBIS failed %d\n", DIAG_MODULE, errno);
		return(-1);
	}

	/* Read any old data hanging about on the port */
	(void)diag_os_read(dev->dev_fd, buf, sizeof(buf), 5);

	dev->dev_protocol = iProtocol;
	return (dev->dev_fd) ;
}

int
diag_l0_muleng_close(int fd)
{
	struct diag_l0_muleng_device *dev;

	dev = diag_l0_muleng_finddev(fd);	/* Find an unused diag block */
		
	if (diag_l0_debug & DIAG_DEBUG_CLOSE)
		fprintf(stderr, "%s: device fd %d info %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 5 Baud initialisation
 *
 * In the case of ISO9141 we operate in the interface's "raw" mode
 * (VAG compatibility mode), in 14230 we do a slow init and send
 * a tester present message
 */
diag_l0_muleng_slowinit( int fd, struct diag_l1_init *in,
		struct diag_l0_muleng_device *dev)
{
	/*
	 * Slow init
	 * Build message into send buffer, and calculate checksum
	 */
	u_int8_t txbuf[15];
	u_int8_t rxbuf[15];
	int i,cnt;
	int rv;
	int baud;

	memset(txbuf, 0, sizeof(txbuf));
	txbuf[0] = INTERFACE_ADDRESS;

	switch (dev->dev_protocol)
	{
	case DIAG_L1_ISO9141:
		txbuf[1] = 0x20;	/* Raw mode 5 baud init */
		txbuf[2] = in->addr;
		break;

	case DIAG_L1_ISO14230:
		txbuf[1] = 0x85;
		txbuf[2] = 0x01;		/* One byte message */
		txbuf[3] = DIAG_KW2K_SI_TP;	/* tester present */
/* XXX checksum ?? */
		break;
	}

	/*
	 * Calculate the checksum, and send the request
	 */
	(void)diag_l0_muleng_txcksum(txbuf);
	rv = diag_l0_muleng_write(fd, txbuf, 15);

	if (rv < 0)
		return(rv);

	/*
	 * Get answer
	 */
	switch (dev->dev_protocol)
	{
	case DIAG_L1_ISO9141:
		/*
		 * This is raw mode, we should get a single byte back
		 * with the timing interval, then we need to change speed
		 * to match that speed. Remember it takes 2 seconds to send
		 * the 10 bit (1+8+1) address at 5 baud
		 */
		rv = diag_os_read(fd, rxbuf, 1, 2350);
		if (rv < 1)
			return(-1);

		if (rxbuf[0] == 0x40)
		{
			/* Problem ..., got an error message */

			/* Empty the receive buffer */
			while (diag_os_read(fd, rxbuf, sizeof(rxbuf), 50) > 0);

			return(-1);
		}
		baud = me_baud_table[rxbuf[0]];

		if (diag_l0_debug & DIAG_DEBUG_PROTO)
			fprintf(stderr, "%s: device fd %d setting baud to %d\n",
				DIAG_MODULE, fd, baud);

		if (baud)
			/* And set the baud rate */
			diag_os_tty_setup(fd, &dev->dev_ttystate, baud, 8, 1,
				DIAG_L1_PAR_N) ;

		dev->dev_state = MULENG_STATE_RAW;

		break;

	case DIAG_L1_ISO14230:
/* XX */
		/*
		 * Should get an ack back, rather than an error response
		 */
		if ((rv = diag_l0_muleng_getmsg(fd, rxbuf)) < 0)
			return(rv);

		if (rxbuf[1] == 0x80)
			return(-1);

		/*
 		 * Now send the "get keybyte" request, and wait for
		 * response
		 */
		memset(txbuf, 0, sizeof(txbuf));
		txbuf[0] = INTERFACE_ADDRESS;
		txbuf[1] = 0x86;
		(void)diag_l0_muleng_txcksum(txbuf);
		rv = diag_l0_muleng_write(fd, txbuf, 15);
		if (rv < 0)
			return(rv);

		if ((rv = diag_l0_muleng_getmsg(fd, rxbuf)) < 0)
			return(rv);

		if (rxbuf[1] == 0x80)	/* Error */
			return(-1);
		/*
		 * Store the keybytes
		 */
		dev->dev_kb1 = rxbuf[2];
		dev->dev_kb2 = rxbuf[3];
		/*
		 * And tell read code to report the keybytes on first read
		 */
		dev->dev_state = MULENG_STATE_KWP_SENDKB1;
		break;
	}


	return (rv);
}

/*
 * 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_muleng_initbus(int fd, struct diag_l1_init *in)
{
	int rv = 0;
	struct diag_l0_muleng_device *dev;
	u_int8_t cbuf[1024];

	dev = diag_l0_muleng_finddev(fd);	/* Find an unused diag block */

⌨️ 快捷键说明

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