BOROSOFTWAREAll work →
scantool/diag_l0_dumbtest.c 763 lines
1/*
2 * freediag - Vehicle Diagnostic Utility
3
4 *************************************************************************
5 * dumbtest (c) 2014-2015 fenugrec
6 * Diag, Layer 0, interface tester. This should *NOT* be used while
7 * a vehicle is connected; only for debugging the electrical interface itself.
8
9 * This is a dummy l0 driver : most functions do nothing except
10 * _open which opens the interface, runs the specified test, and closes everything
11 * before returning.
12 */
13
14
15#include <assert.h>
16#include <stdbool.h>
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h> //for memcmp
21
22#include "diag.h"
23#include "diag_cfg.h"
24#include "diag_err.h"
25#include "diag_os.h"
26#include "diag_tty.h"
27#include "diag_l0.h"
28#include "diag_l1.h"
29
30struct dt_device {
31 int protocol; //set in dt_open with specified iProtocol
32 struct diag_serial_settings serial;
33
34 /* "dumbopts" flags. Copied from l0_dumb driver */
35 /* Using a struct cfgi for each of these really seems like overkill...
36 * current approach is to have a cfgi for an "int dumbopts", that is parsed into
37 * these flags in dumb_open(). Hence, the shortname + descriptions defined here are
38 * unused for the moment.
39 */
40 bool use_L;
41 #define DD_USEL "Use RTS to drive the L line for init. Interface must support this."
42 #define DS_USEL "USEL"
43 bool clr_dtr;
44 #define DD_CLRDTR "Always keep DTR cleared (neg. voltage). Unusual."
45 #define DS_CLRDTR "CLRDTR"
46 bool set_rts;
47 #define DD_SETRTS "Always keep RTS set (pos. voltage). Unusual; do not use with USE_L."
48 #define DS_SETRTS "SETRTS"
49 bool man_break;
50 #define DD_MANBRK "Send manual breaks (essential for USB-serial ICs that don't support 5bps.)"
51 #define DS_MANBRK "MANBRK"
52 bool lline_inv;
53 #define DD_INVL "Invert polarity of the L line. Unusual."
54 #define DS_INVL "INVL"
55 bool fast_break;
56 #define DD_FASTBK "Try alternate iso14230 fastinit code."
57 #define DS_FASTBK "FASTB"
58 bool blockduplex;
59 #define DD_BKDUPX "Use message-based half duplex removal if P4==0."
60 #define DS_BKDUPX "BLKDUP"
61
62 struct cfgi port;
63 struct cfgi dumbopts;
64 #define DUMBOPTS_SN "dumbopts"
65 #define DUMBOPTS_DESC "Dumb interface option flags; addition of the desired flags:\n" \
66 " 0x01 : USE_LLINE : use if the L line (driven by RTS) is required for init. Interface must support this\n" \
67 "\t(VAGTOOL for example).\n" \
68 " 0x02 : CLEAR_DTR : use if your interface needs DTR to be always clear (neg. voltage).\n" \
69 "\tThis is unusual. By default DTR will always be SET (pos. voltage)\n" \
70 " 0x04 : SET_RTS : use if your interface needs RTS to be always set (pos. voltage).\n" \
71 "\tThis is unusual. By default RTS will always be CLEAR (neg. voltage)\n" \
72 "\tThis option should not be used with USE_LLINE.\n" \
73 " 0x08 : MAN_BREAK : essential for USB-serial converters that don't support 5bps\n" \
74 "\tsuch as FTDI232*, P230* and other ICs (enabled by default).\n" \
75 " 0x10: LLINE_INV : Invert polarity of the L line. see\n" \
76 "\tdoc/dumb_interfaces.txt !! This is unusual.\n" \
77 " 0x20: FAST_BREAK : use alternate iso14230 fastinit code.\n" \
78 " 0x40: BLOCKDUPLEX : use message-based half duplex removal (if P4==0)\n\n" \
79 "ex.: \"dumbopts 9\" for MAN_BREAK and USE_LLINE.\n"
80
81
82 ttyp *tty_int; /** handle for tty stuff */
83};
84
85
86// dumbopts flags set according to particular interface type (VAGtool vs SE etc.)
87#define USE_LLINE 0x01 //interface maps L line to RTS : setting RTS normally pulls L down to 0 .
88#define CLEAR_DTR 0x02 //have DTR cleared constantly (unusual, disabled by default)
89#define SET_RTS 0x04 //have RTS set constantly (also unusual, disabled by default).
90#define MAN_BREAK 0x08 //force bitbanged breaks for inits; enabled by default
91#define LLINE_INV 0x10 //invert polarity of the L line if set. see doc/dumb_interfaces.txt
92#define FAST_BREAK 0x20 //do we use diag_tty_fastbreak for iso14230-style fast init.
93#define BLOCKDUPLEX 0x40 //This allows half duplex removal on a whole message if P4==0 (see diag_l1_send())
94#define DUMBDEFAULTS (MAN_BREAK | BLOCKDUPLEX) //default set of flags
95
96
97extern const struct diag_l0 diag_l0_dumbtest;
98
99static int dt_send(struct diag_l0_device *dl0d,
100 const void *data, size_t len);
101
102/*
103 * Init must be callable even if no physical interface is
104 * present, it's just here for the code here to initialise its
105 * variables etc
106 */
107static int dt_init(void) {
108 /* Global init flag */
109 static int dt_initdone=0;
110
111 if (dt_initdone) {
112 return 0;
113 }
114
115 dt_initdone = 1;
116
117 return 0;
118}
119
120
121
122
123//dtest_1 : slow pulse TXD with diag_tty_break; 400ms / 200ms cycles.
124
125static void dtest_1(struct diag_l0_device *dl0d) {
126 int i;
127 struct dt_device *dev = dl0d->l0_int;
128
129 fprintf(stderr, "Starting test 1: pulsing TXD=1, 1s, TXD=0, 500ms:");
130 for (i=0; i<=4; i++) {
131 diag_os_millisleep(1000);
132 if (diag_tty_break(dev->tty_int, 500)) {
133 break;
134 }
135 fprintf(stderr, ".");
136 }
137 fprintf(stderr, "\n");
138 return;
139}
140
141//dtest_2 : fast pulse TXD by sending 0x55 @ 10.4kps with 5ms interbyte
142static void dtest_2(struct diag_l0_device *dl0d) {
143 int i, pc=0;
144 const int iters=300;
145 uint8_t patternbyte=0x55;
146 struct dt_device *dev = dl0d->l0_int;
147
148 fprintf(stderr, "Starting test 2: sending 0x55 with P4=5ms:");
149 for (i=0; i<=iters; i++) {
150 if (diag_tty_write(dev->tty_int, &patternbyte, 1) != 1) {
151 fprintf(stderr, "write error\n");
152 break;
153 }
154 if ((10*i/iters) != pc) {
155 pc +=1;
156 fprintf(stderr, ".");
157 }
158 diag_os_millisleep(5);
159 }
160 fprintf(stderr, "\n");
161 return;
162}
163
164//dtest_3: slow pulse RTS
165static void dtest_3(struct diag_l0_device *dl0d) {
166 int i;
167 struct dt_device *dev = dl0d->l0_int;
168 fprintf(stderr, "Starting test 3: pulsing RTS=1, 1s, RTS=0, 500ms:");
169
170 for (i=0; i<=4; i++) {
171 if (diag_tty_control(dev->tty_int, !(dev->clr_dtr), 1)) {
172 break;
173 }
174 diag_os_millisleep(1000);
175 if (diag_tty_control(dev->tty_int, !(dev->clr_dtr), 0)) {
176 break;
177 }
178 diag_os_millisleep(500);
179 fprintf(stderr, ".");
180 }
181 diag_tty_control(dev->tty_int, !(dev->clr_dtr), dev->set_rts);
182 fprintf(stderr, "\n");
183 return;
184}
185
186//dtest_4: slow pulse DTR
187static void dtest_4(struct diag_l0_device *dl0d) {
188 int i;
189 struct dt_device *dev = dl0d->l0_int;
190 fprintf(stderr, "Starting test 4: pulsing DTR=1, 1s, DTR=0, 500ms:");
191
192 for (i=0; i<=4; i++) {
193 if (diag_tty_control(dev->tty_int, 1, dev->set_rts)) {
194 break;
195 }
196 diag_os_millisleep(1000);
197 if (diag_tty_control(dev->tty_int, 0, dev->set_rts)) {
198 break;
199 }
200 diag_os_millisleep(500);
201 fprintf(stderr, ".");
202 }
203 diag_tty_control(dev->tty_int, !(dev->clr_dtr), dev->set_rts);
204 fprintf(stderr, "\n");
205 return;
206}
207
208
209//dtest_5 : fast pulse TXD with diag_tty_break;
210
211static void dtest_5(struct diag_l0_device *dl0d) {
212 int i, pc=0;
213 struct dt_device *dev = dl0d->l0_int;
214 const int iters=40;
215 fprintf(stderr, "Starting test 5: pulsing TXD=1, 50, TXD=0, 25ms:");
216 for (i=0; i<=iters; i++) {
217 diag_os_millisleep(50);
218 if (diag_tty_break(dev->tty_int, 25)) {
219 fprintf(stderr, "break error\n");
220 break;
221 }
222 if ((10*i/iters) != pc) {
223 pc +=1;
224 fprintf(stderr, ".");
225 }
226 }
227 fprintf(stderr, "\n");
228 return;
229}
230
231//dtest_6 : fast pulse TXD with diag_tty_fastbreak;
232
233static void dtest_6(struct diag_l0_device *dl0d) {
234 int i, pc=0;
235 struct dt_device *dev = dl0d->l0_int;
236 const int iters=50;
237 fprintf(stderr, "Starting test 6: pulsing TXD=1, 50ms, TXD=0, 25ms:");
238 for (i=0; i<=iters; i++) {
239 if (diag_tty_fastbreak(dev->tty_int, 50)) {
240 fprintf(stderr, "fastbreak error\n");
241 break;
242 }
243 if ((10*i/iters) != pc) {
244 pc +=1;
245 fprintf(stderr, ".");
246 }
247 }
248 fprintf(stderr, "\n");
249 return;
250}
251
252//dtest_7 : half duplex echo removal 1 : send bytes and remove echo
253//one by one; P4=0. Print per-byte time to do this; use _dumb_send() instead
254// of diag_tty directly, like l1_send().
255static void dtest_7(struct diag_l0_device *dl0d) {
256 uint8_t i, pc=0, echo;
257 int rv, badechos=0;
258 unsigned long long ti, tf=0; //measure inner time
259 struct dt_device *dev = dl0d->l0_int;
260
261#define DT7_ITERS 100
262 fprintf(stderr, "Starting test 7: half duplex single echo removal:");
263
264 for (i=0; i<DT7_ITERS; i++) {
265 echo=i-1; //init to bad value
266 ti=diag_os_gethrt(); //get starting time.
267 if (dt_send(dl0d, &i, 1)) {
268 break;
269 }
270
271 rv = diag_tty_read(dev->tty_int, &echo, 1, 1000);
272 if (rv != 1) {
273 fprintf(stderr, "\ndt7: tty_read rets %d.\n", rv);
274 break;
275 }
276 tf = tf + diag_os_gethrt() - ti;
277 //check echo
278 if (echo != i) {
279 badechos++;
280 }
281
282 if ((10*i/DT7_ITERS) != pc) {
283 pc +=1;
284 fprintf(stderr, ".");
285 }
286 } //for
287 fprintf(stderr, "\n");
288 tf = tf / DT7_ITERS; //average time per byte
289 printf("Average speed : %d us/byte. %d good; %d bad echos received.\n", (int) diag_os_hrtus(tf), i, badechos);
290
291
292 return;
293} //dtest_7
294
295//dtest_8 : block half duplex removal; send 10 bytes per message
296static void dtest_8(struct diag_l0_device *dl0d) {
297#define DT8_MSIZE 10
298 uint8_t tx[DT8_MSIZE], echo[DT8_MSIZE];
299 int i, rv = -1, badechos=0;
300 unsigned long long ti, tf=0;
301 struct dt_device *dev = dl0d->l0_int;
302
303#define DT8_ITERS 10
304 fprintf(stderr, "Starting test 8: half duplex block echo removal:");
305 //fill i[] first
306 for (i = 0; i < DT8_MSIZE; i++) {
307 tx[i] = (uint8_t)i;
308 }
309
310 for (i=0; i<=DT8_ITERS; i++) {
311 ti=diag_os_gethrt(); //get starting time.
312 if (dt_send(dl0d, tx, DT8_MSIZE)) {
313 break;
314 }
315
316 rv = diag_tty_read(dev->tty_int, echo, DT8_MSIZE, 100 + 5*DT8_MSIZE);
317 if (rv != DT8_MSIZE) {
318 fprintf(stderr, "\ndt8: tty_read rets %d.\n", rv);
319 break;
320 }
321 tf = tf + diag_os_gethrt() - ti;
322 //check echo
323 if ( memcmp(tx, echo, DT8_MSIZE) == 0) {
324 //ok
325 rv=0;
326 } else {
327 badechos++;
328 }
329 fprintf(stderr, ".");
330 } //for
331
332 tf = tf / (DT8_ITERS * DT8_MSIZE); //average time per byte
333 fprintf(stderr, "\n");
334 if (rv != 0) {
335 printf("Error, test did not complete.\n");
336 } else {
337 printf("Average speed : %d us/byte. %d bad echos received.\n", (int) diag_os_hrtus(tf), badechos);
338 }
339
340 return;
341} //dtest_8
342
343//dtest_9 : test accuracy of read timeouts.
344static void dtest_9(struct diag_l0_device *dl0d) {
345 #define DT9_ITERS 4
346 unsigned int i;
347 int iters;
348 uint8_t garbage[MAXRBUF];
349 unsigned long long t0, tf;
350 struct dt_device *dev = dl0d->l0_int;
351
352 fprintf(stderr, "Starting test 9: checking accuracy of read timeouts:\n");
353 diag_tty_iflush(dev->tty_int); //purge before starting
354
355 for (i=10; i<=200; i += 20) {
356 t0=diag_os_gethrt();
357 for (iters=0; iters < DT9_ITERS; iters++) {
358 diag_tty_read(dev->tty_int, garbage, MAXRBUF, i);
359 }
360 tf = (diag_os_gethrt() - t0) / DT9_ITERS; //average measured timeout
361 printf("Timeout=%u: avg=%dms\n", i, (int) (diag_os_hrtus(tf)/1000));
362 }
363
364 return;
365} //dtest_9
366
367//dtest_10 == dtest_2 with a different speed
368
369//dtest_11 : test incomplete read timeout (needs half-duplex connection)
370static void dtest_11(struct diag_l0_device *dl0d) {
371 #define DT11_ITERS 4
372 unsigned int i;
373 int iters,rv;
374 uint8_t garbage[MAXRBUF];
375 unsigned long long t0, tf;
376 struct dt_device *dev = dl0d->l0_int;
377
378 fprintf(stderr, "Starting test 11: half-duplex incomplete read timeout accuracy:\n");
379 diag_tty_iflush(dev->tty_int); //purge before starting
380
381 for (i=10; i<=180; i += 20) {
382 tf=0;
383 for (iters=0; iters < DT11_ITERS; iters++) {
384 uint8_t tc = i;
385 if ((rv = dt_send(dl0d, &tc, 1))) {
386 goto failed;
387 }
388 t0=diag_os_gethrt();
389 if ((rv=diag_tty_read(dev->tty_int, garbage, MAXRBUF, i)) != 1) {
390 // failed: purge + try next timeout value
391 fprintf(stderr, "failed @ timeout=%u : %s\n", i, diag_errlookup(rv));
392 diag_tty_iflush(dev->tty_int);
393 break;
394 }
395 tf = tf + diag_os_gethrt() - t0;
396 }
397 tf = tf / DT11_ITERS;
398 printf("Timeout=%u: avg=%dms\n", i, (int) (diag_os_hrtus(tf)/1000));
399 }
400 return;
401failed:
402 fprintf(stderr, "Problem during test! %s\n",diag_errlookup(rv));
403 return;
404} //dtest_11
405
406//dtest_12 : diag_tty_write() duration
407static void dtest_12(struct diag_l0_device *dl0d) {
408 #define DT12_ITERS 4
409 unsigned int i;
410 int iters;
411 uint8_t garbage[MAXRBUF];
412 unsigned long long t0, tf; //measure inner time
413 unsigned long long ts1, ts2; //measure overall loop
414 struct dt_device *dev = dl0d->l0_int;
415
416 fprintf(stderr, "Starting test 12: diag_tty_write() duration:\n");
417 diag_tty_iflush(dev->tty_int); //purge before starting
418
419 for (i=1; i<=50; i += 5) {
420 tf=0;
421 printf("len=%u:", i);
422 ts1=diag_os_gethrt();
423 for (iters=0; iters < DT12_ITERS; iters++) {
424 unsigned long long tt1;
425 t0 = diag_os_gethrt();
426 if (dt_send(dl0d, garbage, i)) {
427 goto failed;
428 }
429 tt1 = diag_os_gethrt();
430 tf = tf + (tt1 - t0);
431 printf("\t%luus", (long unsigned int) (diag_os_hrtus(tt1-t0)));
432 (void) diag_tty_read(dev->tty_int, garbage, MAXRBUF, 5);
433 }
434 ts2= (diag_os_gethrt() - ts1) / DT12_ITERS;
435 tf = tf / DT12_ITERS;
436 printf(" => avg=%dms / %dms\n", (int) (diag_os_hrtus(tf)/1000), (int) (diag_os_hrtus(ts2)/1000));
437 if (i == 1) {
438 i = 0;
439 }
440 }
441 return;
442failed:
443 fprintf(stderr, "Problem during test!\n");
444 return;
445}
446
447//dtest_13 : simulate 14230 fastinit : 25ms low, tWUP=50ms, then send 0xAA @ 10.4k; with diag_tty_fastbreak
448
449static void dtest_13(struct diag_l0_device *dl0d) {
450 int i, pc=0;
451 const int iters=50;
452 const uint8_t db=0xAA;
453 struct dt_device *dev = dl0d->l0_int;
454
455 fprintf(stderr, "Starting test 6: simulate fastinit:");
456 for (i=0; i<=iters; i++) {
457 if (diag_tty_fastbreak(dev->tty_int, 50)) {
458 fprintf(stderr, "fastbreak error\n");
459 break;
460 }
461 if (diag_tty_write(dev->tty_int, &db, 1) != 1) {
462 fprintf(stderr, "tty_write error\n");
463 break;
464 }
465 diag_tty_iflush(dev->tty_int); //purge echo(s)
466 if ((10*i/iters) != pc) {
467 pc +=1;
468 fprintf(stderr, ".");
469 }
470 }
471 fprintf(stderr, "\n");
472 return;
473}
474
475static int dt_new(struct diag_l0_device *dl0d) {
476 struct dt_device *dev;
477 int rv;
478
479 assert(dl0d);
480
481 rv = diag_calloc(&dev, 1);
482 if (rv != 0) {
483 return diag_ifwderr(rv);
484 }
485
486 dl0d->l0_int = dev;
487
488 rv = diag_cfgn_tty(&dev->port);
489 if (rv != 0) {
490 free(dev);
491 return diag_ifwderr(rv);
492 }
493
494 rv = diag_cfgn_int(&dev->dumbopts, DUMBDEFAULTS, DUMBDEFAULTS);
495 if (rv != 0) {
496 diag_cfg_clear(&dev->port);
497 free(dev);
498 return diag_ifwderr(rv);
499 }
500
501 /* finish filling the dumbopts cfgi */
502 dev->dumbopts.shortname = DUMBOPTS_SN;
503 dev->dumbopts.descr = DUMBOPTS_DESC;
504 dev->port.next = &dev->dumbopts;
505 dev->dumbopts.next = NULL;
506
507 printf("*** Warning ! The DUMBT driver is only for electrical ***\n"
508 "*** testing ! Do NOT use while connected to a vehicle! ***\n"
509 "*** refer to doc/scantool-manual.html ***\n");
510
511 return 0;
512}
513
514static void dt_del(struct diag_l0_device *dl0d) {
515 struct dt_device *dev;
516
517 assert(dl0d);
518
519 dev = dl0d->l0_int;
520 if (!dev) {
521 return;
522 }
523
524 diag_cfg_clear(&dev->port);
525 diag_cfg_clear(&dev->dumbopts);
526 free(dev);
527 return;
528}
529
530static struct cfgi *dt_getcfg(struct diag_l0_device *dl0d) {
531 struct dt_device *dev;
532 if (dl0d == NULL) {
533 return diag_pseterr(DIAG_ERR_BADCFG);
534 }
535
536 dev = dl0d->l0_int;
537 return &dev->port;
538}
539
540
541/*
542 * Open the diagnostic device, returns a file descriptor
543 * records original state of term interface so we can restore later
544 */
545static int dt_open(struct diag_l0_device *dl0d, int testnum) {
546 struct dt_device *dev;
547 struct diag_serial_settings pset;
548 int dumbopts;
549
550 assert(dl0d);
551 dev = dl0d->l0_int;
552
553 DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
554 FLFMT "open port %s test # %d\n", FL, dev->port.val.str, testnum);
555
556 dt_init(); //make sure it is initted
557
558 /* try to open TTY */
559 dev->tty_int = diag_tty_open(dev->port.val.str);
560 if (dev->tty_int == NULL) {
561 return diag_iseterr(DIAG_ERR_GENERAL);
562 }
563
564 dev->protocol = DIAG_L1_RAW; //cheat !
565
566 switch (testnum) {
567 case 10:
568 pset.speed = 15000;
569 break;
570 case 14:
571 pset.speed = 360;
572 break;
573 default:
574 pset.speed=10400;
575 }
576
577 pset.databits = diag_databits_8;
578 pset.stopbits = diag_stopbits_1;
579 pset.parflag = diag_par_n;
580
581 if (diag_tty_setup(dev->tty_int, &pset)) {
582 diag_tty_close(dev->tty_int);
583 return diag_iseterr(DIAG_ERR_GENERAL);
584 }
585
586 /* parse dumbopts to set flags */
587 dumbopts = dev->dumbopts.val.i;
588
589 dev->use_L = dumbopts & USE_LLINE;
590 dev->clr_dtr = dumbopts & CLEAR_DTR;
591 dev->set_rts = dumbopts & SET_RTS;
592 dev->man_break = dumbopts & MAN_BREAK;
593 dev->lline_inv = dumbopts & LLINE_INV;
594 dev->fast_break = dumbopts & FAST_BREAK;
595 dev->blockduplex = dumbopts & BLOCKDUPLEX;
596
597 //set initial DTR and RTS lines before starting tests;
598 if (diag_tty_control(dev->tty_int, !(dev->clr_dtr), dev->set_rts) < 0) {
599 diag_tty_close(dev->tty_int);
600 return diag_iseterr(DIAG_ERR_GENERAL);
601 }
602
603 (void)diag_tty_iflush(dev->tty_int); /* Flush unread input */
604
605 //printf("Press <enter> to stop the test.\n");
606 //Currently these run for a fixed time...
607 switch (testnum) {
608 case 1:
609 dtest_1(dl0d);
610 break;
611 case 2:
612 dtest_2(dl0d);
613 break;
614 case 3:
615 dtest_3(dl0d);
616 break;
617 case 4:
618 dtest_4(dl0d);
619 break;
620 case 5:
621 dtest_5(dl0d);
622 break;
623 case 6:
624 dtest_6(dl0d);
625 break;
626 case 7:
627 dtest_7(dl0d);
628 break;
629 case 8:
630 dtest_8(dl0d);
631 break;
632 case 9:
633 dtest_9(dl0d);
634 break;
635 case 10:
636 dtest_2(dl0d); //same test, different speed
637 break;
638 case 11:
639 dtest_11(dl0d);
640 break;
641 case 12:
642 dtest_12(dl0d);
643 break;
644 case 13:
645 dtest_13(dl0d);
646 break;
647 case 14:
648 dtest_7(dl0d); //same test, different speed
649 break;
650 default:
651 break;
652 }
653
654 diag_tty_close(dev->tty_int);
655
656 fprintf(stderr, "L0 test finished. Ignore the following error.\n");
657 return DIAG_ERR_GENERAL;
658}
659
660
661static void dt_close(UNUSED(struct diag_l0_device *dl0d)) {
662 return;
663}
664
665
666/*
667 * Send a load of data
668 * this is "blocking", i.e. returns only when it's finished or it failed.
669 *
670 * Returns 0 on success, -1 on failure
671 */
672
673static int dt_send(struct diag_l0_device *dl0d,
674 const void *data, size_t len) {
675 struct dt_device *dev = dl0d->l0_int;
676
677 /*
678 * This will be called byte at a time unless P4 timing parameter is zero
679 * as the L1 code that called this will be adding the P4 gap between
680 * bytes
681 */
682 if (len == 0) {
683 return diag_iseterr(DIAG_ERR_BADLEN);
684 }
685
686 DIAG_DBGMDATA(diag_l0_debug, DIAG_DEBUG_WRITE, DIAG_DBGLEVEL_V, data, len,
687 FLFMT "dt_send dl0d=%p , len=%ld. ", FL, (void *)dl0d, (long)len);
688
689 if (diag_tty_write(dev->tty_int, data, len) != (int) len) {
690 fprintf(stderr, FLFMT "dt_send: write error\n", FL);
691 return diag_iseterr(DIAG_ERR_GENERAL);
692 }
693
694 return 0;
695}
696
697/* dummy dt_recv
698 */
699
700static int dt_recv(struct diag_l0_device *dl0d,
701 UNUSED(void *data), size_t len, unsigned int timeout) {
702 fprintf(stderr,
703 FLFMT "link %p recv upto %ld bytes timeout %u; doing nothing.\n",
704 FL, (void *)dl0d, (long)len, timeout);
705
706 return diag_iseterr(DIAG_ERR_TIMEOUT);
707}
708
709/*
710 * Set speed/parity etc
711 */
712static int dt_setspeed(struct diag_l0_device *dl0d,
713 const struct diag_serial_settings *pset) {
714 struct dt_device *dev;
715
716 dev = (struct dt_device *)(dl0d->l0_int);
717
718 dev->serial = *pset;
719
720 return diag_tty_setup(dev->tty_int, &dev->serial);
721}
722
723
724static uint32_t dt_getflags(UNUSED(struct diag_l0_device *dl0d)) {
725 return DIAG_L1_HALFDUPLEX;
726}
727
728static int dt_ioctl(struct diag_l0_device *dl0d, unsigned cmd, void *data) {
729 int rv = 0;
730
731 switch (cmd) {
732 case DIAG_IOCTL_IFLUSH:
733 //do nothing
734 rv = 0;
735 break;
736 case DIAG_IOCTL_SETSPEED:
737 rv = dt_setspeed(dl0d, (const struct diag_serial_settings *) data);
738 break;
739 default:
740 rv = DIAG_ERR_IOCTL_NOTSUPP;
741 break;
742 }
743
744 return rv;
745}
746
747
748const struct diag_l0 diag_l0_dumbtest = {
749 "Dumb interface test suite",
750 "DUMBT",
751 -1, //support "all" L1 protos...
752 dt_init,
753 dt_new,
754 dt_getcfg,
755 dt_del,
756 dt_open,
757 dt_close,
758 dt_getflags,
759 dt_recv,
760 dt_send,
761 dt_ioctl
762};
763