📄 diag_l2_vag.c
字号:
/*
* !!! INCOMPLETE !!!!
*
* 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
*
* L2 driver for Volkswagen Audi Group protocol (Keyword 0x01 0x8a)
*
* !!! INCOMPLETE !!!!
*
*/
#include "diag_os.h" /* operating specific includes */
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include "diag.h"
#include "diag_l1.h"
#include "diag_l2.h"
#include "diag_l2_iso9141.h"
#include "diag_err.h"
#include "diag_general.h"
#include "diag_vag.h"
#include "diag_l2_vag.h" /* prototypes for this file */
static char *cvsid = "$Id: diag_l2_vag.c,v 1.4 2002/04/03 04:56:40 bjorn_helgaas Exp $";
extern int diag_l2_debug;
#define DIAG_MODULE "diag_l2_vag"
/*
* ISO vag specific data
*/
struct diag_l2_vag
{
u_int8_t seq_nr; /* Sequence number */
u_int8_t master; /* Master flag, 1 = us, 0 = ECU */
u_int8_t rxbuf[1024]; /* Receive buffer, for building message in */
int rxoffset; /* Offset to write into buffer */
};
#define STATE_CLOSED 0 /* Established comms */
#define STATE_CONNECTING 1 /* Connecting */
#define STATE_ESTABLISHED 2 /* Established */
/*
* Useful internal routines
*/
/*
* Decode the message header
*/
int
diag_l2_proto_vag_decode(char *data, int len,
int *hdrlen, int *datalen, int *source, int *dest,
int first_frame)
{
int dl;
if (diag_l2_debug & DIAG_DEBUG_PROTO)
{
int i;
printf("%s: decode len %d", DIAG_MODULE, len);
for (i = 0; i < len ; i++)
{
printf(" 0x%x", data[i]&0xff);
}
printf("\n");
}
dl = data[0] & 0x3f;
if (dl == 0)
{
/* Additional length field present */
switch (data[0] & 0xC0)
{
case 0x80:
case 0xC0:
/* Addresses supplied, additional len byte */
if (len < 4)
{
if (diag_l2_debug & DIAG_DEBUG_PROTO)
{
printf("%s: decode len short \n",
DIAG_MODULE);
}
return(DIAG_ERR_INCDATA);
}
*hdrlen = 4;
*datalen = data[3];
if (dest)
*dest = data[1];
if (source)
*source = data[2];
break;
case 0x00:
/* Addresses not supplied, additional len byte */
if (first_frame)
return(DIAG_ERR_BADDATA);
if (len < 2)
return(DIAG_ERR_INCDATA);
*hdrlen = 2;
*datalen = data[1];
if (dest)
*dest = 0;
if (source)
*source = 0;
break;
case 0X40:
/* CARB MODE */
return(DIAG_ERR_BADDATA);
}
}
else
{
/* Additional length field not present */
switch (data[0] & 0xC0)
{
case 0x80:
case 0xC0:
/* Addresses supplied, NO additional len byte */
if (len < 3)
return(DIAG_ERR_INCDATA);
*hdrlen = 3;
*datalen = dl;
if (dest)
*dest = data[1];
if (source)
*source = data[2];
break;
case 0x00:
/* Addresses not supplied, No additional len byte */
if (first_frame)
return(DIAG_ERR_BADDATA);
*hdrlen = 1;
*datalen = dl;
if (dest)
*dest = 0;
if (source)
*source = 0;
break;
case 0X40:
/* CARB MODE */
return(DIAG_ERR_BADDATA);
}
}
/*
* If len is silly [i.e 0] we've got this mid stream
*/
if (*datalen == 0)
return(DIAG_ERR_BADDATA);
/*
* And confirm data is long enough, incl cksum
* If not, return saying data is incomplete so far
*/
if (len < (*hdrlen + *datalen + 1))
return(DIAG_ERR_INCDATA);
return(0);
}
/*
* Internal receive function (does all the message building, but doesn't
* do call back, returns the complete message, hasn't removed checksum
* and header info
*
* Data from the first message is put into *data, and len into *datalen
*
* If the L1 interface is clever (DOESL2FRAME), then each read will give
* us a complete message, and we will wait a little bit longer than the normal
* timeout to detect "end of all responses"
*/
int
diag_l2_proto_vag_int_recv(diag_l2_conn_t *d_l2_conn, int timeout,
u_int8_t *data, int *datalen)
{
struct diag_l2_vag *dp;
int rv = 0;
/* diag_msg_t *tmsg;*/
dp = (struct diag_l2_vag *)d_l2_conn->diag_l2_proto_data;
if (diag_l2_debug & DIAG_DEBUG_READ)
fprintf(stderr,
"%s: diag_l2_vag_intrecv offset %x\n",
DIAG_MODULE, dp->rxoffset);
/* Clear out last received message if not done already */
if (d_l2_conn->diag_msg)
{
diag_freemsg(d_l2_conn->diag_msg);
d_l2_conn->diag_msg = NULL;
}
/*
* And receive the new message
*/
#if notdef
/*
* Now check the messages that we have checksum etc, stripping
* off headers etc
*/
if (rv >= 0)
{
tmsg = d_l2_conn->diag_msg;
while (tmsg)
{
struct diag_l2_vag *dp;
int hdrlen, datalen, source, dest;
/*
* We have the message with the header etc, we
* need to strip the header and checksum
*/
dp = (struct diag_l2_vag *)d_l2_conn->diag_l2_proto_data;
rv = diag_l2_proto_vag_decode( tmsg->data,
tmsg->len,
&hdrlen, &datalen, &source, &dest,
dp->first_frame);
if (rv < 0) /* decode failure */
{
return(rv);
}
#if FULL_DEBUG
printf("msg %x decode done rv %d hdrlen %d datalen %d source %02x dest %02x\n",
tmsg, rv, hdrlen, datalen, source, dest);
#endif
if (tmsg->data[0] & 0xC0 == 0xC0)
{
tmsg->fmt = DIAG_FMT_ISO_FUNCADDR;
} else {
tmsg->fmt = 0;
}
tmsg->fmt |= DIAG_FMT_FRAMED | DIAG_FMT_DATAONLY ;
tmsg->fmt |= DIAG_FMT_CKSUMMED;
tmsg->src = source;
tmsg->dest = dest;
tmsg->data += hdrlen; /* Skip past header */
tmsg->len -= (hdrlen + 1); /* And remove hdr/cksum */
dp->first_frame = 0;
tmsg = tmsg->next;
}
}
#endif
return(rv);
}
/*
* Send a byte, and ensure we get the inverted ack back
*/
int
diag_l2_proto_vag_send_byte(diag_l2_conn_t *d_l2_conn, u_int8_t databyte)
{
u_int8_t rx_data = 0;
int rv;
/* Send the data byte */
rv = diag_l1_send (d_l2_conn->diag_link->diag_l2_fd, 0,
&databyte, 1, d_l2_conn->diag_l2_p4min);
if (rv < 0)
return(rv);
/* And update the last sent timer */
(void) gettimeofday(&d_l2_conn->diag_l2_lastsend, NULL);
/* Receive the ack */
if (rx_data != ~databyte)
return(0); /* Wrong data */
return(0);
}
/*
* Send a telegram to the ECU
*
* Passed connection details, command and optional data
*/
int
diag_l2_proto_vag_send_block(
diag_l2_conn_t *d_l2_conn,
u_int8_t cmd, u_int8_t *data, u_int8_t len)
{
struct diag_l2_vag *dp;
int i, blocklen;
int rv;
u_int8_t databyte;
dp = (struct diag_l2_vag *)d_l2_conn->diag_l2_proto_data;
if (dp->master == 0)
{
/*
* We're not the master, need to receive a block
* to become the master
*/
}
/* Send the length field, which is len + seq + command + data */
blocklen = len + 3;
databyte = blocklen;
if ( (rv = diag_l2_proto_vag_send_byte(d_l2_conn, databyte)) < 0)
return(rv);
/* Now send the sequence nr */
if ( (rv = diag_l2_proto_vag_send_byte(d_l2_conn, dp->seq_nr)) < 0)
return(rv);
/* Now send the command */
if ( (rv = diag_l2_proto_vag_send_byte(d_l2_conn, cmd)) < 0)
return(rv);
/* Now send the data */
for (i=0; i < len; i++)
{
if ( (rv = diag_l2_proto_vag_send_byte(d_l2_conn, data[i])) < 0)
return(rv);
}
/* And send 0x03 as end of frame */
/* And switch to show ECU is master */
dp->master = 0;
return(0);
}
/* External interface */
/*
* The complex initialisation routine for ISOvag, which supports
* 2 types of initialisation (5-BAUD, FAST) and functional
* and physical addressing. The ISOvag spec describes CARB initialisation
* which is done in the ISO9141 code
*/
diag_l2_proto_vag_startcomms( diag_l2_conn_t *d_l2_conn, u_int16_t flags,
int bitrate, u_int8_t target, u_int8_t source)
{
struct diag_l2_vag *dp;
/* diag_msg_t msg;*/
u_int8_t data[1024];
int rv;
/* int wait_time;*/
/* int hdrlen;*/
/* int datalen;*/
/* int datasrc;*/
u_int8_t cbuf[1024];
/* int len;*/
struct diag_l1_init in;
dp = calloc(1, sizeof(struct diag_l2_vag));
if (dp == NULL)
return(DIAG_ERR_NOMEM);
d_l2_conn->diag_l2_proto_data = (void *)dp;
memset(data, 0, sizeof(data));
/*
* If 0 has been specified, use a useful default of 9600
*/
if (bitrate == 0)
bitrate = 9600;
d_l2_conn->diag_l2_speed = bitrate;
/* Set the speed as shown */
rv = diag_l1_setspeed( d_l2_conn->diag_link->diag_l2_fd,
bitrate, 8, 1, DIAG_L1_PAR_N);
if (rv < 0)
{
free(dp);
return (rv);
}
/* Empty our Receive buffer and wait for idle bus */
(void)diag_os_read( d_l2_conn->diag_link->diag_l2_fd, cbuf,
sizeof(cbuf), 200);
/* Now do 5 baud init of supplied address */
in.type = DIAG_L1_INITBUS_5BAUD;
in.addr = target;
rv = diag_l2_ioctl(d_l2_conn, DIAG_IOCTL_INITBUS, &in);
if (rv < 0)
return(-1); /* XXX */
/* Mode bytes are in 7-Odd-1, read as 8N1 and ignore parity */
rv = diag_l1_recv (d_l2_conn->diag_link->diag_l2_fd, 0,
cbuf, 1, 100);
if (rv < 0)
return(-1); /* XXX */
rv = diag_l1_recv (d_l2_conn->diag_link->diag_l2_fd, 0,
&cbuf[1], 1, 100);
if (rv < 0)
return(-1); /* XXX */
/* Keybytes are 0x1 0x8a for VAG protocol */
if (cbuf[0] != 0x01)
return(DIAG_ERR_WRONGKB);
if (cbuf[0] != 0x8a)
return(DIAG_ERR_WRONGKB);
/* Note down the mode bytes */
d_l2_conn->diag_l2_kb1 = cbuf[0] & 0x7f;
d_l2_conn->diag_l2_kb2 = cbuf[1] & 0x7f;
if ( (d_l2_conn->diag_link->diag_l2_l1flags
& DIAG_L1_DOESSLOWINIT) == 0)
{
/*
* Now transmit KB2 inverted
*/
cbuf[0] = ~ d_l2_conn->diag_l2_kb2;
rv = diag_l1_send (d_l2_conn->diag_link->diag_l2_fd, 0,
cbuf, 1, d_l2_conn->diag_l2_p4min);
}
/*
* Now receive the first 3 messages
* which show ECU versions etc
*/
return(0);
}
int
diag_l2_proto_vag_stopcomms(diag_l2_conn_t* pX)
{
/*
* Send a stopcomms message, and wait for the +ve response, for upto
* p3max - the layer 2 code that called this already turned off the
* idle timer
*/
/* XXX */
return (0);
}
/*
* Send the data
*
* - with VAG protocol this will sleep as the message is sent as each byte
* is ack'ed by the far end
*
* - after each byte reset the send timer or the timeout routine may try
* and send something
*
* 1st byte of message is command, followed by data
*/
diag_l2_proto_vag_send(diag_l2_conn_t *d_l2_conn, diag_msg_t *msg)
{
int rv = 0;
/* int i;*/
/* int csum;*/
/* int len;*/
/* u_int8_t buf[1024];*/
/* int offset;*/
struct diag_l2_vag *dp;
if (diag_l2_debug & DIAG_DEBUG_WRITE)
fprintf(stderr,
"%s: diag_l2_vag_send 0x%x msg 0x%x len %d called\n",
DIAG_MODULE, d_l2_conn, msg, msg->len);
dp = (struct diag_l2_vag *)d_l2_conn->diag_l2_proto_data;
#if xx
rv = diag_l1_send (d_l2_conn->diag_link->diag_l2_fd, 0,
buf, len, d_l2_conn->diag_l2_p4min);
#endif
if (diag_l2_debug & DIAG_DEBUG_WRITE)
fprintf(stderr, "%s: send about to return %d\n",
DIAG_MODULE, rv);
return(rv);
}
/*
* Protocol receive routine
*
* Will sleep until a complete set of responses has been received, or fail
* with a timeout error
*
* The interbyte type in data from an ecu is between P1Min and P1Max
* The intermessage time for part of one response is P2Min and P2Max
*
* If we are running with an intelligent L1 interface, then we will be
* getting one message per frame, and we will wait a bit longer
* for extra messages
*/
diag_l2_proto_vag_recv(diag_l2_conn_t *d_l2_conn, int timeout,
void (*callback)(void *handle, diag_msg_t *msg),
void *handle)
{
u_int8_t data[256];
int rv;
int datalen;
/* Call internal routine */
rv = diag_l2_proto_vag_int_recv(d_l2_conn, timeout, data, &datalen);
if (rv < 0) /* Failure */
return(rv);
if (diag_l2_debug & DIAG_DEBUG_READ)
{
printf("%s: calling rcv callback %x handle %x\n", DIAG_MODULE,
callback, handle);
}
/*
* Call user callback routine
*/
if (callback)
callback(handle, d_l2_conn->diag_msg);
/* No longer needed */
diag_freemsg(d_l2_conn->diag_msg);
d_l2_conn->diag_msg = NULL;
if (diag_l2_debug & DIAG_DEBUG_READ)
{
printf("%s: rcv callback completed\n", DIAG_MODULE);
}
return(0);
}
diag_msg_t *
diag_l2_proto_vag_request(diag_l2_conn_t *d_l2_conn, diag_msg_t *msg,
int *errval)
{
int rv;
diag_msg_t *rmsg = NULL;
rv = diag_l2_send(d_l2_conn, msg);
if (rv < 0)
{
*errval = rv;
return(NULL);
}
/* And wait for response */
rv = diag_l2_proto_9141_int_recv(d_l2_conn, 1000);
if ((rv >= 0) && d_l2_conn->diag_msg)
{
/* OK */
rmsg = d_l2_conn->diag_msg;
d_l2_conn->diag_msg = NULL;
}
else
{
/* Error */
*errval = DIAG_ERR_TIMEOUT;
rmsg = NULL;
}
return(rmsg);
}
/*
* AccessTimingParameters
*/
int
diag_l2_proto_vag_atp(diag_l2_conn_t* d_l2_conn, int p2min, int p2max, int p3min, int p3max, int p4min)
{
return (0);
}
/*
* Timer, called regularly, we don't do anything with this
*/
void
diag_l2_proto_vag_timer()
{
}
/*
* Timeout, - if we don't send something to the ECU it will timeout
* soon, so send it a keepalive message now.
*/
void
diag_l2_proto_vag_timeout(diag_l2_conn_t *d_l2_conn)
{
struct diag_l2_vag *dp;
diag_msg_t msg;
u_int8_t data[256];
/* int rv;*/
dp = d_l2_conn->diag_l2_proto_data;
if (diag_l2_debug & DIAG_DEBUG_TIMER)
{
fprintf(stderr, "%s: timeout impending for %x\n",
DIAG_MODULE, d_l2_conn);
}
msg.data = data;
/*
* There is no point in checking for errors, or checking
* the received response as we cant pass an error back
* from here
*/
/* Send it, important to use l2_send as it updates the timers */
(void)diag_l2_send(d_l2_conn, &msg);
/* Get the response in p2max, we use p3min to be more flexible */
(void)diag_l2_recv(d_l2_conn, d_l2_conn->diag_l2_p3min, NULL, NULL);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -