/*++ Copyright (c) 1996 Microsoft Corporation Module Name: modem.c Abstract: This module provides access to modems. Author: Wesley Witt (wesw) 22-Jan-1996 Revision History: --*/ BOOL SendModemCommand( HANDLE hFile, LPOVERLAPPED OverlappedWrite, LPSTR Command ) /*++ Routine Description: Sends an AT command to the modem. Arguments: hFile - File handle for the comm port. Command - AT Command Return Value: TRUE if the command is sent, FALSE otherwise --*/ { DWORD Bytes; DWORD ec; if (!WriteFile( hFile, Command, strlen(Command), &Bytes, OverlappedWrite )) { // // the write failed // ec = GetLastError(); if (ec == ERROR_IO_PENDING) { if (WaitForSingleObject( OverlappedWrite->hEvent, 10000 ) == WAIT_TIMEOUT) { // // write never completed // return FALSE; } if (!GetOverlappedResult( hFile, OverlappedWrite, &Bytes, FALSE )) { // // the write failed // return FALSE; } } else { return FALSE; } } return TRUE; } BOOL ReceiveModemResponse( HANDLE hFile, LPOVERLAPPED OverlappedRead, LPSTR Response, DWORD ResponseSize ) /*++ Routine Description: Receives a response from a modem. Arguments: hFile - File handle for the comm port. Response - Buffer to put the response into ResponseSize - Size of the response buffer Return Value: TRUE if the response is received, FALSE otherwise --*/ { DWORD Bytes; DWORD ec; if (!ReadFile( hFile, Response, ResponseSize, &Bytes, OverlappedRead )) { // // the read failed // ec = GetLastError(); if (ec == ERROR_IO_PENDING) { if (WaitForSingleObject( OverlappedRead->hEvent, 10000 ) == WAIT_TIMEOUT) { // // write never completed // return FALSE; } if (!GetOverlappedResult( hFile, OverlappedRead, &Bytes, FALSE )) { // // the write failed // return FALSE; } } else { return FALSE; } } Response[Bytes] = 0; // { // LPTSTR ResponseW = AnsiStringToUnicodeString( Response ); // DebugPrint(( TEXT("bytes=%d, [%s]"), Bytes, ResponseW )); // MemFree( ResponseW ); // } return TRUE; } BOOL IsResponseOk( LPSTR Response ) /*++ Routine Description: Verifies that a modem response is positive, that it contains the string "OK" Arguments: Response - Modem response Return Value: TRUE if the response is positive, FALSE otherwise --*/ { Response = strchr( Response, 'O' ); if (Response && Response[1] == 'K') { return TRUE; } return FALSE; } DWORD GetModemClass( HANDLE hFile ) /*++ Routine Description: Determines the lowest FAX class that the modem connected to the requested port supports. Arguments: PortName - Communications port name. Return Value: Class number. --*/ { DWORD ModemClass = 0; DCB Dcb; CHAR Response[64]; COMMTIMEOUTS cto; OVERLAPPED OverlappedRead; OVERLAPPED OverlappedWrite; ZeroMemory( &OverlappedRead, sizeof(OVERLAPPED) ); ZeroMemory( &OverlappedWrite, sizeof(OVERLAPPED) ); OverlappedRead.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); OverlappedWrite.hEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); if (!GetCommState( hFile, &Dcb )) { goto exit; } Dcb.BaudRate = CBR_2400; Dcb.fDtrControl = DTR_CONTROL_ENABLE; Dcb.fRtsControl = RTS_CONTROL_ENABLE; if (!SetCommState( hFile, &Dcb )) { goto exit; } cto.ReadIntervalTimeout = 1000; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 4 * 1000; cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 4 * 1000; SetCommTimeouts( hFile, &cto ); // // reset the modem // if (!SendModemCommand( hFile, &OverlappedWrite, "ATZ0\r" )) { goto exit; } if (!ReceiveModemResponse( hFile, &OverlappedRead, Response, sizeof(Response) )) { goto exit; } // // turn off echo // if (!SendModemCommand( hFile, &OverlappedWrite, "ATE0\r" )) { goto exit; } if (!ReceiveModemResponse( hFile, &OverlappedRead, Response, sizeof(Response) )) { goto exit; } // // H0 - go on hook // Q0 - enable modem responses // V1 - verbal modem responses (ok, error, etc) // if (!SendModemCommand( hFile, &OverlappedWrite, "ATH0Q0V1\r" )) { goto exit; } if (!ReceiveModemResponse( hFile, &OverlappedRead, Response, sizeof(Response) )) { goto exit; } if (!IsResponseOk( Response )) { goto exit; } if (!SendModemCommand( hFile, &OverlappedWrite, "AT+FCLASS=?\r" )) { goto exit; } if (!ReceiveModemResponse( hFile, &OverlappedRead, Response, sizeof(Response) )) { goto exit; } if (!IsResponseOk( Response )) { DebugPrint(( TEXT("bad modem response #2 [%s]"), Response )); goto exit; } if (strchr( Response, '1' )) { ModemClass = 1; } else if (strchr( Response, '2' )) { ModemClass = 2; } if (!SendModemCommand( hFile, &OverlappedWrite, "AT+FAE=1\r" )) { goto exit; } if (!ReceiveModemResponse( hFile, &OverlappedRead, Response, sizeof(Response) )) { goto exit; } exit: CloseHandle( OverlappedRead.hEvent ); CloseHandle( OverlappedWrite.hEvent ); if (ModemClass == 0) { DebugPrint(( TEXT("Could not detect modem class") )); } return ModemClass; }