/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ #pragma off (unreferenced) static char rcsid[] = "$Id: comm.c,v 1.1.1.1 2006/03/17 20:00:43 zicodxx Exp $"; #pragma on (unreferenced) #define WIN32_LEAN_AND_MEAN #define WIN95 #define _WIN32 #include #include #include #include #include "mono.h" #include "winapp.h" #include "comm.h" #include "error.h" #define ASCII_XON 0x11 #define ASCII_XOFF 0x13 #define MODEM_REGISTRY_PATH "System\\CurrentControlSet\\Services\\Class\\Modem" static long comm_delay_val = 0; DWORD FAR PASCAL comm_thread_proc(LPSTR lpdata); int FAR PASCAL comm_idle_function(COMM_OBJ *obj); void comm_dump_info(COMM_OBJ *obj); // --------------------------------------------------------------------- int comm_get_modem_info(int modem, COMM_OBJ *obj) { HKEY hKey, hSubKey; char path[256]; char buf[32]; DWORD len, err, type; memset(obj, 0, sizeof(COMM_OBJ)); obj->connect = FALSE; if (modem < 0) { // Direct Link obj->type = 0; obj->port = (char)(modem * -1); return 1; } else obj->type = 1; sprintf(buf, "\\%04d", modem); strcpy(path, MODEM_REGISTRY_PATH); strcat(path, buf); mprintf((0, "Looking for modem in HKEY_LOCAL_MACHINE\\%s\n", path)); err = RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_READ, &hKey); if (err != ERROR_SUCCESS) return 0; // We have a key into the modem 000x // Retreive all pertinant info. len = sizeof(buf); err = RegQueryValueEx(hKey, "Model", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } strcpy(obj->name, buf); len = sizeof(buf); err = RegQueryValueEx(hKey, "PortSubClass", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } mprintf((0, "COM:%d\n", buf[0])); obj->port = buf[0]; len = sizeof(buf); err = RegQueryValueEx(hKey, "Reset", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } strcpy(obj->cmd[COMM_RESET_CMD], buf); // Retreive some settings stuff err = RegOpenKeyEx(hKey, "Answer", 0, KEY_READ, &hSubKey); if (err !=ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } len = sizeof(buf); err = RegQueryValueEx(hSubKey, "1", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hSubKey); RegCloseKey(hKey); return 0; } strcpy(obj->cmd[COMM_ANSWER_CMD], buf); RegCloseKey(hSubKey); err = RegOpenKeyEx(hKey, "Hangup", 0, KEY_READ, &hSubKey); if (err !=ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } len = sizeof(buf); err = RegQueryValueEx(hSubKey, "1", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hSubKey); RegCloseKey(hKey); return 0; } strcpy(obj->cmd[COMM_HANGUP_CMD], buf); RegCloseKey(hSubKey); err = RegOpenKeyEx(hKey, "Settings", 0, KEY_READ, &hSubKey); if (err !=ERROR_SUCCESS) { RegCloseKey(hKey); return 0; } len = sizeof(buf); err = RegQueryValueEx(hSubKey, "DialPrefix", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hSubKey); RegCloseKey(hKey); return 0; } strcpy(obj->cmd[COMM_DIALPREF_CMD], buf); len = sizeof(buf); err = RegQueryValueEx(hSubKey, "Tone", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hSubKey); RegCloseKey(hKey); return 0; } strcat(obj->cmd[COMM_DIALPREF_CMD], buf); len = sizeof(buf); err = RegQueryValueEx(hSubKey, "Prefix", 0, &type, buf, &len); if (err != ERROR_SUCCESS) { RegCloseKey(hSubKey); RegCloseKey(hKey); return 0; } strcpy(obj->cmd[COMM_PREFIX_CMD], buf); RegCloseKey(hSubKey); RegCloseKey(hKey); comm_dump_info(obj); return 1; } // int comm_open_connection(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_open_connection(COMM_OBJ *obj) { char filename[16]; COMMTIMEOUTS ctimeouts; sprintf(filename, "COM%d", obj->port); obj->handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (obj->handle == INVALID_HANDLE_VALUE) return 0; // Modem COMport is open. SetCommMask(obj->handle, EV_RXCHAR); SetupComm(obj->handle, 4096, 4096); PurgeComm( obj->handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ; // Timeout after 10 sec. ctimeouts.ReadIntervalTimeout = 0xffffffff; ctimeouts.ReadTotalTimeoutMultiplier = 0; ctimeouts.ReadTotalTimeoutConstant = 10000; ctimeouts.WriteTotalTimeoutMultiplier = 0; ctimeouts.WriteTotalTimeoutConstant = 10000; SetCommTimeouts(obj->handle, &ctimeouts); memset(&obj->rov, 0, sizeof(OVERLAPPED)); memset(&obj->wov, 0, sizeof(OVERLAPPED)); obj->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (obj->rov.hEvent == NULL) { mprintf((0, "COMM: Unable to create read event.\n")); CloseHandle(obj->handle); return 0; } obj->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (obj->wov.hEvent == NULL) { mprintf((0, "COMM: Unable to create write event.\n")); CloseHandle(obj->rov.hEvent); CloseHandle(obj->handle); return 0; } // Setup parameters for Connection // 38400 8N1 obj->dcb.DCBlength = sizeof(DCB); GetCommState(obj->handle, &obj->dcb); if (obj->baud) obj->dcb.BaudRate = obj->baud; else obj->baud = obj->dcb.BaudRate; mprintf((0, "COM%d (%d) is opened.\n", obj->port, obj->baud)); obj->dcb.fBinary = 1; obj->dcb.Parity = NOPARITY; obj->dcb.fNull = 0; obj->dcb.XonChar = ASCII_XON; obj->dcb.XoffChar = ASCII_XOFF; obj->dcb.XonLim = 1024; obj->dcb.XoffLim = 1024; obj->dcb.EofChar = 0; obj->dcb.EvtChar = 0; obj->dcb.fDtrControl = DTR_CONTROL_ENABLE;// dtr=on obj->dcb.fRtsControl = RTS_CONTROL_ENABLE; obj->dcb.ByteSize = 8; obj->dcb.StopBits = ONESTOPBIT; obj->dcb.fParity = FALSE; obj->dcb.fOutxDsrFlow = FALSE; obj->dcb.fOutxCtsFlow = FALSE; // rts/cts off // obj->dcb.fInX = obj->dcb.fOutX = 1; // Software flow control XON/XOFF if (SetCommState(obj->handle, &obj->dcb) == TRUE) { obj->hThread = NULL; obj->threadID = (DWORD)(-1); // Send DTR EscapeCommFunction(obj->handle, SETDTR); obj->connect = TRUE; } else { mprintf((1, "COMM: Unable to set CommState: (%x)\n", GetLastError())); obj->hThread = NULL; obj->threadID = (DWORD)(-1); obj->connect = FALSE; // CloseHandle(obj->wov.hEvent); // CloseHandle(obj->rov.hEvent); CloseHandle(obj->handle); return 0; } return 1; } // int comm_close_connection(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_close_connection(COMM_OBJ *obj) { CloseHandle(obj->wov.hEvent); CloseHandle(obj->rov.hEvent); SetCommMask(obj->handle, 0); EscapeCommFunction(obj->handle, CLRDTR); PurgeComm( obj->handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ; CloseHandle(obj->handle); obj->connect = FALSE; obj->handle = NULL; mprintf((0, "COM%d closed.\n", obj->port)); return 1; } // int comm_read_char(COMM_OBJ *obj); // ---------------------------------------------------------------------------- #define ROTBUF_SIZE 16 static char rotbuf[ROTBUF_SIZE]; static int rotbuf_cur=0, rotbuf_tail=0; int comm_read_char(COMM_OBJ *obj) { DWORD errflags, result; COMSTAT comstat; DWORD length, length_to_read; if (!obj->connect) return COMM_BUF_EMPTY; // Do read buffer stuff if (rotbuf_cur < rotbuf_tail) { return (int)rotbuf[rotbuf_cur++]; } // Now if we have a condition of cur = tail, then the buffer is empty // and we have to refill it. ClearCommError(obj->handle, &errflags, &comstat); if (comstat.cbInQue > 0) { if (comstat.cbInQue < ROTBUF_SIZE) length_to_read = comstat.cbInQue; else length_to_read = ROTBUF_SIZE; result = ReadFile(obj->handle, rotbuf, length_to_read, &length, &obj->rov); if (result == 0) { if ((errflags = GetLastError()) != ERROR_IO_PENDING) { mprintf((1, "CommReadChar err: %X\n", errflags)); ClearCommError(obj->handle, &errflags, &comstat); } else { while (!GetOverlappedResult(obj->handle, &obj->rov, &length, TRUE)) { errflags = GetLastError(); if (errflags == ERROR_IO_INCOMPLETE) { continue; } else { mprintf((1, "GetOverlappedResult error: %d.\n", errflags)); rotbuf_cur = rotbuf_tail; return COMM_BUF_EMPTY; } } } } rotbuf_cur = 0; Assert(length <= ROTBUF_SIZE); rotbuf_tail = length; return (int)rotbuf[rotbuf_cur++]; } else return COMM_BUF_EMPTY; } // int comm_read_char_timed(COMM_OBJ *obj, int msecs); // ---------------------------------------------------------------------------- int comm_read_char_timed(COMM_OBJ *obj, int msecs) { DWORD err; COMSTAT cstat; int status; long timeout = timeGetTime() + (long)msecs; ClearCommError(obj->handle, &err, &cstat); while (cstat.cbInQue == 0) { status = comm_idle_function(obj); if (!status) return -1; ClearCommError(obj->handle, &err, &cstat); if (timeout <= timeGetTime()) return -1; } return comm_read_char(obj); } // int comm_write_char(COMM_OBJ *obj, int ch); // ---------------------------------------------------------------------------- int comm_write_char(COMM_OBJ *obj, int ch) { DWORD errflags; DWORD length; COMSTAT comstat; char c; if (!obj->connect) return 0; c = (char)ch; // mprintf((0, "%c", c)); if (!WriteFile(obj->handle, &c, 1, &length, &obj->wov)) { if (GetLastError() == ERROR_IO_PENDING) { while (!GetOverlappedResult(obj->handle, &obj->wov, &length, TRUE)) { errflags = GetLastError(); if (errflags == ERROR_IO_INCOMPLETE) continue; else { ClearCommError(obj->handle, &errflags, &comstat); mprintf((1, "Comm: Write error!\n")); return 0; } } } else { ClearCommError(obj->handle, &errflags, &comstat); mprintf((1, "Comm: Write error!\n")); return 0; } } //mprintf((0, "[%c]", c)); return 1; } // int comm_get_cd(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_get_cd(COMM_OBJ *obj) { DWORD status; if (!obj->connect) return 0; GetCommModemStatus(obj->handle, &status); if (status & MS_RLSD_ON) return 1; else return 0; } // int comm_get_line_status(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_get_line_status(COMM_OBJ *obj) { COMSTAT comstat; DWORD err; int status=0; if (!obj->connect) return 0; ClearCommError(obj->handle, &err, &comstat); if (err & CE_BREAK) status |= COMM_STATUS_BREAK; if (err & CE_FRAME) status |= COMM_STATUS_FRAME; if (err & CE_OVERRUN) status |= COMM_STATUS_OVERRUN; if (err & CE_RXPARITY) status |= COMM_STATUS_RXPARITY; return status; } // void comm_clear_line_status(COMM_OBJ *obj) // ---------------------------------------------------------------------------- void comm_clear_line_status(COMM_OBJ *obj) { } // void comm_set_dtr(COMM_OBJ *obj, int flag); // ---------------------------------------------------------------------------- void comm_set_dtr(COMM_OBJ *obj, int flag) { if (!obj->connect) return; GetCommState(obj->handle, &obj->dcb); if (flag == 1) obj->dcb.fDtrControl = DTR_CONTROL_ENABLE; else obj->dcb.fDtrControl = DTR_CONTROL_DISABLE; SetCommState(obj->handle, &obj->dcb); } // void comm_set_rtscts(COMM_OBJ *obj, int flag); // ---------------------------------------------------------------------------- void comm_set_rtscts(COMM_OBJ *obj, int flag) { if (!obj->connect) return; GetCommState(obj->handle, &obj->dcb); if (flag) { obj->dcb.fOutxCtsFlow = TRUE; // rts/cts off obj->dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; } else { obj->dcb.fOutxCtsFlow = FALSE; // rts/cts off obj->dcb.fRtsControl = RTS_CONTROL_ENABLE; } SetCommState(obj->handle, &obj->dcb); } // int comm_modem_input_line(COMM_OBJ *obj, int msecs, char *buffer, int chars); // ---------------------------------------------------------------------------- int comm_modem_input_line(COMM_OBJ *obj, int msecs, char *buffer, int chars) { long timeout; int ch; int retval=1; int i; i = 0; timeout = timeGetTime() + msecs; if (chars <= 0) return 0; while (1) { ch = comm_read_char(obj); if (ch >=0) { if (ch == '\r') { // mprintf((0, "\n")); break; } if (ch == '\n') continue; buffer[i++] = (char)ch; chars--; if (chars == 0) break; } else if (ch == COMM_BUF_EMPTY) { retval = 0; break; } else { retval = ch; break; } if (timeout <= timeGetTime()) break; } buffer[i] = '\0'; if (retval < 0) return retval; retval = timeout - timeGetTime(); if (retval < 0) retval = 0; return retval; } // void comm_set_delay(COMM_OBJ *obj, int msecs) // ---------------------------------------------------------------------------- void comm_set_delay(COMM_OBJ *obj, int msecs) { comm_delay_val = (long)msecs; } // void comm_wait(COMM_OBJ *obj, int msecs) // ---------------------------------------------------------------------------- int comm_wait(COMM_OBJ *obj, int msecs) { long delaytime; delaytime = timeGetTime() + (long)msecs; while (timeGetTime() < delaytime) { if (!comm_idle_function(obj)) { mprintf((1, "Comm_wait: THIS IS NOT GOOD!!\n")); return 0; } } return 1; } // int comm_modem_send_string(COMM_OBJ *obj, char *str); // ---------------------------------------------------------------------------- int comm_modem_send_string(COMM_OBJ *obj, char *str) { int retval; long curtime; char buf[64]; mprintf((0, "Commodem: send %s\n", str)); retval = comm_modem_send_string_nowait(obj, str, -2); if (!retval) return 0; if (comm_delay_val > 0) { if (!comm_wait(obj, comm_delay_val)) return 0; } // Checking for OK response curtime = comm_delay_val; while(1) { curtime = comm_modem_input_line(obj, curtime, buf, 64); if (curtime == 0) { mprintf((1, "CommSendString: Didn't get an OK!\n")); return 0; } if (strcmp("OK", buf) == 0) { return comm_wait(obj, 500); } } } // int comm_modem_send_string_nowait(COMM_OBJ *obj, char *str, int term); // ---------------------------------------------------------------------------- int comm_modem_send_string_nowait(COMM_OBJ *obj, char *str, int term) { int i; if (term < -2 || term > 255) return 0; // mprintf((0, "<%s", str)); for (i= 0; i < lstrlen(str); i++) comm_write_char(obj, str[i]); //@@ if (!WriteFile(obj->handle, &str, lstrlen(str), &length, &obj->wov)) { //@@ if (GetLastError() == ERROR_IO_PENDING) { //@@ mprintf((0,"Comm: SendStringNoWait IO pending...\n")); //@@ while (!GetOverlappedResult(obj->handle, &obj->wov, &length, TRUE)) //@@ { //@@ errflags = GetLastError(); //@@ if (errflags == ERROR_IO_INCOMPLETE) //@@ continue; //@@ else { //@@ ClearCommError(obj->handle, &errflags, &comstat); //@@ mprintf((1, "Comm: SendStringNoWait error!\n")); //@@ return 0; //@@ } //@@ } //@@ } //@@ else { //@@ ClearCommError(obj->handle, &errflags, &comstat); //@@ mprintf((1, "Comm: SendStringNoWait error!\n")); //@@ return 0; //@@ } //@@ } if (term >=0) comm_write_char(obj, term); else if (term == -2) { comm_write_char(obj, '\r'); comm_write_char(obj, '\n'); } return 1; } // int comm_modem_reset(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_modem_reset(COMM_OBJ *obj) { return comm_modem_send_string(obj, obj->cmd[COMM_RESET_CMD]); } // int comm_modem_dial(COMM_OBJ *obj, char *phonenum); // ---------------------------------------------------------------------------- int comm_modem_dial(COMM_OBJ *obj, char *phonenum) { char str[40]; strcpy(str, obj->cmd[COMM_PREFIX_CMD]); strcat(str, obj->cmd[COMM_DIALPREF_CMD]); strcat(str, phonenum); return comm_modem_send_string_nowait(obj, str, '\r'); } // int comm_modem_answer(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int comm_modem_answer(COMM_OBJ *obj) { return comm_modem_send_string_nowait(obj, obj->cmd[COMM_ANSWER_CMD], '\r'); } //@@ DWORD FAR PASCAL comm_thread_proc (LPSTR lpData); //@@ ------------------------------------------------------------------------- //@@DWORD FAR PASCAL comm_thread_proc (LPSTR lpData) //@@{ //@@ DWORD event_mask; //@@ OVERLAPPED os; //@@ COMM_OBJ *obj = (COMM_OBJ *)lpData; //@@ //@@ memset(&os, 0, sizeof(OVERLAPPED)); //@@ os.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //@@ if (os.hEvent == NULL) { //@@ mprintf((1, "CommThread: unable to create event!\n")); //@@ return FALSE; //@@ } //@@ //@@ if (!SetCommMask(obj->handle, EV_RXCHAR)) return FALSE; //@@ //@@ while (obj->connected) //@@ { //@@ event_mask = 0; //@@ WaitCommEvent(obj->handle, &event_mask, NULL); //@@ if ((event_mask & EV_RXCHAR) == EV_RXCHAR) { //@@ } //@@ } //@@} // int FAR PASCAL comm_idle_function(COMM_OBJ *obj); // ---------------------------------------------------------------------------- int FAR PASCAL comm_idle_function(COMM_OBJ *obj) { MSG msg; while (PeekMessage(&msg, 0,0,0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } return 1; } // Dump Info // ---------------------------------------------------------------------------- void comm_dump_info(COMM_OBJ *obj) { int baud; switch (obj->dcb.BaudRate) { case CBR_9600: baud = 9600; break; case CBR_14400: baud = 14400; break; case CBR_19200: baud = 19200; break; case CBR_38400: baud = 38400; break; case CBR_57600: baud = 57600; break; default: baud = -1; } mprintf((0, "CommObj %x:\n", obj->handle)); mprintf((0, "\tConnect: %d\n\tDevice: %s\n", obj->connect, obj->name)); mprintf((0, "\tPort: COM%d\n", obj->port)); mprintf((0, "\tBaud: %d\n\tDTR:[%d] RTS/CTS:[%d|%d]\n", baud, obj->dcb.fDtrControl,obj->dcb.fRtsControl,obj->dcb.fOutxCtsFlow)); mprintf((0, "\tXON/XOFF [In|Out]:[%d|%d] XON/OFF thresh:[%d|%d]\n", obj->dcb.fInX, obj->dcb.fOutX, obj->dcb.XonLim, obj->dcb.XoffLim)); }