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