コード例 #1
0
ファイル: diag_l0_me.c プロジェクト: rshigemura/freediag
/*
 * Safe write routine; return 0 on success
 */
static int
diag_l0_muleng_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen)
{
	if (txlen <=0)
		return diag_iseterr(DIAG_ERR_BADLEN);

	if ( (diag_l0_debug & (DIAG_DEBUG_WRITE|DIAG_DEBUG_DATA)) ==
			(DIAG_DEBUG_WRITE|DIAG_DEBUG_DATA) )
	{
		fprintf(stderr, FLFMT "device link %p sending to ME device: ",
			FL, (void *)dl0d);
		diag_data_dump(stderr, dp, txlen);
		fprintf(stderr, "\n");
	}

	/*
	 * And send it to the interface
	 */
	if (diag_tty_write(dl0d, dp, txlen) != (int) txlen) {
		fprintf(stderr, FLFMT "muleng_write error!!\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	return 0;
}
コード例 #2
0
ファイル: diag_l0_br.c プロジェクト: RIndriulis/freediag
static int
diag_l0_br_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen)
{
	ssize_t xferd;

	while ((size_t)(xferd = diag_tty_write(dl0d, dp, txlen)) != txlen) {
		if (xferd < 0) {
			/* error */
			if (errno != EINTR) {
				fprintf(stderr, FLFMT "write returned error %s.\n",
					FL, strerror(errno));
				return diag_iseterr(DIAG_ERR_GENERAL);
			}
			xferd = 0; /* Interrupted read, nothing transferred. */
			errno = 0;
		}
		/*
		 * Successfully wrote xferd bytes (or 0 bytes if EINTR),
		 * so increment the pointers and continue
		 */
		txlen -= (size_t) xferd;
		dp = (const void *)((const char *)dp + xferd);
	}
	return 0;
}
コード例 #3
0
ファイル: diag_l0_br.c プロジェクト: shirou/freediag
static int
diag_l0_br_write(struct diag_l0_device *dl0d, const void *dp, size_t txlen)
{
	if (txlen <=0)
		return diag_iseterr(DIAG_ERR_BADLEN);

	if (diag_tty_write(dl0d, dp, txlen) != (int) txlen) {
		fprintf(stderr, FLFMT "br_write error\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	return 0;
}
コード例 #4
0
ファイル: diag_l0_elm.c プロジェクト: shirou/freediag
static int
diag_l0_elm_send(struct diag_l0_device *dl0d,
	UNUSED(const char *subinterface), const void *data, size_t len)
{
	uint8_t buf[ELM_BUFSIZE];
	//ssize_t xferd;
	int rv;
	unsigned int i;

	if (len <= 0)
		return diag_iseterr(DIAG_ERR_BADLEN);

	if ((2*len)>(ELM_BUFSIZE-1)) {
		//too much data for buffer size
		fprintf(stderr, FLFMT "ELM: too much data for buffer (report this bug please!)\n", FL);
		return diag_iseterr(DIAG_ERR_BADLEN);
	}

	if (diag_l0_debug & DIAG_DEBUG_WRITE) {
		fprintf(stderr, FLFMT "ELM: sending %d bytes\n", FL, (int) len);
	}

	for (i=0; i<len; i++) {
		//fill buffer with ascii-fied hex data
		snprintf((char *) &buf[2*i], 3, "%02X", (unsigned int)((uint8_t *)data)[i] );
	}
	i=2*len;
	buf[i]=0x0D;
	buf[i+1]=0x00;	//terminate string

	if ((diag_l0_debug & DIAG_DEBUG_WRITE) && (diag_l0_debug & DIAG_DEBUG_DATA)) {
		fprintf(stderr, FLFMT "ELM: (sending string %s)\n", FL, (char *) buf);
	}

	rv=diag_tty_write(dl0d, buf, i+1);
	if (rv != (int) (i+1)) {	//XXX danger ! evil cast !
		fprintf(stderr, FLFMT "elm_send:write error\n",FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	return 0;
}
コード例 #5
0
ファイル: diag_l0_elm.c プロジェクト: shirou/freediag
//elm_purge : sends ATI command and checks for a valid prompt. This is faster than ATZ.
//use : if the ELM received garbage before ATI, ex.: "\xFF\xFFATI\r" it will just reject
//the invalid command but still give a valid prompt.
//Return 0 only if a valid prompt was received.
static int elm_purge(struct diag_l0_device *dl0d) {
	uint8_t buf[ELM_BUFSIZE] = "ATI\x0D";
	int rv;

	if (diag_tty_write(dl0d, buf, 4) != 4) {
		fprintf(stderr, FLFMT "elm_purge : write error\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	rv = diag_tty_read(dl0d, buf, sizeof(buf), ELM_PURGETIME);
	if (rv < 1) {
		return DIAG_ERR_GENERAL;
	}

	if (buf[rv-1] != '>') {
		if (diag_l0_debug & DIAG_DEBUG_DATA) {
			fprintf(stderr, FLFMT "elm_purge: got ", FL);
			diag_data_dump(stderr, buf, rv);
			fprintf(stderr, "\n");
		}
		return DIAG_ERR_GENERAL;
	}
	return 0;
}
コード例 #6
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);

}
コード例 #7
0
ファイル: diag_tty.c プロジェクト: butljon/freediag
/*
 * diag_tty_break
 */
int diag_tty_break(struct diag_l0_device *dl0d, const int ms)
{
	char cbuf;
	struct timeval tv;
	int xferd;
	struct diag_serial_settings set;

	/*
	 *	We need to send an 25ms (+/- 1ms) break
	 *	and then wait 25ms. We must have waited Tidle (300ms) first
	 *
	 *	The trouble here is Linux doesn't let us be that accurate sending
	 *	a break - so we do it by sending a '0x00' at a baud rate that means
	 *	the output is low for 25ms, then we wait for 25ms, using busy
	 *	waits (which we get from being in real-time mode and doing nanosleeps
	 *	of less than 2ms each)
	 *
	 */

	/* Set baud rate etc to 360 baud, 8, N, 1 */
	set.speed = 360;
	set.databits = diag_databits_8;
	set.stopbits = diag_stopbits_1;
	set.parflag = diag_par_n;

	diag_tty_setup(dl0d, &set);

	gettimeofday(&tv,NULL);
	/* Send a 0x00 byte message */
	diag_tty_write(dl0d, "", 1);
	
	if (diag_l0_debug & DIAG_DEBUG_TIMER) {
		fprintf(stderr, FLFMT "%04ld.%03ld : break start\n", FL, tv.tv_sec, tv.tv_usec);
	}

	/*
	 * And read back the single byte echo, which shows TX completes
 	 */
	while ( (xferd = diag_tty_read(dl0d, &cbuf, 1, 1000)) <= 0)
	{
		if (xferd == DIAG_ERR_TIMEOUT)
			return diag_iseterr(DIAG_ERR_TIMEOUT);
		if (xferd == 0)
		{
			/* Error, EOF */
			fprintf(stderr, FLFMT "read returned EOF.\n", FL);
			return diag_iseterr(DIAG_ERR_GENERAL);
		}
		if (errno != EINTR)
		{
			/* Error, EOF */
			fprintf(stderr, FLFMT "read returned error %s.\n", FL,
				strerror(errno));
			return diag_iseterr(DIAG_ERR_GENERAL);
		}
	}

	/* Now wait the requested number of ms */
	gettimeofday(&tv,NULL);
	diag_os_millisleep(ms);
	if (diag_l0_debug & DIAG_DEBUG_TIMER) {
		fprintf(stderr, FLFMT "%04ld.%03ld : end of break_L\n", FL, tv.tv_sec, tv.tv_usec);
	}

	return 0;
}