📄 diag_l0_me.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.
*
*************************************************************************
*
* 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 + -