Serial Comm Handle Problem



  • Hallo Leute,

    I wrote a code to do serial communication with an equipament.
    When i use the code outside of threaded class it seens work properly,
    but when i put inside a class and execute a thread in the first seconds the
    communication is ok, later i receive read/write error.
    I´ve been in MSDN site and there i discover that the read/write error is a
    INVALID_HANDLE problem. But why??? I just create the serial communication
    file and use it.
    Anyone can help me?

    Here is the code

    /* cut /
    /
    --------------------------------------------------------------------*/
    /* Main Class */

    #ifndef _IGERENCIADOREQUIPAMENTO_H
    #define _IGERENCIADOREQUIPAMENTO_H

    #include <stdio.h>
    #include <windows.h>

    #define SERIAL_PARITY_NONE 0
    #define SERIAL_PARITY_ODD 1
    #define SERIAL_PARITY_EVEN 2

    #define SERIAL_MAX_RX 256 // Input buffer max size
    #define SERIAL_MAX_TX 256 // output buffer max size

    #define SERIAL_CONNECTED 0
    #define SERIAL_DISCONNECTED 1
    #define SERIAL_DATA_SENT 2
    #define SERIAL_DATA_ARRIVAL 3
    #define SERIAL_RING 4
    #define SERIAL_CD_ON 5
    #define SERIAL_CD_OFF 6
    #define SERIAL_DATA_RECV 7

    #define SERIAL_SIGNAL_NBR 7

    class IGerenciadorEquipamento;

    typedef struct
    {
    HANDLE serialFD;
    IGerenciadorEquipamento* pIGE;
    }_SERIALCOM_IONICS;

    class IGerenciadorEquipamento: public IThread
    {

    private:
    HANDLE hSerial;
    char *cPortaSerial;
    DWORD dwBaudRate;
    BYTE byByteSize;
    BYTE byTipoParidade;
    bool conectado;
    bool bRX_In_Progress; // BOOL indicating if a
    ReadFile is
    // in progress
    bool bTX_In_Progress; // BOOL indicating if a
    WriteFile is
    // in progress

    unsigned char pacoteIN[256];
    unsigned char pacoteOUT[256];

    bool bConectado;

    int ConfigTimeouts(COMMTIMEOUTS mCommtimeout);
    int ConfigDCB(DCB mDCB);

    public:
    IGerenciadorEquipamento(char *mcPortaSerial, DWORD mdwBaudRate,
    BYTE mbyByteSize, BYTE mbyiTipoParidade);
    ~IGerenciadorEquipamento();

    int AtivaEquipamento(BOOL mbIniciaThread = true);
    int DesativaEquipamento(BOOL mbFinalizaThread = true);
    int EscreveMensagem(HANDLE hSerialCOM,unsigned char* mcMensagem, int
    miTamanho);
    int LeMensagem(HANDLE hSerialCOM,unsigned char* mcMensagem, int
    miTamanho);
    void PurgeSerial(void);
    bool VerificaEstado(void);
    int Run(void);
    HANDLE GetSerialHND(void);
    void OnSendRecv(void);
    unsigned char *GetDadosRecebidos(void);
    unsigned char *GetDadosEnviados(void);

    int EnviaPOLLING(HANDLE hSerialCOM);
    int ConcedePrivilegio(HANDLE hSerialCOM, BYTE byEndereco);
    void TraduzMens(unsigned char *ucPacote, DWORD miTamanho);
    DWORD IGerenciadorEquipamento::ExtraiCMD(unsigned char ucPacoteIN,
    DWORD dStartpos,
    DWORD dQtdebytes,
    unsigned char
    ucPacoteOUT);

    };

    //DWORD WINAPI ComSendRecv(LPVOID p);
    int ComSendRecv(LPVOID p);

    #endif

    /--------------------------------------------------------------------/
    /* until here */

    /* cut /
    /
    --------------------------------------------------------------------*/
    /* Main Class Code */

    //#define STRICT
    #include <cstdlib>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <process.h>
    #include <conio.h>
    #include <windows.h>
    #include <iostream>
    #include <math.h>
    #include "IGerenciadorEquipamento.hpp"
    #include "StringMethods.hpp"
    #include "Consts.hpp"
    #include "TipoProtocolo.hpp"

    #define SIG_POWER_DOWN 0
    #define SIG_READER 1
    #define SIG_READ_DONE 2 // data received has been read
    #define SIG_WRITER 3
    #define SIG_DATA_TO_TX 4 // data waiting to be sent
    #define SIG_MODEM_EVENTS 5
    #define SIG_MODEM_CHECKED 6

    using namespace std;

    typedef struct
    {
    BYTE controladora;
    BYTE tentativas;
    bool detectaprot;
    }STRU_CONFCONTROL;

    STRU_CONFCONTROL ConfControl;

    unsigned char *IGerenciadorEquipamento::GetDadosRecebidos(void)
    {
    return pacoteOUT;
    }

    unsigned char *IGerenciadorEquipamento::GetDadosEnviados(void)
    {
    return pacoteIN;
    }

    int IGerenciadorEquipamento::EnviaPOLLING(HANDLE hSerialCOM)
    {
    unsigned char ucPacoteIN[256];
    unsigned char ucPacoteOUT[256];
    int iTotalLido;

    ZeroMemory(ucPacoteIN,3);

    ucPacoteIN[0] = SYN;
    ucPacoteIN[1] = '1';
    ucPacoteIN[2] = 0x55;

    EscreveMensagem(hSerialCOM ,ucPacoteIN,3);
    iTotalLido=LeMensagem(hSerialCOM ,ucPacoteOUT,30);
    if (iTotalLido)
    {
    if ((ucPacoteOUT[0] == SYN) && (ucPacoteOUT[1] == '1') &&
    (ucPacoteOUT[2] == 0xAA))
    ConfControl.detectaprot = false;
    }
    return iTotalLido;
    }

    int IGerenciadorEquipamento::ConcedePrivilegio(HANDLE hSerialCOM, BYTE
    byEndereco)
    {
    unsigned char ucPacoteIN[256];
    int iTotalEscrito;

    ZeroMemory(ucPacoteIN,3);

    // privilegio
    ucPacoteIN[0] = SYN;
    ucPacoteIN[1] = byEndereco+48;
    ucPacoteIN[2] = ACK;

    iTotalEscrito=EscreveMensagem(hSerialCOM ,ucPacoteIN,3);
    return iTotalEscrito;
    }

    void IGerenciadorEquipamento::TraduzMens(unsigned char *ucPacote, DWORD
    miTamanho)
    {
    int iCanal;
    double dLitros;
    char cPulsos[8];
    double dPulsos;
    char parcelaPacote;
    char cInd;
    int iInd;
    int k;

    dLitros = 0;

    iCanal = ((((BYTE)ucPacote[1])-49)*8);
    iInd = ucPacote[3] & 0x0F;

    switch(iInd)
    {
    case 0:
    iCanal += ((((BYTE)ucPacote[4])-47)+100);
    printf("Bomba %i ligada\n",iCanal-100);
    break;
    case 1:
    iCanal += ((((BYTE)ucPacote[4])-47)+100);
    printf("Bomba %i desligada\n",iCanal-100);

    dPulsos = 0;
    k=0;
    ZeroMemory(cPulsos,8);
    for (int i=5;i<13;i++)
    {
    cPulsos[k] = ucPacote[i];
    k++;
    }
    dPulsos = atof(cPulsos);

    dLitros = round(dPulsos/1*100)/100;

    if ((iCanal > 100) && (iCanal < 133))
    {
    printf("Bomba %i abasteceu %4.2f litros \n",iCanal-100, dLitros);
    }
    else
    printf("Bomba %i abasteceu %4.2f litros \n",iCanal-100, 0.00);

    break;
    case 7:
    printf("APM Reenergizado\n");
    break;
    }

    }

    DWORD IGerenciadorEquipamento::ExtraiCMD(unsigned char ucPacoteIN,
    DWORD dStartpos,
    DWORD dQtdebytes,
    unsigned char
    ucPacoteOUT)
    {
    int i;
    DWORD dPosETX = 0;
    DWORD dPosSTX = 0;
    DWORD dPosDC2 = 0;
    bool bOneMoreSYN;
    bool bMensTexto;
    bool bContinuar = true;
    DWORD dBytesToSYN;
    int iTotalBytes;

    iTotalBytes = 0;
    dBytesToSYN = 0;
    bMensTexto = false;
    bOneMoreSYN = true;
    dPosETX = 0;
    dPosSTX = 0;
    dPosDC2 = 0;

    for(i=dQtdebytes-1;(i>=0);i--)
    {

    if (bOneMoreSYN)
    dBytesToSYN++;

    switch(ucPacoteIN[i])
    {
    case SYN:
    if ((dPosETX) && (dPosSTX) && ((dPosSTX-i) == 2) && (dQtdebytes
    > dPosETX))
    {
    bMensTexto = true;
    bContinuar = false;
    break;
    }
    else
    {
    if ((dPosDC2) && (dPosDC2-i) == 2)
    {
    if ((!bOneMoreSYN) && (dBytesToSYN > 0))
    {
    return iTotalBytes;
    }
    else
    {
    bContinuar = false;
    break;
    }
    }
    else
    {
    if (!bOneMoreSYN) { return 0; }
    bOneMoreSYN = false;
    dPosDC2 = 0;
    dPosETX = 0;
    dPosSTX = 0;
    }

    }
    break;

    case DC2: dPosDC2 = i; break;
    case STX: dPosSTX = i; break;
    case ETX: dPosETX = i; break;
    }
    if (!bContinuar) break;

    }

    if ((i != 0xFFFF) && (ucPacoteIN[i] == SYN))
    {
    if (bMensTexto)
    dPosETX++;
    else
    dPosETX = dPosDC2;

    for(int j=i;j<=dPosETX;j++)
    {
    ucPacoteOUT[iTotalBytes] = ucPacoteIN[j];
    iTotalBytes++;
    }
    }
    return iTotalBytes;
    }

    IGerenciadorEquipamento::IGerenciadorEquipamento(char *mcPortaSerial,
    DWORD mdwBaudRate,
    BYTE mbyByteSize,
    BYTE mbyTipoParidade)
    {
    cPortaSerial = mcPortaSerial;
    dwBaudRate = mdwBaudRate;
    mbyTipoParidade = mbyTipoParidade;
    mbyByteSize = mbyByteSize;
    hSerial = INVALID_HANDLE_VALUE;
    conectado = false;
    bRX_In_Progress = false;
    bTX_In_Progress = false;
    ConfControl.detectaprot = true;
    ConfControl.tentativas = 0;
    ConfControl.controladora = 0;

    }

    IGerenciadorEquipamento::~IGerenciadorEquipamento()
    {
    conectado = false;
    cPortaSerial = "";
    dwBaudRate = 0;
    byTipoParidade = SERIAL_PARITY_NONE;
    byByteSize = 0;

    if (GetThreadHND()!=0)
    WaitForSingleObject(GetThreadHND(), 2000);

    bRX_In_Progress = false;
    bTX_In_Progress = false;

    if (hSerial != INVALID_HANDLE_VALUE)
    CloseHandle(hSerial);
    hSerial = INVALID_HANDLE_VALUE;
    }

    int IGerenciadorEquipamento::ConfigTimeouts(COMMTIMEOUTS mCommtimeout)
    {

    // configura os timeouts da Porta Serial
    mCommtimeout.ReadIntervalTimeout = 20;
    mCommtimeout.ReadTotalTimeoutMultiplier = 1;
    mCommtimeout.ReadTotalTimeoutConstant = 20;
    mCommtimeout.WriteTotalTimeoutMultiplier = 5;
    mCommtimeout.WriteTotalTimeoutConstant = 5;

    return SetCommTimeouts(hSerial,&mCommtimeout);
    }

    int IGerenciadorEquipamento::ConfigDCB(DCB mDCB)
    {
    // recupera as informações do DCB
    if (!GetCommState(hSerial,&mDCB))
    {
    CloseHandle(hSerial);
    return ERROR_INVALID_HANDLE;
    }

    // set DCB to configure the serial port
    mDCB.DCBlength = sizeof(mDCB);

    /* ---------- Serial Port Config ------- */
    mDCB.BaudRate = dwBaudRate;

    switch(byTipoParidade)
    {
    case SERIAL_PARITY_NONE:
    mDCB.Parity = NOPARITY;
    mDCB.fParity = 0;
    break;
    case SERIAL_PARITY_EVEN:
    mDCB.Parity = EVENPARITY;
    mDCB.fParity = 1;
    break;
    case SERIAL_PARITY_ODD:
    mDCB.Parity = ODDPARITY;
    mDCB.fParity = 1;
    break;
    }

    mDCB.StopBits = ONESTOPBIT;
    mDCB.ByteSize = 8;
    mDCB.fBinary = 0;
    mDCB.fAbortOnError = 0;
    mDCB.wReserved = 0;
    mDCB.XonLim = 100;
    mDCB.XoffLim = 100;
    mDCB.XonChar = 0x0D;
    mDCB.XoffChar = 0x0A;
    mDCB.ErrorChar = 0;
    mDCB.EofChar = 0;
    mDCB.EvtChar = 0;
    mDCB.wReserved1 = 0;

    return SetCommState(hSerial,&mDCB);

    }

    int IGerenciadorEquipamento::AtivaEquipamento(BOOL mbIniciaThread)
    {
    int iErro;
    DCB dcb;
    int i;

    COMMTIMEOUTS cto;

    if (hSerial != INVALID_HANDLE_VALUE)
    CloseHandle(hSerial);
    hSerial = INVALID_HANDLE_VALUE;

    if (cPortaSerial != "")
    {
    iErro = 0;

    hSerial = CreateFile(cPortaSerial, // filename
    GENERIC_READ | GENERIC_WRITE, // acesso
    desejado
    0, // modo de
    compartilhamento
    NULL, // atributos
    de segurança
    OPEN_EXISTING, // disposição
    da criação do arquivo
    FILE_FLAG_NO_BUFFERING,
    // flag de criação
    NULL); // indica se
    pode ou não copiar os
    // atributos do
    arquivo atual para outro
    // arquivo
    if (hSerial != INVALID_HANDLE_VALUE)
    {
    bConectado = true;

    // aplica os timeous
    if (!ConfigTimeouts(cto))
    iErro = 2;

    // aplica o DCB
    if (!ConfigDCB(dcb))
    iErro = 4;

    }
    }
    else
    iErro = -2;

    /* --------------------------------------------- */
    if (iErro > 0)
    {
    CloseHandle(hSerial);
    hSerial = INVALID_HANDLE_VALUE;
    }
    else
    {

    HANDLE hThread1;
    DWORD dThreadID1;
    if(mbIniciaThread)
    {
    printf("Connected ! \n");

    hThread1 = CreateThread(NULL, // default
    security attributes
    0, // use default
    stack size
    (DWORD (_stdcall *)(void ))ComSendRecv,
    // thread function
    (void
    )this, // argument to thread
    function
    0, // use default
    creation flags
    &dThreadID1); // returns the
    thread identifier

    */

    }
    }

    /* --------------------------------------------- */
    return iErro;

    }

    int IGerenciadorEquipamento::DesativaEquipamento(BOOL mbFinalizaThread)
    {
    conectado = false;

    if(mbFinalizaThread)
    {

    }
    if (hSerial != INVALID_HANDLE_VALUE)
    CloseHandle(hSerial);
    hSerial = INVALID_HANDLE_VALUE;

    if (this->GetThreadHND())
    {
    if (WaitForSingleObject (this->GetThreadHND(), 2000) == WAIT_TIMEOUT)
    {
    TerminateThread (this->GetThreadHND(), 1);
    CloseHandle (this->GetThreadHND());
    }
    else CloseHandle (this->GetThreadHND());
    }
    CloseHandle(this->GetThreadHND());

    printf("Disconnected ! \n");

    }

    int IGerenciadorEquipamento::EscreveMensagem(HANDLE hSerialCOM,unsigned
    char* mcMensagem, int miTamanho)

    {
    char cTXBuffer[SERIAL_MAX_RX];
    DWORD iQtdebytesEscritos;
    int iTamanhoBuffer = 0;
    int iSuccess = 0;
    int Error = 0;
    HANDLE hCom;

    if (!bTX_In_Progress)
    {
    PurgeComm(hSerialCOM,PURGE_TXCLEAR | PURGE_RXCLEAR);
    //hCom = hSerialCOM;

    iSuccess = WriteFile(hSerialCOM,
    mcMensagem,
    miTamanho,
    &iQtdebytesEscritos,
    NULL);

    if (!iSuccess)
    {
    // failure
    if((Error = GetLastError()) != ERROR_IO_PENDING )
    printf("erro: %i , qtde: %i => WriteFile error (not pending)\
    n", Error,iQtdebytesEscritos & 0xFFFF);
    }

    bTX_In_Progress = false;

    }

    return iQtdebytesEscritos;
    }

    int IGerenciadorEquipamento::LeMensagem(HANDLE hSerialCOM,unsigned char*
    mcMensagem, int miTamanho)
    {
    DWORD iQtdebytesLidos;
    DWORD iLenMensagem = 0;
    int iSuccess = 0;
    int Error = 0;
    HANDLE hCom;

    ZeroMemory(mcMensagem,SERIAL_MAX_RX);

    if (!bRX_In_Progress)
    {
    // locking reading
    bRX_In_Progress = true;
    //hCom = hSerialCOM;

    // starting a new read
    iSuccess = ReadFile(hSerialCOM, // handle do arquivo
    mcMensagem, // buffer de leitura
    miTamanho, // número de bytes a serem lidos
    &iQtdebytesLidos, // número de bytes realmente
    lidos
    NULL); // usado para leitura
    concorrente
    // da serial

    if (!iSuccess)
    {
    // failure
    if((Error = GetLastError()) != ERROR_IO_PENDING)
    {
    printf("erro: %i , qtde: %i => Readfile error (not pending)\
    n", Error,iQtdebytesLidos & 0xFFFF);
    }
    }
    bRX_In_Progress = false;
    }

    return iQtdebytesLidos;
    }

    void IGerenciadorEquipamento::PurgeSerial(void)
    {
    PurgeComm(hSerial,PURGE_TXCLEAR | PURGE_RXCLEAR);
    }

    bool IGerenciadorEquipamento::VerificaEstado(void)
    {
    // return (bRX_In_Progress || bTX_In_Progress);
    }

    int ComSendRecv(LPVOID p)
    {
    IGerenciadorEquipamento* pIGE;

    pIGE = (IGerenciadorEquipamento*)p;

    if (pIGE !=0)
    return pIGE->Run();

    }

    BYTE CalculaCRC(unsigned char *msg, int qtdeBytes)
    {
    BYTE valor_crc = 0;

    for (int i=0; i<=qtdeBytes-1;i++)
    {
    valor_crc += msg[i];
    }
    return valor_crc;
    }

    int IGerenciadorEquipamento::Run(void)
    {
    bool bDone;
    unsigned char ucPacoteIN[256];
    unsigned char ucPacoteOUT[256];
    unsigned char ucPacoteCMD[256];
    int iRetry;
    BYTE byPacoteCRC, byPacoteCalcCRC;
    // char *lista[3];

    int iTotalLido = 0;
    int iTamPacoteCMD = 0;

    bDone = false;
    bRX_In_Progress = false;
    bTX_In_Progress = false;

    GetLastError(); // just to clear any pending error

    HANDLE hComm = hSerial;

    char cmd[5];

    while(!bDone)
    {

    Sleep(1000);

    if (ConfControl.detectaprot)
    EnviaPOLLING(hSerial);

    if (ConfControl.controladora)
    {
    iTotalLido = LeMensagem(hSerial ,pacoteOUT,30);
    if (iTotalLido)
    {
    ConcedePrivilegio(hSerial,ConfControl.controladora);
    ConfControl.tentativas = 5;
    }
    ConfControl.tentativas--;
    if (ConfControl.tentativas <= 0)
    {
    ConfControl.tentativas = 0;
    ConfControl.controladora = 0;
    }
    }

    ConcedePrivilegio(hSerial,0);

    iRetry = 1;

    while (iRetry >0)
    {

    iRetry--;

    iTotalLido = LeMensagem(hSerial,ucPacoteOUT,30);
    if (iTotalLido)
    {
    ZeroMemory(ucPacoteCMD,SERIAL_MAX_RX);

    iTamPacoteCMD = ExtraiCMD
    (ucPacoteOUT,1,iTotalLido,ucPacoteCMD);
    if (iTamPacoteCMD > 0)
    {

    ZeroMemory(ucPacoteIN,SERIAL_MAX_RX);

    switch(ucPacoteCMD[2])
    {
    case DC2:
    if (isdigit(ucPacoteCMD[1]))
    {
    iRetry = 1;
    ConcedePrivilegio(hSerial,((BYTE)ucPacoteCMD[1]
    -48));
    }
    break;

    case STX:
    byPacoteCalcCRC = CalculaCRC
    (ucPacoteCMD,iTamPacoteCMD-1);
    byPacoteCRC = (BYTE)ucPacoteCMD[iTamPacoteCMD-1];
    if (byPacoteCRC == byPacoteCalcCRC)
    {
    iRetry = 0;
    if (isdigit(ucPacoteCMD[1]))
    {

    ConfControl.controladora = (BYTE)(
    (ucPacoteCMD[1])- 48);
    ConfControl.tentativas = 5;
    ConcedePrivilegio(hSerial,((BYTE)ucPacoteCMD
    [1]-48));
    PurgeComm(hSerial, PURGE_RXCLEAR);
    }
    TraduzMens(ucPacoteCMD,iTamPacoteCMD);

    /* teste do comando pede abastecimento
    if (gets(cmd) != NULL)
    {
    y = dividePorCaractere(cmd," ",lista);

    if (y > 1)
    {
    if (strcmp(lista[0],"abast") == 0)
    {
    PedeAbastecimentoManual(atoi(lista[1])
    +100);
    }
    }
    if (strcmp(cmd,"quit") == 0)
    {
    break;
    }
    }
    */
    }
    break;
    }
    }
    }

    }

    }
    DesativaEquipamento(true);
    }

    /--------------------------------------------------------------------/
    /* until here */

    /* cut /
    /
    --------------------------------------------------------------------*/
    /* Main Exec Code */

    /***********************************************************************
    main.cpp - The main() routine for all the "Basic Winsock" suite of
    programs from the Winsock Programmer's FAQ. This function parses
    the command line, starts up Winsock, and calls an external function
    called DoWinsock to do the actual work.

    This program is hereby released into the public domain. There is
    ABSOLUTELY NO WARRANTY WHATSOEVER for this product. Caveat hacker.
    ***********************************************************************/

    #include "IThreadConnect.hpp"
    #include "IGerenciadorEquipamento.hpp"
    #include <windows.h>
    #include <vector>
    #include <algorithm>

    using namespace std;

    BOOL CtrlHandler(DWORD fdwCtrlType)
    {
    switch( fdwCtrlType )
    {
    // Handle the CTRL+C signal.
    case CTRL_C_EVENT:
    //printf( "Ctrl-C event\n\n" );
    Beep( 750, 300 );
    return( TRUE );

    // CTRL+CLOSE: confirm that the user wants to exit.
    case CTRL_CLOSE_EVENT:
    Beep( 600, 200 );
    //printf( "Ctrl-Close event\n\n" );
    return( TRUE );

    // Pass other signals to the next handler.
    case CTRL_BREAK_EVENT:
    Beep( 900, 200 );
    //printf( "Ctrl-Break event\n\n" );
    return FALSE;

    case CTRL_LOGOFF_EVENT:
    Beep( 1000, 200 );
    //printf( "Ctrl-Logoff event\n\n" );
    return FALSE;

    case CTRL_SHUTDOWN_EVENT:
    Beep( 750, 500 );
    //printf( "Ctrl-Shutdown event\n\n" );
    return FALSE;

    default:
    return FALSE;
    }
    system("PAUSE");
    }

    //// main //////////////////////////////////////////////////////////////
    int main(int argc, char* argv[])
    {
    IThreadConnect threadConnect(0);
    IGerenciadorEquipamento gerente1("COM1", 9600, 8, SERIAL_PARITY_NONE);
    // IGerenciadorEquipamento gerente2("COM3", 9600, 8, SERIAL_PARITY_NONE);
    // IGerenciadorEquipamento gerente3("COM3", 9600, 8, SERIAL_PARITY_NONE);

    vector<IGerenciadorEquipamento> vEquipamento;

    if( SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE))
    {

    gerente1.AtivaEquipamento();
    printf("1 - Connected ! \n");

    }
    else
    printf( "\nERROR: Could not set control handler");
    //system("PAUSE");

    // exit(1);
    }

    /--------------------------------------------------------------------/
    /* until here */

    villen Dank,
    Berti


Anmelden zum Antworten