[C con Clase] Ayuda Puerto Serial

D1e6o! diegogeid en gmail.com
Mar Ene 30 23:29:59 CET 2007


Muchas Gracias..! Si, debo usar el puerto serie porque es más rápido y es
configurable con respecto a interrupciones por lo que tengo entendido... Y
es compatible, pero no logro encontrar mucha información. Solo esto que me
pierde... Encontré algo que puede serme muy útil pero estoy realmente
perdido.. je son muchas cosas juntas...!

Si alguien tiene una idea de por donde puedo empezar va a ser bienvenida..!
y si a alguien le sirve, acá está (no tenía sentido poner todo el codigo
fuente entero ya que es largo, esta es solo una parte)

lo que encontré es esto que corresponde al programa winlirc de código libre
(GNU)

/*
 * This file is part of the WinLIRC package, which was derived from
 * LIRC (Linux Infrared Remote Control) 0.5.4pre9.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Copyright (C) 1999 Jim Paris <jim en jtan.com>
 * Modifications Copyright (C) 2000 Scott Baily <baily en uiuc.edu>
 * RX device, some other stuff Copyright (C) 2002 Alexander Nesterovsky <
Nsky en users.sourceforge.net>
 */

#include "irdriver.h"
#include "irconfig.h"
#include "config.h"
#include "remote.h"
#include "drvdlg.h"
#include "server.h"

unsigned int IRThread(void *drv) {((CIRDriver *)drv)->ThreadProc();return
0;}
unsigned int DaemonThread(void *drv) {((CIRDriver
*)drv)->DaemonThreadProc();return 0;}

CIRDriver::CIRDriver()
{
    hPort=NULL;
    ov.hEvent=NULL;
    hDataReadyEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
}

CIRDriver::~CIRDriver()
{
    DEBUG("~CIRDriver\n");
    ResetPort();
    KillThread(&IRThreadHandle,&IRThreadEvent);
    KillThread(&DaemonThreadHandle,&DaemonThreadEvent);
    if(hDataReadyEvent) CloseHandle(hDataReadyEvent);
}

bool CIRDriver::InitPort(CIRConfig *cfg, bool daemonize)
{
    struct ir_remote *tmp;
    if(cfg==NULL) return false;

    DEBUG("Initializing port...\n");

    KillThread(&IRThreadHandle,&IRThreadEvent);
    KillThread(&DaemonThreadHandle,&DaemonThreadEvent);
    cbuf_start=cbuf_end=0;

    if(ov.hEvent)
    {
        SetEvent(ov.hEvent);    // singal it
        Sleep(100);                // wait a tiny bit
        CloseHandle(ov.hEvent);    // and close it
        ov.hEvent=NULL;
    }

    if(hPort)
    {
        SetCommMask(hPort,0);    // stop any waiting on the port
        Sleep(100);                // wait a tiny bit
        CloseHandle(hPort);        // and close it
        hPort=NULL;
    }

    if((hPort=CreateFile(
        cfg->port,GENERIC_READ | GENERIC_WRITE,
        0,0,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,0))==INVALID_HANDLE_VALUE)
    {
        hPort=NULL;
        return false;
    }

    DCB dcb;
    if(!GetCommState(hPort,&dcb))
    {
        CloseHandle(hPort);
        hPort=NULL;
        return false;
    }
    if (cfg->animax) dcb.fDtrControl=DTR_CONTROL_ENABLE; //set DTR high, the
animax receiver needs this for power
    else
        dcb.fDtrControl=DTR_CONTROL_DISABLE; // set the transmit LED to off
initially.
    dcb.fRtsControl=RTS_CONTROL_ENABLE;

    dcb.BaudRate = cfg->speed;
    devicetype = cfg->devicetype;
    virtpulse = cfg->virtpulse;

    if(!SetCommState(hPort,&dcb))
    {
        CloseHandle(hPort);
        hPort=NULL;
        DEBUG("SetCommState failed.\n");
        return false;
    }
    tmp=global_remotes;
    while (tmp!=NULL && tmp->next!=NULL) {
        if (!(tmp->flags&SPECIAL_TRANSMITTER))
tmp->transmitter=cfg->transmittertype;
        tmp=tmp->next;
    }
    SetTransmitPort(hPort,cfg->transmittertype);

    if(cfg->sense==-1)
    {
        /* Wait for receiver to settle (since we just powered it on) */
        Sleep(1000);
        DWORD state;
        if(!GetCommModemStatus(hPort,&state))
        {
            CloseHandle(hPort);
            hPort=NULL;
            return false;
        }
        sense=(state & MS_RLSD_ON) ? 1 : 0;
        DEBUG("Sense set to %d\n",sense);
    }
    else
        sense=cfg->sense;

    if((ov.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL))==NULL)
    {
        CloseHandle(hPort);
        hPort=NULL;
        return false;
    }

    /* Start the thread */
    /* THREAD_PRIORITY_TIME_CRITICAL combined with the
REALTIME_PRIORITY_CLASS */
    /* of this program results in the highest priority (26 out of 31) */
    if((IRThreadHandle=
        AfxBeginThread(IRThread,(void
*)this,THREAD_PRIORITY_TIME_CRITICAL))==NULL)
    {
        CloseHandle(hPort);
        CloseHandle(ov.hEvent);
        hPort=ov.hEvent=NULL;
        return false;
    }

    if(daemonize)
    {

        /* Start the thread */
        /* THREAD_PRIORITY_IDLE combined with the REALTIME_PRIORITY_CLASS */
        /* of this program still results in a really high priority. (16 out
of 31) */
        if((DaemonThreadHandle=
            AfxBeginThread(DaemonThread,(void
*)this,THREAD_PRIORITY_IDLE))==NULL)
        {
            KillThread(&IRThreadHandle,&IRThreadEvent);
            CloseHandle(hPort);
            CloseHandle(ov.hEvent);
            hPort=ov.hEvent=NULL;
            return false;
        }
    }

    DEBUG("Port initialized.\n");

    return true;
}

HANDLE CIRDriver::GetCommPort()
{
    return(hPort);
}
void CIRDriver::ResetPort(void)
{
    DEBUG("Resetting port\n");

    KillThread(&IRThreadHandle,&IRThreadEvent);
    KillThread(&DaemonThreadHandle,&DaemonThreadEvent);

    if(ov.hEvent) {
        CloseHandle(ov.hEvent);
        ov.hEvent=NULL;
    }
    if(hPort) {
        CloseHandle(hPort);
        hPort=NULL;
    }
}

void CIRDriver::ThreadProc(void)
{
    /* Virtually no error checking is done here, because */
    /* it's pretty safe to assume that everything works, */
    /* and we have nowhere to report errors anyway.      */

    /* We use two timers in case the high resolution doesn't   */
    /* last too long before wrapping around (is that true?     */
    /* is it really only a 32 bit timer or a true 64 bit one?) */

    __int64 hr_time, hr_lasttime, hr_freq;    // high-resolution
    time_t lr_time, lr_lasttime;            // low-resolution

    DWORD status;
    GetCommModemStatus(hPort, &status);
    int prev=(status & MS_RLSD_ON) ? 1 : 0;

    /* Initialize timer stuff */
    QueryPerformanceFrequency((LARGE_INTEGER *)&hr_freq);

    /* Get time (both LR and HR) */
    time(&lr_lasttime);
    QueryPerformanceCounter((LARGE_INTEGER *)&hr_lasttime);

    HANDLE events[2]={ov.hEvent,IRThreadEvent};

    for(;;)
    {
        /* We want to be notified of DCD or RX changes */
        if(SetCommMask(hPort, devicetype ? EV_RLSD : EV_RXCHAR)==0)
        {
            DEBUG("SetCommMask returned zero, error=%d\n",GetLastError());
        }
        /* Reset the event */
        ResetEvent(ov.hEvent);
        /* Start waiting for the event */
        DWORD event;
        if(WaitCommEvent(hPort,&event,&ov)==0 && GetLastError()!=997)
        {
            DEBUG("WaitCommEvent error: %d\n",GetLastError());
        }

        /* Wait for the event to get triggered */
        int res=WaitForMultipleObjects(2,events,FALSE,INFINITE);

        /* Get time (both LR and HR) */
        QueryPerformanceCounter((LARGE_INTEGER *)&hr_time);
        time(&lr_time);

        if(res==WAIT_FAILED)
        {
            DEBUG("Wait failed.\n");
            continue;
        }

        if(res==(WAIT_OBJECT_0+1))
        {
            DEBUG("IRThread terminating\n");
            AfxEndThread(0);
            return;
        }

        if(res!=WAIT_OBJECT_0)
        {
            DEBUG("Wrong object\n");
            continue;
        }

        int dcd;
        if (devicetype) {
            GetCommModemStatus(hPort,&status);

            dcd = (status & MS_RLSD_ON) ? 1 : 0;

            if(dcd==prev)
            {
                /* Nothing changed?! */
                /* Continue without changing time */
                continue;
            }

            prev=dcd;
        }

        int deltv=lr_time-lr_lasttime;
        if (devicetype && (deltv>15)) {
            /* More than 15 seconds passed */
            deltv=0xFFFFFF;
            if(!(dcd^sense))
            {
                /* sense had to be wrong */
                sense=sense?0:1;
                DEBUG("sense was wrong!\n");
            }
        } else
            deltv=(int)(((hr_time-hr_lasttime)*1000000) / hr_freq);

        lr_lasttime=lr_time;
        hr_lasttime=hr_time;

        int data;
        if (devicetype) {
            data = (dcd^sense) ? (deltv) : (deltv | 0x1000000);

            if(SetData(data))
                SetEvent(hDataReadyEvent);
        } else {
            data = deltv;

            SetData(data-100);
            if(SetData(virtpulse | 0x1000000))
                SetEvent(hDataReadyEvent);
            PurgeComm(hPort,PURGE_RXCLEAR);
        }
    }
}

bool CIRDriver::SetData(unsigned long int src)
{
    int diff=cbuf_start-cbuf_end;
    if(cbuf_end>cbuf_start) diff+=CBUF_LEN;
    if(diff==1)
    {
        DEBUG("buffer full\n");
        return false;
    }

    cbuf[cbuf_end++]=src;
    if(cbuf_end>=CBUF_LEN) cbuf_end=0;

    return true;
}

bool CIRDriver::GetData(unsigned long int *dest)
{
    if(cbuf_end==cbuf_start)
        return false;

    *dest=cbuf[cbuf_start++];
    if(cbuf_start>=CBUF_LEN) cbuf_start=0;
    return true;
}

unsigned long CIRDriver::readdata(unsigned long maxusec, HANDLE ThreadEvent)
{
    unsigned long int x=0;

    HANDLE events[2]={hDataReadyEvent,ThreadEvent};
    int evt;
    if(ThreadEvent==NULL) evt=1;
    else evt=2;

    if(GetData(&x)==false)
    {
        ResetEvent(hDataReadyEvent);
        int res;
        if(maxusec)
            res=WaitForMultipleObjects(evt,events,FALSE,(maxusec+500)/1000);
        else
            res=WaitForMultipleObjects(evt,events,FALSE,INFINITE);
        if(res==(WAIT_OBJECT_0+1))
        {
            DEBUG("Unknown thread terminating (readdata)\n");
            AfxEndThread(0);
            return 0;
        }
        GetData(&x);
    }

    return x;
}

void CIRDriver::DaemonThreadProc(void)
{
    /* Accept client connections,        */
    /* and watch the data buffer.        */
    /* When data comes in, decode it    */
    /* and send the result to clients.    */
    unsigned long data;
    char *message;

        Cwinlirc *app = (Cwinlirc *)AfxGetApp();

    for(;;)
    {
        if(GetData(&data)==false)
        data=readdata(0,DaemonThreadEvent);
        use_ir_hardware=true;
        message=decode_command(data);
        if(message!=NULL)
        {
            //DEBUG("decode_command successful\n");
            drvdlg->GoGreen();
            app->server->send(message);
        }
        else
        {
            //DEBUG("decode_command failed\n");
        }
    }
}


Si alguien tiene una idea de por donde puedo empezar va a ser bienvenida..!
y si a alguien le sirve, acá está (no tenía sentido poner todo el codigo
fuente entero ya que es largo, esta es solo una parte)
Un saludo a todos y muchas gracias por los aportes!

El día 27/01/07, Juan Antonio <jalr43 en hotmail.com> escribió:
>
>  Hola,
>
> gracias Steven por la aclaración y Diego de nada, aquí estamos todos para
> ayudarnos.
>
> Diego yo en tu caso vería la opción de usar el puerto paralelo en vez del
> serie. Conectaría la línea en la que se van a producir los cambios en el pin
> de datos menos significativo (LSB). Luego deberías establecer la frecuencia
> con la que quieres muestrear la la línea, es decir leer los datos del puerto
> a partir del conocimiento de tu dispositivo, porque supongo que puedes
> estimar una frecuencia de muestreo para no cometer mucho error en las
> medidas de la anchura de los pulsos. Ojo en un puerto serie que sigue la
> norma RS-232 la tensiones oscilan entre +15 y -15V, el  puerto pararalelo
> trabaja con 0 y 5V, aunque lo mismo si tu dispositivo no transmite con
> ningún protocolo tampoco sigue los niveles de tensión del RS-232.
>
> Para hacerlo con puerto serie, para que el PC se entere que le quieres
> enviar datos la señal tiene que pasar de '1' (entre -3 y -15V) a '0' (de 3 a
> 15V) que es el bit de inicio o los que hayan, para decirle que el dato
> termina se necesita enviar los bits de parada (paso de '0' a '1')
> establecidos al configurar la comunicación. Entonces claro se podría usar
> una función para ver si hay datos en el puerto, mientrás no hayan la señal
> ha permanecido a '1' por lo que la puedes contar el tiempo a partir de la
> velocidad de transmisión. Mi duda es la señal cambia de '1' a '0', la UART
> empieza a muestrear, pero si la señal no vuelve a pasar de '0' a '1' en el
> tiempo configurado del puerto (que se obtiene a partir de la velocidad) para
> indicar los bits de parada después de los bits de datos, sobrescribirá los
> datos anteriores o ocurrirá algún error.
>
> Lo mismo también puedes usar alguna de las líneas de control como
> mencionastes en el primer mensaje, navega, busca su significado, si son
> compatibles en voltios con tu entrada y con qué función puedes leerlas.
>
> Espero que te sirva.
>
> Un saludo,
> Juan Antonio.
>
> ----- Original Message -----
> *From:* D1e6o! <diegogeid en gmail.com>
> *To:* Lista de correo sobre C y C++ <cconclase en listas.conclase.net>
> *Sent:* Friday, January 26, 2007 4:52 AM
> *Subject:* Re: [C con Clase] Ayuda Puerto Serial
>
> Antes que nada siempre agradezco a quienes se toman un tiempo en leer o
> contestar mis dudas... (creo que está bien ser agradecido y saber reconocer)
> así que Juan Antonio muchas gracias por todo (entre otros que leyeron)
>
> El tema es el siguiente: (y te entiendo que no me hayas entendido.. je, no
> me expliqué muy bien) estoy intentando analizar lógicamente datos
> asincrónicos, que no poseen bits de stop ni de paridad ni nada por el
> estilo, a eso me refería sin protocolo, ya que para eso necesitaría conectar
> un microcontrolador y no, el circuito ya está armado así. Entonces debería
> comuncarme con el pc y que este detecte el ancho (en tiempo) de los pulsos,
> que no de error y poder almacenar en un buffer el tiempo entre un '1' lógico
> y un '0' y viceversa, y a eso viene mi pregunta, como podría hacer para
> lograrlo? Sé que se puede, pero no se como... El problema central es conocer
> en tiempo cuando cambia de estado el pin dts, y si es posible asignarle
> alguna interrupción o algo por el estilo para poder almacenar en una pila
> estas duraciones.
>
> Muchas gracias! (y perdón por expresarme mal)
>
> Saludos!
>
> El día 25/01/07, Juan Antonio <jalr43 en hotmail.com > escribió:
> >
> >  Hola Diego,
> >
> > no lo encuentro sentido a medir la anchura de los pulso cuanto depende
> > exclusivamente de la velocidad a la que tengas configurado el puerto. Por
> > ejemplo si la velocidad es de 9600 bps, es decir 9600 bits por segundo la
> > anchura de cada bit que se transmite es 1/9600 = 104.16 microsegundos.
> > Entonces cuando se hayan transmitido 9600 bits habrá pasado un segundo,
> > 104.16 microsegundos = 1/9600 que por 9600 devuelte 1 segundo.
> >
> > Si los datos los vas a leer en un PC, lo que se envía por el puerto
> > deberías seguir la norma RS-232, porque el puerto del PC conecta con una
> > UART que se encarga de quitar de la trama los bits de comienzo y parada
> > almacanando el dato resultante en una pila.
> >
> > Yo hicé un diseño una vez creando el protocolo RS-232 es tan fácil como
> > tener la rutina de espera de un bit: poner la línea con el valor del bit,
> > rutina de espera de un bit, poner el la línea el siguiente valor, etc.
> > Lógicamente si los bits de parada, comienzo no son 1 ó 2, por ejemplo
> > 1.5 bits también hace falta una rutina de espea de 1/2 bit.
> >
> > Si explicas con más detalle tu problema quizá te pueda ayudar, es decir
> > conecto en el pueto serie del PC un cacharro que cambia el valor de la señal
> > que transmite sin ningún protocolo.
> >
> > Un saludo,
> > Juan Antonio.
> >
> >  ----- Original Message -----
> > *From:* D1e6o! <diegogeid en gmail.com>
> > *To:* Lista de correo sobre C y C++ <cconclase en listas.conclase.net>
> > *Sent:* Thursday, January 25, 2007 7:13 PM
> > *Subject:* [C con Clase] Ayuda Puerto Serial
> >
> > Hola gente, bueno estoy programando un poco con el puerto serial y
> > quería saber si alguien tiene ideas de esto: No de una comunicación a través
> > de rs232 por el puerto serial sino sin protocolo, es decir, medir el ancho
> > de los pulsos (1 y 0) para después procesarlos... Se que se puede.. pero no
> > se como, tengo entendido que es por los pines rts y dtr del puerto serie
> > pero como hago para saber el estado en tiempo real de los pines?...
> >
> > Saludos si alguien tiene algo acerca de esto cualquier cosa me sirve..!
> >
> > Gracias..
> >
> > ------------------------------
> >
> > _______________________________________________
> > Lista de correo Cconclase Cconclase en listas.conclase.net
> >
> > http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> > Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
> >
> >
> > _______________________________________________
> > Lista de correo Cconclase Cconclase en listas.conclase.net
> > http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> >
> > Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
> >
> >
>  ------------------------------
>
> _______________________________________________
> Lista de correo Cconclase Cconclase en listas.conclase.net
> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>
>
> _______________________________________________
> Lista de correo Cconclase Cconclase en listas.conclase.net
> http://listas.conclase.net/mailman/listinfo/cconclase_listas.conclase.net
> Bajas: http://listas.conclase.net/index.php?gid=2&mnu=FAQ
>
>
------------ próxima parte ------------
Se ha borrado un adjunto en formato HTML...
URL: <http://listas.conclase.net/pipermail/cconclase_listas.conclase.net/attachments/20070130/949fc29c/attachment.html>


Más información sobre la lista de distribución Cconclase