コード例 #1
0
ファイル: diag_tty_win.c プロジェクト: shirou/freediag
/*
 * Set/Clear DTR and RTS lines, as specified
 * on Win32 this can easily be done by calling EscapeCommFunction twice.
 * This takes around ~15-20us to do; probably with ~10 us skew between setting RTS and DTR.
 * If it proves to be a problem, it's possible to change both RTS and DTR at once by updating
 * the DCB and calling SetCommState. That call would take around 30-40us.
 * Note : passing 1 in dtr or rts means "set DTR/RTS", i.e. positive voltage.
 * ret 0 if ok
 */
int
diag_tty_control(struct diag_l0_device *dl0d,  unsigned int dtr, unsigned int rts)
{
    unsigned int escapefunc;
    struct tty_int *wti = (struct tty_int *)dl0d->tty_int;


    if (wti->fd == INVALID_HANDLE_VALUE) {
        fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    if (dtr)
        escapefunc=SETDTR;
    else
        escapefunc=CLRDTR;

    if (! EscapeCommFunction(wti->fd,escapefunc)) {
        fprintf(stderr, FLFMT "Could not change DTR: %s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    if (rts)
        escapefunc=SETRTS;
    else
        escapefunc=CLRRTS;

    if (! EscapeCommFunction(wti->fd,escapefunc)) {
        fprintf(stderr, FLFMT "Could not change RTS: %s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    return 0;
} //diag_tty_control
コード例 #2
0
ファイル: diag_tty_win.c プロジェクト: remspoor/freediag
ssize_t
diag_tty_read(struct diag_l0_device *dl0d, void *buf, size_t count, unsigned int timeout) {
	DWORD bytesread;
	ssize_t rv=DIAG_ERR_TIMEOUT;
	OVERLAPPED *pOverlap;
	struct tty_int *wti = (struct tty_int *)dl0d->tty_int;
	pOverlap=NULL;
	COMMTIMEOUTS devtimeouts;

	if ((count <= 0) || (timeout <= 0)) return DIAG_ERR_BADLEN;

	if (diag_l0_debug & DIAG_DEBUG_READ) {
		fprintf(stderr, FLFMT "tty_read: ttyh=%p, fd=%p, len=%u, t=%u\n", FL,
					(void *)wti, (void *)wti->fd, count, timeout);
	}

	if (wti->fd == INVALID_HANDLE_VALUE) {
		fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

//	GetCommTimeouts(dl0d->fd, &devtimeouts);	//get current timeouts
	//and modify them
	devtimeouts.ReadIntervalTimeout= timeout ? 0:MAXDWORD;	//disabled unless timeout was 0.
	devtimeouts.ReadTotalTimeoutMultiplier=0;	//timeout per requested byte
	devtimeouts.ReadTotalTimeoutConstant=timeout;	// (tconst + mult*numbytes) = total timeout on read
	devtimeouts.WriteTotalTimeoutMultiplier=0;	//probably useless as all flow control will be disabled ??
	devtimeouts.WriteTotalTimeoutConstant=0;
	if (! SetCommTimeouts(wti->fd, &devtimeouts)) {
		fprintf(stderr, FLFMT "Could not set comm timeouts: %s\n",FL, diag_os_geterr(0));
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

	if (! ReadFile(wti->fd, buf, count, &bytesread, pOverlap)) {
		fprintf(stderr, FLFMT "ReadFile error: %s\n",FL, diag_os_geterr(0));
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	if (bytesread > 0)
		rv=bytesread;
	return rv;

}
コード例 #3
0
ファイル: diag_tty_win.c プロジェクト: remspoor/freediag
ssize_t diag_tty_write(struct diag_l0_device *dl0d, const void *buf, const size_t count) {
	DWORD byteswritten;
	OVERLAPPED *pOverlap;
	struct tty_int *wti = (struct tty_int *)dl0d->tty_int;
	pOverlap=NULL;		//note : if overlap is eventually enabled, the CreateFile flags should be adjusted

	if (wti->fd == INVALID_HANDLE_VALUE) {
		fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}

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

	if (! WriteFile(wti->fd, buf, count, &byteswritten, pOverlap)) {
		fprintf(stderr, FLFMT "WriteFile error:%s. %u bytes written, %u requested\n", FL, diag_os_geterr(0), (unsigned int) byteswritten, (unsigned) count);
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	if (!FlushFileBuffers(wti->fd)) {
		fprintf(stderr, FLFMT "tty_write : could not flush buffers, %s\n", FL, diag_os_geterr(0));
		return diag_iseterr(DIAG_ERR_GENERAL);
	}
	return byteswritten;
} //diag_tty_write
コード例 #4
0
ファイル: diag_tty_win.c プロジェクト: shirou/freediag
/*
 * diag_tty_fastbreak: send 0x00 at 360bps => fixed 25ms break; return [ms] after starting break.
 * This is for ISO14230 fast init : typically diag_tty_fastbreak(dl0d, 50)
 * It assumes the interface is half-duplex.
 * Ret 0 if ok
 */
int diag_tty_fastbreak(struct diag_l0_device *dl0d, const unsigned int ms) {
    HANDLE dh;	//just to clarify code
    struct tty_int *wti = (struct tty_int *)dl0d->tty_int;
    DCB tempDCB; 	//for sabotaging the settings just to do the break
    DCB origDCB;
    LARGE_INTEGER qpc1, qpc2, qpc3;	//to time the break period
    LONGLONG timediff;		//64bit delta
    long int tremain,counts, break_error;

    uint8_t cbuf;
    int xferd;
    DWORD byteswritten;

    dh = wti->fd;
    if (ms<25)		//very funny
        return diag_iseterr(DIAG_ERR_TIMEOUT);

    if (dh == INVALID_HANDLE_VALUE) {
        fprintf(stderr, FLFMT "Error. Is the port open ?\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    GetCommState(dh, &origDCB);
    GetCommState(dh, &tempDCB); //ugly, but a memcpy would be worse

    tempDCB.BaudRate=360;
    tempDCB.ByteSize=8;
    tempDCB.fParity=0;
    tempDCB.Parity=NOPARITY;
    tempDCB.StopBits=ONESTOPBIT;

    if (! SetCommState(dh, &tempDCB)) {
        fprintf(stderr, FLFMT "SetCommState error\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    /* Send a 0x00 byte message */

    if (! WriteFile(dh, "\0", 1, &byteswritten, NULL)) {
        fprintf(stderr, FLFMT "WriteFile error:%s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }
    //get approx starting time. I think this is the closest we can
    //get to the actual time the byte gets sent since we call FFB
    //right after.
    QueryPerformanceCounter(&qpc1);

    if (!FlushFileBuffers(dh)) {
        fprintf(stderr, FLFMT "FFB error, %s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }


    /*
     * And read back the single byte echo, which shows TX completes
     */
    xferd = diag_tty_read(dl0d, &cbuf, 1, ms + 20);

    //we'll usually have a few ms left to wait; we'll use this
    //to restore the port settings

    if (! SetCommState(dh, &origDCB)) {
        fprintf(stderr, FLFMT "tty_fastbreak: could not restore setting: %s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    //Not getting the echo byte doesn't mean fastbreak has necessarily
    // failed. But we really should be getting an echo back...
    if (xferd < 0)
        return diag_iseterr(xferd);
    if ((xferd == 0) || (cbuf != 0)) {
        /* Error, EOF or bad echo */
        fprintf(stderr, FLFMT "Did not get fastbreak echo!\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }


    QueryPerformanceCounter(&qpc2);		//get current time,
    timediff=qpc2.QuadPart-qpc1.QuadPart;	//elapsed counts since diag_tty_write
    counts=(ms*perfo_freq.QuadPart)/1000;		//total # of counts for requested tWUP
    tremain=counts-timediff;	//counts remaining
    if (tremain<=0)
        return 0;

    tremain = ((LONGLONG) tremain*1000)/perfo_freq.QuadPart;	//convert to ms; imprecise but that should be OK.
    diag_os_millisleep((unsigned int) tremain);
    QueryPerformanceCounter(&qpc3);

    timediff=qpc3.QuadPart-qpc1.QuadPart;	//total cycle time.
    break_error= (long) timediff - counts;	//real - requested
    break_error= (long) (break_error * pf_conv);	//convert to us !
    if (break_error > 1000 || break_error < -1000)
        fprintf(stderr, FLFMT "tty_fastbreak: tWUP out of spec by %ldus!\n", FL, break_error);


    return 0;
}	//diag_tty_fastbreak
コード例 #5
0
ファイル: diag_tty_win.c プロジェクト: shirou/freediag
//diag_tty_open : open specified port for L0
int diag_tty_open(struct diag_l0_device *dl0d,
                  const char *portname)
{
    int rv;
    struct tty_int *wti;
    size_t n = strlen(portname) + 1;
    COMMTIMEOUTS devtimeouts;

    if (!dl0d) return diag_iseterr(DIAG_ERR_GENERAL);

    if ((rv=diag_calloc(&wti,1))) {
        return diag_iseterr(rv);
    }

    dl0d->tty_int = wti;
    wti->fd = INVALID_HANDLE_VALUE;

    //allocate space for portname name
    if ((rv=diag_malloc(&wti->name, n))) {
        free(dl0d->tty_int);
        return diag_iseterr(rv);
    }
    //Now, in case of errors we can call diag_tty_close() on the dl0d since its members are alloc'ed
    strncpy(wti->name, portname, n);

    wti->fd=CreateFile(portname, GENERIC_READ | GENERIC_WRITE, 0, NULL,
                       OPEN_EXISTING,
                       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
                       NULL);
    //File hande is created as non-overlapped. This may change eventually.

    if (wti->fd != INVALID_HANDLE_VALUE) {
        if (diag_l0_debug & DIAG_DEBUG_OPEN)
            fprintf(stderr, FLFMT "Device %s opened, fd %p\n",
                    FL, wti->name, wti->fd);
    } else {
        fprintf(stderr,
                FLFMT "Open of device interface \"%s\" failed: %s\n",
                FL, wti->name, diag_os_geterr(0));
        fprintf(stderr, FLFMT
                "(Make sure the device specified corresponds to the\n", FL );
        fprintf(stderr,
                FLFMT "serial device your interface is connected to.\n", FL);

        diag_tty_close(dl0d);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    //purge & abort everything.
    PurgeComm(wti->fd,PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);

    //as opposed to the unix diag_tty.c ; this one doesn't save previous commstate. The next program to use the COM port
    //will need to deal with it...

    //We will load the DCB with the current comm state. This way we only need to call GetCommState once during a session
    //and the DCB should contain coherent initial values
    if (! GetCommState(wti->fd, &wti->dcb)) {
        fprintf(stderr, FLFMT "Could not get comm state: %s\n",FL, diag_os_geterr(0));
        diag_tty_close(dl0d);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    //Finally set COMMTIMEOUTS to reasonable values (all in ms) ?
    devtimeouts.ReadIntervalTimeout=30;	//i.e. more than 30ms between received bytes
    devtimeouts.ReadTotalTimeoutMultiplier=5;	//timeout per requested byte
    devtimeouts.ReadTotalTimeoutConstant=20;	// (constant + multiplier*numbytes) = total timeout on read(buf, numbytes)
    devtimeouts.WriteTotalTimeoutMultiplier=0;	//probably useless as all flow control will be disabled ??
    devtimeouts.WriteTotalTimeoutConstant=0;
    if (! SetCommTimeouts(wti->fd,&devtimeouts)) {
        fprintf(stderr, FLFMT "Could not set comm timeouts: %s\n",FL, diag_os_geterr(0));
        diag_tty_close(dl0d);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    return 0;
} //diag_tty_open
コード例 #6
0
ファイル: diag_tty_win.c プロジェクト: shirou/freediag
/*
 * Set speed/parity etc of dl0d with settings in pset
 * ret 0 if ok
 */
int
diag_tty_setup(struct diag_l0_device *dl0d,
               const struct diag_serial_settings *pset)
{
    HANDLE devhandle;		//just to clarify code
    struct tty_int *wti;
    DCB *devstate;
    COMMPROP supportedprops;
    DCB verif_dcb;

    wti = (struct tty_int *)dl0d->tty_int;
    devhandle = wti->fd;
    devstate = &wti->dcb;

    if (devhandle == INVALID_HANDLE_VALUE) {
        fprintf(stderr, FLFMT "setup: something is not right\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    //optional : verify if device supports the requested settings. Testing required to see if USB->serial bridges support this !
    //i.e. some l0 devices try to set 5bps which isn't supported on some devices.
    //For now let's just check if it supports custom baud rates. This check should be added to diag_tty_open where
    //it would set appropriate flags to allow _l0 devices to adapt their functionality.
    if (! GetCommProperties(devhandle,&supportedprops)) {
        fprintf(stderr, FLFMT "could not getcommproperties: %s\n",FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }
    //simple test : only check if custom baud rates are supported, but don't abort if they aren't. Just notify user.
    if ( !(supportedprops.dwMaxBaud & BAUD_USER))
        fprintf(stderr, FLFMT "warning : device does not support custom baud rates !\n", FL);



    if (diag_l0_debug & DIAG_DEBUG_IOCTL)
    {
        fprintf(stderr, FLFMT "dev %p; %dbps %d,%d,%d \n",
                FL, (void *)devhandle, pset->speed,
                pset->databits, pset->stopbits, pset->parflag);
    }

    /*
     * Now load the DCB with the parameters requested.
     */
    // the DCB (devstate) has been loaded with initial values in diag_tty_open so it should already coherent.
    devstate->BaudRate = pset->speed;
    devstate->fBinary=1;	// always binary mode.
    switch (pset->parflag) {
    case diag_par_n:
        //no parity : disable parity in the DCB
        devstate->fParity=0;
        devstate->Parity=NOPARITY;
        break;
    case diag_par_e:
        devstate->fParity=1;
        devstate->Parity=EVENPARITY;
        break;
    case diag_par_o:
        devstate->fParity=1;
        devstate->Parity=ODDPARITY;
        break;
    default:
        fprintf(stderr,
                FLFMT "bad parity setting used !\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
        break;
    }
    devstate->fOutxCtsFlow=0;
    devstate->fOutxDsrFlow=0;	//disable output flow control
    devstate->fDtrControl=DTR_CONTROL_DISABLE;	//XXX allows to permanently set the DTR line !
    devstate->fDsrSensitivity=0;		//pay no attention to DSR for receiving
    devstate->fTXContinueOnXoff=1;	//probably irrelevant ?
    devstate->fOutX=0;		//disable Xon/Xoff tx flow ctl
    devstate->fInX=0;		//disable XonXoff rx flow ctl
    devstate->fErrorChar=0;	//do not replace data with bad parity
    devstate->fNull=0;		// do not discard null bytes ! on rx
    devstate->fRtsControl=RTS_CONTROL_DISABLE;	//XXX allows to set the RTS line!
    devstate->fAbortOnError=0;		//do not abort transfers on error ?
    devstate->wReserved=0;
    devstate->ByteSize=pset->databits;	//bits per byte
    switch (pset->stopbits) {
    case diag_stopbits_1:
        devstate->StopBits=ONESTOPBIT;
        break;
    case diag_stopbits_2:
        devstate->StopBits=TWOSTOPBITS;
        break;
    default:
        fprintf(stderr, FLFMT "bad stopbit setting used!)\n", FL);
        return diag_iseterr(DIAG_ERR_GENERAL);
        break;
    }
    // DCB in devstate is now filled.
    if (! SetCommState(devhandle, devstate)) {
        fprintf(stderr, FLFMT "Could not SetCommState: %s\n",FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    //to be really thorough we do another GetCommState and check that the speed was set properly.
    //This *may* help to detect if the serial port supports non-standard baudrates (5bps being
    //particularly problematic with USB->serial converters)
    //I see no particular reason to check all the other fields though.

    if (! GetCommState(devhandle, &verif_dcb)) {
        fprintf(stderr, FLFMT "Could not verify with GetCommState: %s\n", FL, diag_os_geterr(0));
        return diag_iseterr(DIAG_ERR_GENERAL);
    }
    if (verif_dcb.BaudRate != pset->speed) {
        fprintf(stderr, FLFMT "SetCommState failed : speed is currently %u\n", FL, (unsigned int) verif_dcb.BaudRate);
        return diag_iseterr(DIAG_ERR_GENERAL);
    }

    return 0;
} //diag_tty_setup