コード例 #1
0
ファイル: diag_l0_me.c プロジェクト: rshigemura/freediag
/*
 * 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
 */
static int
diag_l0_muleng_initbus(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in)
{
	int rv = 0;
	struct diag_l0_muleng_device *dev;

	dev = (struct diag_l0_muleng_device *)dl0d->l0_int;

	if (!dev)
		return diag_iseterr(DIAG_ERR_GENERAL);

	if (diag_l0_debug & DIAG_DEBUG_IOCTL)
		fprintf(stderr, FLFMT "device link %p info %p initbus type %d proto %d\n",
			FL, (void *)dl0d, (void *)dev, in->type, dev->protocol);

	diag_tty_iflush(dl0d); /* Empty the receive buffer, wait for idle bus */

	if (in->type == DIAG_L1_INITBUS_5BAUD)
		rv = diag_l0_muleng_slowinit(dl0d, in, dev);
	else
	{
		/* Do wakeup on first TX */
		dev->dev_wakeup = in->type;
		dev->dev_state = MULENG_STATE_FASTSTART;
	}

	return rv;
}
コード例 #2
0
ファイル: diag_l0_me.c プロジェクト: rshigemura/freediag
/*
 * Open the diagnostic device, returns a file descriptor
 * records original state of term interface so we can restore later
 */
static struct diag_l0_device *
diag_l0_muleng_open(const char *subinterface, int iProtocol)
{
	int rv;
	struct diag_l0_device *dl0d;
	struct diag_l0_muleng_device *dev;
	struct diag_serial_settings set;

	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "open subinterface %s protocol %d\n",
			FL, subinterface, iProtocol);
	}

	diag_l0_muleng_init();

	if ((rv=diag_calloc(&dev, 1)))
		return diag_pseterr(rv);

	dev->protocol = iProtocol;

	dl0d = diag_l0_new(&diag_l0_me, (void *)dev);
	if (!dl0d) {
		free(dev);
		return diag_pseterr(rv);
	}
	/* try to open TTY */
	if ((rv=diag_tty_open(dl0d, subinterface))) {
		diag_l0_del(dl0d);
		free(dev);
		return diag_pseterr(rv);
	}

	/* And set to 19200 baud , 8N1 */

	set.speed = 19200;
	set.databits = diag_databits_8;
	set.stopbits = diag_stopbits_1;
	set.parflag = diag_par_n;

	if ((rv=diag_tty_setup(dl0d, &set))) {
		diag_l0_muleng_close(dl0d);
		return diag_pseterr(rv);
	}

	/* And set DTR high and RTS low to power the device */
	if ((rv=diag_tty_control(dl0d, 1, 0))) {
		diag_l0_muleng_close(dl0d);
		return diag_pseterr(rv);
	}

	diag_tty_iflush(dl0d);	/* Flush unread input */

	return dl0d ;
}
コード例 #3
0
ファイル: diag_l0_dumb.c プロジェクト: shirou/freediag
/*
 * Open the diagnostic device, returns a file descriptor
 * records original state of term interface so we can restore later
 */
static struct diag_l0_device *
diag_l0_dumb_open(const char *subinterface, int iProtocol)
{
	int rv;
	struct diag_l0_device *dl0d;
	struct diag_l0_dumb_device *dev;

	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "open subinterface %s protocol %d\n",
			FL, subinterface, iProtocol);
	}

	diag_l0_dumb_init();	 //make sure it is initted

	if ((rv=diag_calloc(&dev, 1)))
		return diag_pseterr(DIAG_ERR_NOMEM);

	dev->protocol = iProtocol;

	dl0d = diag_l0_new(&diag_l0_dumb, (void *)dev);
	if (!dl0d) {
		free(dev);
		return diag_pseterr(rv);
	}
	/* try to open TTY */
	if ((rv=diag_tty_open(dl0d, subinterface))) {
		diag_l0_del(dl0d);
		free(dev);
		return diag_pseterr(rv);
	}

	/*
	 * We set RTS to low, and DTR high, because this allows some
	 * interfaces to work than need power from the DTR/RTS lines;
	 * this is altered according to dumb_flags.
	 */
	if (diag_tty_control(dl0d, !(dumb_flags & CLEAR_DTR), (dumb_flags & SET_RTS)) < 0) {
		diag_l0_dumb_close(&dl0d);
		return diag_pseterr(DIAG_ERR_GENERAL);
	}

	if (dumb_flags & DUMBDEFAULTS)
		dumb_flags = DUMBDEFAULTS & MAN_BREAK;

	(void)diag_tty_iflush(dl0d);	/* Flush unread input */

	return dl0d;
}
コード例 #4
0
ファイル: diag_l0_br.c プロジェクト: shirou/freediag
/*
 * 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
 */
static int
diag_l0_br_initbus(struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in)
{
	int rv = 0;
	struct diag_l0_br_device *dev;

	dev = (struct diag_l0_br_device *)dl0d->l0_int;

	if (diag_l0_debug & DIAG_DEBUG_IOCTL)
		fprintf(stderr,
			FLFMT "device link %p info %p initbus type %d proto %d\n",
			FL, (void *)dl0d, (void *)dev, in->type,
			dev ? dev->protocol : -1);

	if (!dev)
		return diag_iseterr(DIAG_ERR_GENERAL);

	diag_tty_iflush(dl0d); /* Flush unread input */

	switch (in->type)
	{
	case DIAG_L1_INITBUS_5BAUD:
		rv = diag_l0_br_slowinit(dl0d, in);
		break;
	case DIAG_L1_INITBUS_FAST:
		if ((dev->dev_features & BR_FEATURE_FASTINIT) == 0)
		{
			/* Fast init Not supported */
			rv = DIAG_ERR_INIT_NOTSUPP;
		}
		else
		{
			/* Fastinit done on 1st TX */
			dev->dev_state = BR_STATE_KWP_FASTINIT;
			rv = 0;
		}
		break;
	default:
		rv = DIAG_ERR_INIT_NOTSUPP;
		break;
	}
	return rv? diag_iseterr(rv):0 ;
}
コード例 #5
0
ファイル: diag_l0_br.c プロジェクト: fenugrec/freediag
/*
 * Open the diagnostic device, return a file descriptor,
 * record the original state of term interface so we can restore later
 */
static int br_open(struct diag_l0_device *dl0d, int iProtocol) {
	struct br_device *dev = dl0d->l0_int;
	int rv;
	uint8_t buf[4];	/* Was MAXRBUF. We only use 1! */
	struct diag_serial_settings set;

	br_init();

	dev->protocol = iProtocol;
	dev->dev_rdoffset = 0;
	dev->dev_txlen = 0;
	dev->dev_framenr = 0;
	dev->dev_state = BR_STATE_CLOSED;
	dev->dev_features = BR_FEATURE_SETADDR;

	/* try to open TTY */
	dev->tty_int = diag_tty_open(dev->port.val.str);
	if (dev->tty_int == NULL) {
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
		FLFMT "features 0x%X\n", FL, dev->dev_features);

	/* Set serial line to 19200 baud , 8N1 */
	set.speed = 19200;
	set.databits = diag_databits_8;
	set.stopbits = diag_stopbits_1;
	set.parflag = diag_par_n;

	if (diag_tty_setup(dev->tty_int, &set)) {
		fprintf(stderr, FLFMT "open: TTY setup failed\n", FL);
		br_close(dl0d);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	diag_tty_iflush(dev->tty_int);	/* Flush unread input data */

	/*
	 * Initialise the BR1 interface by sending the CHIP CONNECT
	 * (0x20h) command, we should get a 0xFF back
	 */
	buf[0] = 0x20;
	if (br_write(dl0d, buf, 1)) {
		DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
			FLFMT "CHIP CONNECT write failed link %p\n",
			FL, (void *)dl0d);

		br_close(dl0d);
		return diag_iseterr(DIAG_ERR_BADIFADAPTER);
	}
	/* And expect 0xff as a response */
	if (diag_tty_read(dev->tty_int, buf, 1, 100) != 1) {
		DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
			FLFMT "CHIP CONNECT read failed link %p\n",
			FL, (void *)dl0d);

		br_close(dl0d);
		return diag_iseterr(DIAG_ERR_BADIFADAPTER);
	}
	if (buf[0] != 0xff) {
		DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
			FLFMT "CHIP CONNECT rcvd 0x%X != 0xff, link %p\n",
			FL, buf[0], (void *)dl0d);

		br_close(dl0d);
		return diag_iseterr(DIAG_ERR_BADIFADAPTER);
	}

	/* If it's J1850, send initialisation string now */
	rv = 0;
	switch (iProtocol) {
	case DIAG_L1_J1850_VPW:
		rv = br_initialise(dl0d, 0, 0);
		break;
	case DIAG_L1_J1850_PWM:
		rv = br_initialise(dl0d, 1, 0);
		break;
	case DIAG_L1_ISO9141:
	case DIAG_L1_ISO14230:
		/* This initialisation is done in the SLOWINIT code */
		break;
	}
	if (rv) {
		br_close(dl0d);
		return diag_ifwderr(rv);
	}

	DIAG_DBGM(diag_l0_debug, DIAG_DEBUG_OPEN, DIAG_DBGLEVEL_V,
		FLFMT "open succeeded link %p features 0x%X\n",
		FL, (void *)dl0d, dev->dev_features);

	dl0d->opened = 1;
	return 0;
}
コード例 #6
0
ファイル: diag_l0_br.c プロジェクト: shirou/freediag
/*
 * Open the diagnostic device, return a file descriptor,
 * record the original state of term interface so we can restore later
 */
static struct diag_l0_device *
diag_l0_br_open(const char *subinterface, int iProtocol)
{
	struct diag_l0_device *dl0d;
	struct diag_l0_br_device *dev;
	int rv;
	uint8_t buf[4];	/* Was MAXRBUF. We only use 1! */
	struct diag_serial_settings set;

	diag_l0_br_init();

	if ((rv=diag_calloc(&dev, 1)))
		return diag_pseterr(rv);

	dev->protocol = iProtocol;
	dev->dev_rdoffset = 0;
	dev->dev_txlen = 0;
	dev->dev_framenr = 0;
	dev->dev_state = BR_STATE_CLOSED;
	dev->dev_features = BR_FEATURE_SETADDR;

	/* Get an L0 link */
	dl0d = diag_l0_new(&diag_l0_br, (void *)dev);
	if (!dl0d) {
		free(dev);
		return diag_pseterr(rv);
	}
	/* try to open TTY */
	if ((rv=diag_tty_open(dl0d, subinterface))) {
		diag_l0_del(dl0d);
		free(dev);
		return diag_pseterr(rv);
	}

	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "features 0x%X\n", FL, dev->dev_features);
	}

	/* Set serial line to 19200 baud , 8N1 */
	set.speed = 19200;
	set.databits = diag_databits_8;
	set.stopbits = diag_stopbits_1;
	set.parflag = diag_par_n;

	if (diag_tty_setup(dl0d, &set)) {
		fprintf(stderr, FLFMT "open: TTY setup failed\n", FL);
		diag_l0_br_close(&dl0d);
		return diag_pseterr(rv);
	}

	diag_tty_iflush(dl0d);	/* Flush unread input data */

	/*
	 * 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(dl0d, buf, 1)) {
		if ((diag_l0_debug&DIAG_DEBUG_OPEN)) {
			fprintf(stderr, FLFMT "CHIP CONNECT write failed link %p\n",
				FL, (void *)dl0d);
		}
		diag_l0_br_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}
	/* And expect 0xff as a response */
	if (diag_tty_read(dl0d, buf, 1, 100) != 1) {
		if (diag_l0_debug & DIAG_DEBUG_OPEN) {
			fprintf(stderr, FLFMT "CHIP CONNECT read failed link %p\n",
				FL, (void *)dl0d);
		}

		diag_l0_br_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}
	if (buf[0] != 0xff) {
		if (diag_l0_debug & DIAG_DEBUG_OPEN) {
			fprintf(stderr, FLFMT "CHIP CONNECT rcvd 0x%X != 0xff, link %p\n",
				FL, buf[0], (void *)dl0d);
		}

		diag_l0_br_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}

	/* If it's J1850, send initialisation string now */
	rv = 0;
	switch (iProtocol)
	{
	case DIAG_L1_J1850_VPW:
		rv = diag_l0_br_initialise(dl0d, 0, 0);
		break;
	case DIAG_L1_J1850_PWM:
		rv = diag_l0_br_initialise(dl0d, 1, 0);
		break;
	case DIAG_L1_ISO9141:
	case DIAG_L1_ISO14230:
		/* This initialisation is done in the SLOWINIT code */
		break;
	}
	if (rv) {
		diag_l0_br_close(&dl0d);
		return diag_pseterr(rv);
	}

	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "open succeeded link %p features 0x%X\n",
			FL, (void *)dl0d, dev->dev_features);
	}
	return dl0d;
}
コード例 #7
0
ファイル: diag_l0_elm.c プロジェクト: shirou/freediag
/*
 * Open the diagnostic device
 * ELM settings used : no echo (E0), headers on (H1), linefeeds off (L0), mem off (M0)
 */
static struct diag_l0_device *
diag_l0_elm_open(const char *subinterface, int iProtocol)
{
	int i,rv;
	struct diag_l0_device *dl0d;
	struct diag_l0_elm_device *dev;
	struct diag_serial_settings sset;
	const uint8_t *buf;
	uint8_t rxbuf[ELM_BUFSIZE];

	const char ** elm_official;
	const char ** elm_clones;	//point to elm323_ or elm327_ clone and official version string lists

	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "open subinterface %s protocol %d\n",
			FL, subinterface, iProtocol);
	}

	diag_l0_elm_init();

	if ((rv=diag_calloc(&dev, 1)))
		return diag_pseterr(rv);

	dev->protocol = iProtocol;

	dl0d = diag_l0_new(&diag_l0_elm, (void *)dev);
	if (!dl0d) {
		free(dev);
		return diag_pseterr(rv);
	}
	/* try to open TTY */
	if ((rv=diag_tty_open(dl0d, subinterface))) {
		diag_l0_del(dl0d);
		free(dev);
		return diag_pseterr(rv);
	}

	//set speed to 38400;8n1.
	sset.speed=38400;
	sset.databits = diag_databits_8;
	sset.stopbits = diag_stopbits_1;
	sset.parflag = diag_par_n;

	dev->serial = sset;

	if ((rv=diag_tty_setup(dl0d, &sset))) {
		fprintf(stderr, FLFMT "Error setting 38400;8N1 on %s\n",
			FL, subinterface);
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(rv);
	}

	diag_tty_iflush(dl0d);	/* Flush unread input */

	//At this stage, the ELM has possibly been powered up for a while;
	//it may have an unfinished command / garbage in its input buffer. We
	//need to clear that before sending the real ATZ ==> ATI is quick and safe; elm_purge does this.

	dev->elmflags=0;	//we know nothing yet

	rv=elm_purge(dl0d);
	//if rv=0, we got a prompt so we know speed is set properly.
	if (rv==0) {
		dev->elmflags |= ELM_38400;
	} else {
		fprintf(stderr, FLFMT "sending ATI @ 38400 failed; trying @ 9600...\n", FL);

		sset.speed=9600;
		dev->serial = sset;

		if ((rv=diag_tty_setup(dl0d, &sset))) {
			fprintf(stderr, FLFMT "Error setting 9600;8N1 on %s\n",
				FL, subinterface);
			diag_l0_elm_close(&dl0d);
			return diag_pseterr(rv);
		}

		diag_tty_iflush(dl0d);	/* Flush unread input */
		rv = elm_purge(dl0d);	//try ATI\r again
		if (rv !=0) {
			fprintf(stderr, FLFMT "sending ATI @ 9600 failed. Verify connection to ELM\n", FL);
			diag_l0_elm_close(&dl0d);
			return diag_pseterr(DIAG_ERR_BADIFADAPTER);
		}
	}

	if (diag_l0_debug&DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "elm_open : sending ATZ...\n", FL);
	}

	//the command "ATZ" causes a full reset and the ELM replies with
	//a string like "ELM32x vX.Xx\n>"

	buf=(uint8_t *)"ATZ\x0D";
	rv=elm_sendcmd(dl0d, buf, 4, 2000, rxbuf);
	if (rv) {
		fprintf(stderr, FLFMT "elm_open : ATZ failed !\n", FL);
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}

	//Correct prompt received; try to identify device.
	// 1) guess 323 vs 327
	if (strstr((char *)rxbuf, "ELM323")!=NULL) {
		dev->elmflags |= ELM_323_BASIC;
		elm_official=elm323_official;
		elm_clones=elm323_clones;
	} else if (strstr((char *)rxbuf, "ELM327")!=NULL) {
		dev->elmflags |= ELM_327_BASIC;
		elm_official=elm327_official;
		elm_clones=elm327_clones;
	} else {
		fprintf(stderr, FLFMT "no valid version string !! Report this !. Got:\n%s\n", FL, rxbuf);
		//no point in continuing...
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}
	// 2) identify valid VS clone devices.
	rv=0;	// temp "device identified" flag
	for (i=0; elm_clones[i]; i++) {
		if (strstr((char *)rxbuf, elm_clones[i])) {
			printf("Clone ELM found, v%s\n", elm_clones[i]);
			dev->elmflags |= ELM_32x_CLONE;
			rv=1;
			break;
		}
	}

	if (rv==0) {
		for (i=0; elm_official[i]; i++) {
				if (strstr((char *)rxbuf, elm_official[i])) {
				printf("Official ELM found, v%s\n", elm_official[i]);
				rv=1;
				break;
			}
		}
	}

	if (rv==0) {
		//still not identified : assume clone.
		dev->elmflags |= ELM_32x_CLONE;
		printf("ELM version not recognized! Please report this ! Resp=%s\n", rxbuf);
	}

	if ((dev->elmflags & ELM_323_BASIC) && (dev->elmflags & ELM_32x_CLONE)) {
		printf("A 323 clone ? Report this !\n");
	}


	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "ELM reset success, elmflags=%#x\n", FL, dev->elmflags);
	}

	//now send "ATE0\n" command to disable echo.
	buf=(uint8_t *)"ATE0\x0D";
	if (elm_sendcmd(dl0d, buf, 5, 500, NULL)) {
		if (diag_l0_debug & DIAG_DEBUG_OPEN) {
			fprintf(stderr, FLFMT "sending \"ATE0\" failed\n", FL);
		}
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}

	//ATL0 : disable linefeeds
	buf=(uint8_t *)"ATL0\x0D";
	if (elm_sendcmd(dl0d, buf, 5, 500, NULL)) {
		if (diag_l0_debug & DIAG_DEBUG_OPEN) {
			fprintf(stderr, FLFMT "sending \"ATL0\" failed\n", FL);
		}
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}

	//ATH1 : always show header bytes
	buf=(uint8_t *)"ATH1\x0D";
	if (elm_sendcmd(dl0d, buf, 5, 500, NULL)) {
		if (diag_l0_debug & DIAG_DEBUG_OPEN) {
			fprintf(stderr, FLFMT "sending \"ATH1\" failed\n", FL);
		}
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
	}

	//for elm327 only: disable memory
	if (dev->elmflags & ELM_327_BASIC) {
		buf=(uint8_t *)"ATM0\x0D";
		if (elm_sendcmd(dl0d, buf, 5, 500, NULL)) {
			if (diag_l0_debug & DIAG_DEBUG_OPEN) {
				fprintf(stderr, FLFMT "sending \"ATM0\" failed\n", FL);
			}
			diag_l0_elm_close(&dl0d);
			return diag_pseterr(DIAG_ERR_BADIFADAPTER);
		}
	}

	//check if proto is really supported (323 supports only 9141 and 14230)
	if ((dev->elmflags & ELM_323_BASIC) &&
		((iProtocol != DIAG_L1_ISO9141) && (iProtocol != DIAG_L1_ISO14230)))
			return diag_pseterr(DIAG_ERR_PROTO_NOTSUPP);

	//if 327, set proto when possible; we won't if 14230, because init type (fast vs slow) isn't decided yet
	// CAN is also not implemented here
	buf=NULL;
	if (dev->elmflags & ELM_327_BASIC) {
		switch (iProtocol) {
		case DIAG_L1_J1850_PWM:
			buf=(uint8_t *)"ATTP1\x0D";
			break;
		case DIAG_L1_J1850_VPW:
			buf=(uint8_t *)"ATTP2\x0D";
			break;
		case DIAG_L1_ISO9141:
			buf=(uint8_t *)"ATTP3\x0D";
			break;
		default:
			buf=NULL;
		}
	}

	if (buf != NULL) {
		if (elm_sendcmd(dl0d, buf, 6, 500, NULL)) {
			if (diag_l0_debug & DIAG_DEBUG_OPEN) {
				fprintf(stderr, FLFMT "sending \"ATTPx\" failed\n", FL);
			}
		diag_l0_elm_close(&dl0d);
		return diag_pseterr(DIAG_ERR_BADIFADAPTER);
		}
	}


	//at this point : ELM is ready for further ops
	if (diag_l0_debug & DIAG_DEBUG_OPEN) {
		fprintf(stderr, FLFMT "ELM ready.\n", FL);
	}
	return dl0d;
}
コード例 #8
0
ファイル: diag_l0_elm.c プロジェクト: shirou/freediag
//Send a command to ELM device and make sure no error occured. Data is passed on directly as a string;
//caller must make sure the string is \r-terminated , i.e. 0x0D-terminated.
//Sending 0A after 0D will cause ELM to interrupt what it's doing to "process" 0A, resulting in a
//failure.
//This func should not be used for commands that elicit a data response (i.e. all data destined to the OBD bus,
//hence not prefixed by "AT"). Response is dumped in *resp (0-terminated) for optional analysis by caller; *resp must be ELM_BUFSIZE long.
//returns 0 if (prompt_good) && ("OK" found anywhere in the response) && (no known error message was present) ||
//		(prompt_good && ATZ command was sent) , since response doesn't contain "OK" for ATZ.
//elm_sendcmd should not be called from outside diag_l0_elm.c.
static int
elm_sendcmd(struct diag_l0_device *dl0d, const uint8_t *data, size_t len, unsigned int timeout, uint8_t *resp)
{
	//note : we better not request (len == (size_t) -1) bytes ! The casts between ssize_t and size_t are
	// "muddy" in here
	//ssize_t xferd;
	int rv;
	uint8_t ebuf[ELM_BUFSIZE];	//local buffer if caller provides none.
	uint8_t *buf;
	struct diag_l0_elm_device *dev;
	const char *err_str;	//hold a possible error message

	dev = (struct diag_l0_elm_device *)dl0d->l0_int;
	//we need access to diag_l0_elm_device to access .elmflags

	if (resp==NULL)
		buf=ebuf;	//use local buffer
	else
		buf=resp;	//or caller-provided buffer

	if (!len)
		return diag_iseterr(DIAG_ERR_BADLEN);
	if (!dev)
		return diag_iseterr(DIAG_ERR_BADFD);


	if (data[len-1] != 0x0D) {
		//Last byte is not a carriage return, this would die.
		fprintf(stderr, FLFMT "elm_sendcmd: non-terminated command : %.*s\n", FL, (int) len, (char *) data);
		//the %.*s is pure magic : limits the string length to len, even if the string is not null-terminated.
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	diag_tty_iflush(dl0d);	//currently the code often "forgets" data in the input buffer, especially if the previous
					//transaction failed. Flushing the input increases the odds of not crashing soon

	if (diag_l0_debug & DIAG_DEBUG_WRITE) {
		fprintf(stderr, FLFMT "elm_sendcmd: %.*s\n", FL, (int) len-1, (char *)data);
	}

	rv = diag_tty_write(dl0d, data, len);
	if (rv != (int) len) {	//XXX danger ! evil cast
		fprintf(stderr, FLFMT "elm_sendcmd: write error\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	//next, receive ELM response, within {ms} delay.

	rv=diag_tty_read(dl0d, buf, ELM_BUFSIZE-1, timeout);	//rv=# bytes read

	if (rv<1) {
		//no data or error
		if (diag_l0_debug & DIAG_DEBUG_WRITE) {
			fprintf(stderr, FLFMT "ELM did not respond\n", FL);
		}
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	if (diag_l0_debug & DIAG_DEBUG_READ) {
		elm_parse_cr(buf, rv);	//debug output is prettier with this
		fprintf(stderr, FLFMT "received %d bytes (%.*s\n); hex: ", FL, rv, rv, (char *)buf);
		if (diag_l0_debug & DIAG_DEBUG_DATA) {
			diag_data_dump(stderr, buf, rv);
			fprintf(stderr, "\n");
		}
	}
	buf[rv]=0;	//terminate string
	if (buf[rv-1] != '>') {
		//if last character isn't the input prompt, there is a problem
		fprintf(stderr, FLFMT "ELM not ready (no prompt received): %s\nhex: ", FL, buf);
		diag_data_dump(stderr, buf, rv);
		fprintf(stderr, "\n");
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	//At this point we got a prompt but there may have been an error message.
	//There is some ambiguity in the ELM datasheets on the exact format of the replies.
	//1) the prompt character '>' is always alone on its line;
	//2) depending on some parameters, it may be preceded by 0D or 0D 0A
	//3) some errors ( "<DATA ERROR" and "<RX ERROR" ) can be appended after
	//a reply; others should be at the beginning of the response (alone on a line)

	//ex. of good reply : "41 00 00 \r>", bad reply :"NO DATA\r>"
	//let's just use strstr() to find occurences for each known error.
	//it'll take a while but speed isn't normally critical when sending commands

	err_str = elm_parse_errors(dl0d, buf);

	if (err_str != NULL) {
		fprintf(stderr, FLFMT "ELM returned error : %s\n", FL, err_str);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	//check if we either 1)got a positive response "OK"
	//2)were sending ATZ (special case hack, it doesn't answer "OK")
	if ((strstr((char *)buf, "OK") != NULL) ||
		(strstr((char *)data, "ATZ") != NULL)) {
		return 0;
	}

	fprintf(stderr, FLFMT "Response not recognized ! Report this ! Got: \n", FL);
	diag_data_dump(stderr, buf, rv);
	fprintf(stderr, "\n");
	return diag_iseterr(DIAG_ERR_GENERAL);

}
コード例 #9
0
ファイル: diag_l0_me.c プロジェクト: rshigemura/freediag
/*
 * Do 5 Baud initialisation
 *
 * In the case of ISO9141 we operate in the interface's "raw" mode
 * (VAG compatibility mode), in 14230 we do a slow init and send
 * a tester present message
 */
static int
diag_l0_muleng_slowinit( struct diag_l0_device *dl0d, struct diag_l1_initbus_args *in,
		struct diag_l0_muleng_device *dev)
{
	/*
	 * Slow init
	 * Build message into send buffer, and calculate checksum
	 */
	uint8_t txbuf[15];
	uint8_t rxbuf[15];
	int rv;
	unsigned int baud;

	memset(txbuf, 0, sizeof(txbuf));
	txbuf[0] = INTERFACE_ADDRESS;

	switch (dev->protocol) {
	case DIAG_L1_ISO9141:
		txbuf[1] = 0x20;	/* Raw mode 5 baud init */
		txbuf[2] = in->addr;
		break;
	case DIAG_L1_ISO14230:
		txbuf[1] = 0x85;
		txbuf[2] = 0x01;		/* One byte message */
		txbuf[3] = DIAG_KW2K_SI_TP;	/* tester present */
		break;
	}

	/*
	 * Calculate the checksum, and send the request
	 */
	(void)diag_l0_muleng_txcksum(txbuf);
	if ((rv = diag_l0_muleng_write(dl0d, txbuf, 15)))
		return diag_iseterr(rv);

	/*
	 * Get answer
	 */
	switch (dev->protocol) {
	case DIAG_L1_ISO9141:
		/*
		 * This is raw mode, we should get a single byte back
		 * with the timing interval, then we need to change speed
		 * to match that speed. Remember it takes 2 seconds to send
		 * the 10 bit (1+8+1) address at 5 baud
		 */
		rv = diag_tty_read(dl0d, rxbuf, 1, 2350);
		if (rv != 1)
			return diag_iseterr(DIAG_ERR_GENERAL);

		if (rxbuf[0] == 0x40) {
			/* Problem ..., got an error message */

			diag_tty_iflush(dl0d); /* Empty the receive buffer */

			return diag_iseterr(DIAG_ERR_GENERAL);
		}
		baud = me_baud_table[rxbuf[0]];

		if (diag_l0_debug & DIAG_DEBUG_PROTO)
			fprintf(stderr, FLFMT "device link %p setting baud to %u\n",
				FL, (void *)dl0d, baud);

		if (baud) {
			struct diag_serial_settings set;
			set.speed = baud;
			set.databits = diag_databits_8;
			set.stopbits = diag_stopbits_1;
			set.parflag = diag_par_n;

			/* And set the baud rate */
			diag_tty_setup(dl0d, &set);
		}

		dev->dev_state = MULENG_STATE_RAW;

		break;
	case DIAG_L1_ISO14230:
		/* XXX
		 * Should get an ack back, rather than an error response
		 */
		if ((rv = diag_tty_read(dl0d, rxbuf, 14, 200)) < 0)
			return diag_iseterr(rv);

		if (rxbuf[1] == 0x80)
			return diag_iseterr(DIAG_ERR_GENERAL);

		/*
 		 * Now send the "get keybyte" request, and wait for
		 * response
		 */
		memset(txbuf, 0, sizeof(txbuf));
		txbuf[0] = INTERFACE_ADDRESS;
		txbuf[1] = 0x86;
		(void)diag_l0_muleng_txcksum(txbuf);
		rv = diag_l0_muleng_write(dl0d, txbuf, 15);
		if (rv < 0)
			return diag_iseterr(rv);

		if ((rv = diag_tty_read(dl0d, rxbuf, 14, 200)) < 0)
			return diag_iseterr(rv);

		if (rxbuf[1] == 0x80)	/* Error */
			return diag_iseterr(rv);
		/*
		 * Store the keybytes
		 */
		dev->dev_kb1 = rxbuf[2];
		dev->dev_kb2 = rxbuf[3];
		/*
		 * And tell read code to report the keybytes on first read
		 */
		dev->dev_state = MULENG_STATE_KWP_SENDKB1;
		break;
	}


	return rv;
}