📄 diag_l1.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 + -