Modem_init or Comm*

From
Henry Tabunkin (2:5054/39)
To
Timur Shemsedinov
Date
2002-05-05T04:06:26Z
Area
SU.WINDOWS.NT.PROG
Приветствую вас уважаемый(-ая)(-ое), Timur!

Как-то 23 Apr 02 в аккурат в 21:55, некто Timur Shemsedinov отписал к All на вот такую занятную тему как "Modem_init or Comm*":

 TS> Киньте, если имеете, пpимеpчик инициализации модема, желательно чеpез,
 TS> WinApi т.е. CreateFile, Comm* На асме я когда-то пpогpаммиpовал
 TS> микpосхему чеpез поpты, но тут же ж под NT по pучкам надают, так что
 TS> интеpесует как установить: - скоpость обмена - четность - битов в
 TS> байте - стоповых битов А вообще будет великолепно, если есть пpимеp с
 TS> CreateEvent для чтения данных с поpта в отдельном тpеде, посаженном на
 TS> событие. Если я пpавильно понял, как это в винде культуpно делать?
Есть паpа соpцов.
1. За 100% pаботоспособность пеpвого файла не pучаюсь, ибо его _желательно_
   попpавить под свои нужды, но общее напpавление там достаточно веpное.
   (Я его как-то пользовал как "темплейт")
2. Вопpосы к автоpу исходного письма (а шапке)

№1.

=== Cut ===
// Open_Comport
// -------------
// Opens a communications port for use.
//
// Returns:   Handle number if successful, else 0
//
// Comport  = Communications port to open (ie. 1, 2, 3, 4, ... 255)
// BaudRate = Desired baud rate (ie, 110, 300, 600, 1200, 2400, 4800, 9600,
19200, ...)
//
HANDLE Open_Comport (DWORD Comport, DWORD BaudRate)
{
    HANDLE  DriverHandle;
    char    Com_Name[10];
    DWORD   DCB_Baud_Rate;
    DCB     Our_DCB;

    //
    // Range check the Comport number
    //

    if (Comport > 255) {
        return INVALID_HANDLE_VALUE;
    }

    //
    // Make a COMPORT name from a number
    //

    sprintf(Com_Name, "COM%i", Comport);

    //
    // Convert the Baud Rate to the Com library define for the DCB
    //
    switch (BaudRate) {
        case 110:
            DCB_Baud_Rate = 110;
            break;
        case 300:
            DCB_Baud_Rate = CBR_300;
            break;
        case 600:
            DCB_Baud_Rate = CBR_600;
            break;
        case 1200:
            DCB_Baud_Rate = CBR_1200;
            break;
        case 2400:
            DCB_Baud_Rate = CBR_2400;
            break;
        case 4700:
            DCB_Baud_Rate = CBR_4800;
            break;
        case 9600:
            DCB_Baud_Rate = CBR_9600;
            break;
        case 19200:
            DCB_Baud_Rate = CBR_19200;
            break;
        case 38400:
            DCB_Baud_Rate = CBR_38400;
            break;
        case 57600:
            DCB_Baud_Rate = CBR_57600;
            break;
        case 115200:
            DCB_Baud_Rate = CBR_115200;
            break;
        default:
            return INVALID_HANDLE_VALUE;
    }

    //
    // Open a channel to the Comport - This example DOES NOT use overlapped
I/O
    // Since the benefits of overlapped I/O are few, we suggest not using
it.
    //
    DriverHandle = CreateFile (Com_Name, GENERIC_READ | GENERIC_WRITE,
                               0, NULL, OPEN_EXISTING, 0, NULL);

    //
    // Do we have a valid handle? (If not, the driver probably isn't loaded)
    //

    if (DriverHandle == INVALID_HANDLE_VALUE) {
        return (DriverHandle);
    } else {
        //
        // The SetupComm() function establishes the Transmit and Receive
        // buffer sizes.
        //
 SetupComm (DriverHandle, 1024, 1024);

        //
        // Obtain the current DCB structure. this can be saved away for
restore after
        // the application is done using the Comport
        //
        GetCommState (DriverHandle, &Our_DCB);

        //
        // Fill in the DCB structure with our own settings.
        //
        Our_DCB.BaudRate = DCB_Baud_Rate;
        Our_DCB.fParity = 0;
        Our_DCB.fOutxCtsFlow = 0;
        Our_DCB.fOutxDsrFlow = 0;
        Our_DCB.fDtrControl = DTR_CONTROL_ENABLE;
        Our_DCB.fDsrSensitivity = FALSE;
        Our_DCB.fTXContinueOnXoff = 0;
        Our_DCB.fOutX = 0;
        Our_DCB.fInX = 0;
        Our_DCB.fErrorChar = 0;
        Our_DCB.fNull = 0;
        Our_DCB.fRtsControl = RTS_CONTROL_DISABLE;
        Our_DCB.fAbortOnError = 0;
        Our_DCB.ByteSize = 8;
        Our_DCB.Parity = NOPARITY;
        Our_DCB.StopBits = ONESTOPBIT;

        //
        // Configure the comport with our new DCB
        //
        SetCommState (DriverHandle, &Our_DCB);

        //
        // Setup a mask that allows us to tell if the port is done
transmitting
        // the current buffer of data
        //
        SetCommMask (DriverHandle, EV_TXEMPTY);
    }

    return DriverHandle;
}

// Close_Comport
// -------------
// Closes a communications port previously opened
// Returns:   TRUE on success, FALSE on failure
// DriverHandle = Handle returned on Open_Comport() call
int Close_Comport (HANDLE DriverHandle)
{
    //
    // Sanity check on the Handle
    //
    if ((DriverHandle == 0) || (DriverHandle == INVALID_HANDLE_VALUE)) {
        return FALSE;
    }

    //
    // Close the communications port
    //
    CloseHandle (DriverHandle);

    return TRUE;
}


//
// Write_Comport
// -------------
// Writes a buffer of data out the RS232 commmunications port
//
// Returns:   TRUE on success, FALSE on failure
//
// DriverHandle = Handle returned on Open_RS232() call
// NumBytes     = Number of bytes to send
// Buffer       = Buffer of data to send
int Write_Comport (HANDLE DriverHandle, DWORD NumBytes, void *Buffer)
{
    DWORD BytesWritten;
//    DWORD EvtMask;
//    BOOL status;

    //
    // Sanity check on the Handle
    //
    if ((DriverHandle == 0) || (DriverHandle == INVALID_HANDLE_VALUE)) {
        return FALSE;
    }

    //
    // Some devices may require setting RTS or DTR to specific states prior
to
    // tranmission of data
    //
    EscapeCommFunction (DriverHandle, SETRTS);

    //
    // Output the data to the Comport
    //
//    status = WriteFile (DriverHandle, Buffer, NumBytes, &BytesWritten, 0);
    WriteFile (DriverHandle, Buffer, NumBytes, &BytesWritten, 0);

    //
    // If you want, use the WaitCommEvent() function to wait for the
    // data Transmission to complete
    //
   //    WaitCommEvent(DriverHandle, &EvtMask, NULL);

    //
    // Some devices may require clearing RTS or DTR to after transmission of
data
    //
    EscapeCommFunction (DriverHandle, CLRRTS);

    return TRUE;
}

//
// Read_Comport
// -------------
// Reads data received on the RS232 communications port
//
// Returns:   TRUE on success, FALSE on failure
//
// DriverHandle = Handle returned on Open_RS232() call
// BytesRead    = Number of bytes read by the ReadFile() function
// BufferSize   = Size of Buffer in bytes
// Buffer       = Data buffer that holds received data
//
int Read_Comport (HANDLE DriverHandle, DWORD *BytesRead, DWORD BufferSize,
void *Buffer)
{
    COMSTAT     Our_Comstat;
    DWORD       Com_Errors, BytesToRead;

    //
    // Sanity check on the Handle
    //
    if ((DriverHandle == 0) || (DriverHandle == INVALID_HANDLE_VALUE)) {
        return FALSE;
    }

    //
    // By far the most efficient way to input Comport data is the following:
    // ---------------------------------------------------------------------
    // A) See how much data is present
    // B) Read exactly that amount of data
    //
    // Note: It is possible to ask for more data than is present, but the
ReadFile()
    //       function call will not return until that amount of data has
been received.
    //       Some programs will request more data and establish a timeout
using the
    //       SetCommTimeouts() function to return from the ReadFile()
function when
    //       not enough data has been receive. Although this may work, it is
inefficient
    //       and generally works like crap. For everyone's sake, use the
technique above
    //       and handle your own timeout in applications code.

    //
    // Check the Input buffer
    //
    ClearCommError (DriverHandle, &Com_Errors, &Our_Comstat);

    //
    // ReadFile() only if there is data.
    //
    if (Our_Comstat.cbInQue > 0) {

        //
        // Make sure we do not overrun the Buffer
        //
        if (Our_Comstat.cbInQue > BufferSize) {
            BytesToRead = BufferSize;
        } else {
            BytesToRead = Our_Comstat.cbInQue;
        }
        //
        // Read the data, no (NULL) Overlapped I/O
        //
        ReadFile(DriverHandle, Buffer, BytesToRead, BytesRead, NULL);

    } else {
        *BytesRead = 0;
    }

    return TRUE;
}
=== Cut ===

№2.
=== Cut ===
═ RU.VISUAL.CPP (2:5054/45.7) ═════════════════════════════════ RU.VISUAL.CPP ═
 Msg  : 487 of 861 -476 +516
 From : Dmitry A. Semenets                  2:5020/400      17 Jan 01  12:40:09
 To   : All                                                 18 Jan 01  07:11:09
 Subj : Re: команды модему
═══════════════════════════════════════════════════════════════════════════════
From: "Dmitry A. Semenets" <alta@atm-lan.com.ua>

> Написал как-то Dmitry A. Semenets к All следующие строки:
>  >> Необходимо используя API функции работы с портами посылать команды
>  >> модему типа ATZ|и в таком роде. Куда копать?
>  DS> Посылать прямо в порт соответсвующую комманду прямо в чистом виде,
>  DS> ждать ответа (OK).
> Вот именно это меня и интересует.Если нетрудно пару строк кода.
> Я пробавал CreateFile...WriteFile.
В принципе - правильно. Но настаивать параметры порта тоже нужно. Попробуй
следующий код.
================= CUT ======================
// Opening Comm Port
// Используется асинхронный ввод/вывод
    hFile=CreateFile("COM2", GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {
        Report("CreateFile");
        return 1;
    };
    DCB dcb;
    char buffer[70];
// Set Comm port params
// Получаем оригинальные параметры.
    if (!GetCommState(hFile, &dcb))
    {
        nRetCode=1;
        Report("GetCommState");
        goto exit_app;
    };
// Здесь настраиваем свои параметры. Остальные остаются оригинальными.
    if (!BuildCommDCB("baud=19200 parity=N data=8 stop=1", &dcb))
    {
        nRetCode=1;
        Report("BuildCommDCB");
        goto exit_app;
    };
    if (!SetCommState(hFile, &dcb))
    {
        nRetCode=1;
        Report("SetCommState");
        goto exit_app;
    };
=============== end CUT =================
функция Report выводит информацию об ошибке. Далее как обычно WriteFile,
ReadFile.
Может быть в конце каждой комманды нужно ставить конец строки.


-+- ifmail v.2.15dev5
 + Origin: Svit Online (post does not reflect views of Golden Tele (2:5020/400)

=== Cut ===

                       До следующего коннекта!
                                    the Hunter.

                               [39 кошек] [HoM&M]  [Metal Music] [No Smoking]
--- Not yet implemented
 * Origin: -=<{\/\_ Видеть звуки... слышать звезды... _/\/}>=- (2:5054/39)