BOROSOFTWAREAll work →
scantool/diag_l1.c 281 lines
3 findings in this fileD2L75A1L141D6
1/*
2 * freediag - Vehicle Diagnostic Utility
3 *
4 *
5 * Copyright (C) 2001 Richard Almeida & Ibex Ltd ([email protected])
6 * 2009-2015 fenugrec
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *************************************************************************
23 *
24 * L1 diagnostic interface, generic routines
25 *
26 * These look much like the L0 interface, but handle things such
27 * as de-duplexing etc
28 *
29 * This is written so that sometime this can dynamically support more
30 * than one L0 interface - I don't have more than one (or more than one type)
31 * so it's not completely that way :-(
32 *
33 * HOWEVER, if the L0 interface has multiple interfaces in it, which have
34 * different flags, then this code needs some enhancements. One of the
35 * interfaces we use does have this (multiplex engineering interface)
36 */
37
38
39#include <stdio.h>
40#include <string.h>
41
42#include "diag.h"
43#include "diag_err.h"
44#include "diag_os.h"
45#include "diag_l0.h"
46#include "diag_l1.h"
47
48
49int diag_l1_debug; //debug flags for l1
50
51
52
53/* Global init flag */
54static int diag_l1_initdone=0;
55
56//diag_l1_init : parse through l0dev_list and call each ->init()
57int diag_l1_init(void) {
58 if (diag_l1_initdone) {
59 return 0;
60 }
61
62 DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_INIT, DIAG_DBGLEVEL_V,
63 FLFMT "entered diag_l1_init\n", FL);
64
65 /* Now call the init routines for the L0 devices */
66
67 //NOTE : ->init functions should NOT play any mem tricks (*alloc etc) or open handles.
68 //That way we won't need to add a diag_l0_end function.
69
70 const struct diag_l0 *dl0;
71 int i=0;
72 while (l0dev_list[i]) {
73 dl0=l0dev_list[i];
74 if (dl0->init) {
75 (void) dl0->init(); //TODO : forward errors up ?
76 }
77 i++;
78 }
79
80 diag_l1_initdone = 1;
81 return 0;
82}
83
84//diag_l1_end : opposite of diag_l1_init . Non-critical for now
85int diag_l1_end(void) {
86 diag_l1_initdone=0;
87 return 0;
88}
89
90/*
91 * Open the L0 device with L1 proto.
92 *
93 */
94int diag_l1_open(struct diag_l0_device *dl0d, int l1protocol) {
95 DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
96 FLFMT "diag_l1_open(0x%p, l1 proto=%d\n",
97 FL, (void *)dl0d, l1protocol);
98
99 /* Check h/w supports this l1 protocol */
100 if ((dl0d->dl0->l1proto_mask & l1protocol) == 0) {
101 return diag_iseterr(DIAG_ERR_PROTO_NOTSUPP);
102 }
103
104 /* Call the open routine with the requested L1 protocol */
105 return diag_l0_open(dl0d, l1protocol);
106}
107
108//diag_l1_close : call the ->close member of the
109//specified diag_l0_device.
110void diag_l1_close(struct diag_l0_device *dl0d) {
111 DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_CLOSE, DIAG_DBGLEVEL_V,
112 FLFMT "entering diag_l1_close: dl0d=%p\n", FL, (void *)dl0d);
113
114 if (dl0d) {
115 diag_l0_close(dl0d);
116 }
117 return;
118}
119
120int diag_l1_ioctl(struct diag_l0_device *dl0d, unsigned cmd, void *data) {
121 /* At the moment, no ioctls are handled at the L1 level, so forward them to L0. */
122
123 return diag_l0_ioctl(dl0d, cmd, data);
124}
125
126
127/*
128 * Send a load of data
129 *
130 * P4 is the inter byte gap
131 *
132 * This does very un-clever half duplex removal, there better not be
133 * any outstanding data on the bus (or in the l0 buffers) or this
134 * will think it has a half-duplex failure, i.e a bus error
135 *
136 * Returns 0 on success
137 */
138int diag_l1_send(struct diag_l0_device *dl0d, const void *data, size_t len, unsigned int p4) {
139 int rv = DIAG_ERR_GENERAL;
140 uint32_t l0flags;
141 uint8_t duplexbuf[MAXRBUF];
142
143 if (len > MAXRBUF) {
144 return diag_iseterr(DIAG_ERR_BADLEN);
145 }
146
147 l0flags = diag_l1_getflags(dl0d);
148
149 DIAG_DBGMDATA(diag_l1_debug, DIAG_DEBUG_WRITE, DIAG_DBGLEVEL_V, data, len,
150 FLFMT "_send: len=%d P4=%u l0flags=0x%X; ",
151 FL, (int) len, p4, l0flags);
152
153 /*
154 * If p4 is zero and not in half duplex mode, or if
155 * L1 is a "DOESL2" interface, or if L0 takes care of P4 waits,
156 * or if P4==0 and we do per-message duplex removal:
157 * send the whole message to L0 as one write
158 */
159
160 if ( ((p4 == 0) && ((l0flags & DIAG_L1_HALFDUPLEX) == 0)) ||
161 (l0flags & DIAG_L1_DOESL2FRAME) || (l0flags & DIAG_L1_DOESP4WAIT) ||
162 ((p4==0) && (l0flags & DIAG_L1_BLOCKDUPLEX)) ) {
163 /*
164 * Send the lot
165 */
166 rv = diag_l0_send(dl0d, data, len);
167
168 //optionally remove echos
169 if ((l0flags & DIAG_L1_BLOCKDUPLEX) && (rv==0)) {
170 //try to read the same number of sent bytes; timeout=300ms + 1ms/byte
171 //This is plenty OK for typical 10.4kbps but should be changed
172 //if ever slow speeds are used.
173 if (diag_l0_recv(dl0d, duplexbuf, len, 300+len) != (int) len) {
174 rv=DIAG_ERR_GENERAL;
175 }
176
177 //compare to sent bytes
178 if ( memcmp(duplexbuf, data, len) !=0) {
179 fprintf(stderr,FLFMT "Bus Error: bad half duplex echo!\n", FL);
180 rv=DIAG_ERR_BUSERROR;
181 }
182 }
183 } else {
184 /* else: send each byte */
185 const uint8_t *dp = (const uint8_t *)data;
186
187 while (len--) {
188 rv = diag_l0_send(dl0d, dp, 1);
189 if (rv != 0) {
190 break;
191 }
192
193 /*
194 * If half duplex, read back the echo, if
195 * the echo is wrong then this is an error
196 * i.e something wrote on the diag bus whilst
197 * we were writing
198 */
199 if (l0flags & DIAG_L1_HALFDUPLEX) {
200 uint8_t c;
201
202 c = *dp - 1; /* set it with wrong val. */
203 if (diag_l0_recv(dl0d, &c, 1, 200) != 1) {
204 rv=DIAG_ERR_GENERAL;
205 break;
206 }
207
208 if (c != *dp) {
209 if (c == *dp - 1) {
210 fprintf(stderr,"Half duplex interface not echoing!\n");
211 } else {
212 fprintf(stderr,
213 "Bus Error: got 0x%X "
214 "expected 0x%X\n",
215 c, *dp);
216 }
217 rv = DIAG_ERR_BUSERROR;
218 break;
219 }
220 }
221 dp++;
222
223 if (p4) { /* Inter byte gap */
224 diag_os_millisleep(p4);
225 }
226 }
227 }
228
229 return rv? diag_iseterr(rv):0;
230}
231
232/*
233 * Get data (blocking, unless timeout is 0)
234 * returns # of bytes read, or <0 if error.
235 * XXX currently nothing handles the case of L0 returning 0 bytes read. Logically that could
236 * only happen when requesting n bytes with a timeout of 0; otherwise DIAG_ERR_TIMEOUT will
237 * generated.
238 */
239int diag_l1_recv(struct diag_l0_device *dl0d, void *data, size_t len, unsigned int timeout) {
240 int rv;
241 if (!len) {
242 return diag_iseterr(DIAG_ERR_BADLEN);
243 }
244
245 DIAG_DBGM(diag_l1_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V,
246 FLFMT "_recv request len=%d, timeout=%u;",
247 FL, (int)len, timeout);
248
249 if (timeout == 0) {
250 fprintf(stderr,
251 FLFMT
252 "Interesting : L1 read with timeout=0. Report this !\n",
253 FL);
254 }
255
256 rv=diag_l0_recv(dl0d, data, len, timeout);
257 if (!rv) {
258 fprintf(stderr, FLFMT "L0 returns with 0 bytes; returning TIMEOUT instead. Report this !\n", FL);
259 return DIAG_ERR_TIMEOUT;
260 }
261
262 if (rv>0) {
263 DIAG_DBGMDATA(diag_l1_debug, DIAG_DEBUG_READ, DIAG_DBGLEVEL_V,
264 data, (size_t) rv, "got %d bytes; ",rv);
265 }
266
267 return rv;
268}
269
270
271//diag_l1_getflags: returns l0 flags
272uint32_t diag_l1_getflags(struct diag_l0_device *dl0d) {
273 return diag_l0_getflags(dl0d);
274}
275
276//diag_l1_gettype: returns l1proto_mask :supported L1 protos
277//of the l0 driver
278int diag_l1_gettype(struct diag_l0_device *dl0d) {
279 return dl0d->dl0->l1proto_mask;
280}
281