DOSBox-X
|
00001 /* 00002 * Copyright (C) 2002-2020 The DOSBox Team 00003 * 00004 * This program is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with this program; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 */ 00018 00019 00020 #include "libserial.h" 00021 00022 #include "config.h" 00023 00024 #ifdef WIN32 00025 00026 #include <windows.h> 00027 #include <stdio.h> 00028 00029 struct _COMPORT { 00030 HANDLE porthandle; 00031 bool breakstatus; 00032 DCB orig_dcb; 00033 }; 00034 00035 bool SERIAL_open(const char* portname, COMPORT* port) { 00036 // allocate COMPORT structure 00037 COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); 00038 if(cp == NULL) return false; 00039 00040 cp->breakstatus=false; 00041 00042 // open the port in NT object space (recommended by Microsoft) 00043 // allows the user to open COM10+ and custom port names. 00044 size_t len = strlen(portname); 00045 if(len > 240) { 00046 SetLastError(ERROR_BUFFER_OVERFLOW); 00047 free(cp); 00048 return false; 00049 } 00050 char extended_portname[256] = "\\\\.\\"; 00051 memcpy(extended_portname+4,portname,len+1); 00052 00053 cp->porthandle = CreateFile (extended_portname, 00054 GENERIC_READ | GENERIC_WRITE, 0, 00055 // must be opened with exclusive-access 00056 NULL, // no security attributes 00057 OPEN_EXISTING, // must use OPEN_EXISTING 00058 0, // non overlapped I/O 00059 NULL // hTemplate must be NULL for comm devices 00060 ); 00061 00062 if (cp->porthandle == INVALID_HANDLE_VALUE) goto cleanup_error; 00063 00064 cp->orig_dcb.DCBlength=sizeof(DCB); 00065 00066 if(!GetCommState(cp->porthandle, &cp->orig_dcb)) { 00067 goto cleanup_error; 00068 } 00069 00070 // configure the port for polling 00071 DCB newdcb; 00072 memcpy(&newdcb,&cp->orig_dcb,sizeof(DCB)); 00073 00074 newdcb.fBinary=true; 00075 newdcb.fParity=true; 00076 newdcb.fOutxCtsFlow=false; 00077 newdcb.fOutxDsrFlow=false; 00078 newdcb.fDtrControl=DTR_CONTROL_DISABLE; 00079 newdcb.fDsrSensitivity=false; 00080 00081 newdcb.fOutX=false; 00082 newdcb.fInX=false; 00083 newdcb.fErrorChar=0; 00084 newdcb.fNull=false; 00085 newdcb.fRtsControl=RTS_CONTROL_DISABLE; 00086 newdcb.fAbortOnError=false; 00087 00088 if(!SetCommState(cp->porthandle, &newdcb)) { 00089 goto cleanup_error; 00090 } 00091 00092 // Configure timeouts to effectively use polling 00093 COMMTIMEOUTS ct; 00094 ct.ReadIntervalTimeout = MAXDWORD; 00095 ct.ReadTotalTimeoutConstant = 0; 00096 ct.ReadTotalTimeoutMultiplier = 0; 00097 ct.WriteTotalTimeoutConstant = 0; 00098 ct.WriteTotalTimeoutMultiplier = 0; 00099 if(!SetCommTimeouts(cp->porthandle, &ct)) { 00100 goto cleanup_error; 00101 } 00102 if(!ClearCommBreak(cp->porthandle)) { 00103 // Bluetooth Bluesoleil seems to not implement it 00104 //goto cleanup_error; 00105 } 00106 DWORD errors; 00107 if(!ClearCommError(cp->porthandle, &errors, NULL)) { 00108 goto cleanup_error; 00109 } 00110 *port = cp; 00111 return true; 00112 00113 cleanup_error: 00114 if (cp->porthandle != INVALID_HANDLE_VALUE) CloseHandle(cp->porthandle); 00115 free(cp); 00116 return false; 00117 } 00118 00119 void SERIAL_close(COMPORT port) { 00120 // restore original DCB, close handle, free the COMPORT struct 00121 if (port->porthandle != INVALID_HANDLE_VALUE) { 00122 SetCommState(port->porthandle, &port->orig_dcb); 00123 CloseHandle(port->porthandle); 00124 } 00125 free(port); 00126 } 00127 00128 void SERIAL_getErrorString(char* buffer, size_t length) { 00129 int error = GetLastError(); 00130 if(length < 50) return; 00131 memset(buffer,0,length); 00132 // get the error message text from the operating system 00133 LPVOID sysmessagebuffer; 00134 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 00135 NULL, 00136 error, 00137 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 00138 (LPTSTR) &sysmessagebuffer, 00139 0,NULL); 00140 00141 size_t sysmsg_offset = 0; 00142 00143 if(error == 5) { 00144 const char* err5text = "The specified port is already in use.\n"; 00145 sysmsg_offset = (int)strlen(err5text); 00146 memcpy(buffer,err5text,sysmsg_offset); 00147 00148 } else if(error == 2) { 00149 const char* err2text = "The specified port does not exist.\n"; 00150 sysmsg_offset = (int)strlen(err2text); 00151 memcpy(buffer,err2text,sysmsg_offset); 00152 } 00153 00154 // Go for length > so there will be bytes left afterwards. 00155 // (which are 0 due to memset, thus the buffer is 0 terminated 00156 if ( length > (sysmsg_offset + (int)strlen((const char*)sysmessagebuffer)) ) { 00157 memcpy(buffer + sysmsg_offset, sysmessagebuffer, 00158 strlen((const char*)sysmessagebuffer)); 00159 } 00160 00161 LocalFree(sysmessagebuffer); 00162 } 00163 00164 00165 void SERIAL_setDTR(COMPORT port, bool value) { 00166 EscapeCommFunction(port->porthandle, value ? SETDTR:CLRDTR); 00167 } 00168 00169 void SERIAL_setRTS(COMPORT port, bool value) { 00170 EscapeCommFunction(port->porthandle, value ? SETRTS:CLRRTS); 00171 } 00172 00173 void SERIAL_setBREAK(COMPORT port, bool value) { 00174 EscapeCommFunction(port->porthandle, value ? SETBREAK:CLRBREAK); 00175 port->breakstatus = value; 00176 } 00177 00178 int SERIAL_getmodemstatus(COMPORT port) { 00179 DWORD retval = 0; 00180 GetCommModemStatus (port->porthandle, &retval); 00181 return (int)retval; 00182 } 00183 00184 bool SERIAL_sendchar(COMPORT port, char data) { 00185 DWORD bytesWritten; 00186 00187 // mean bug: with break = 1, WriteFile will never return. 00188 if(port->breakstatus) return true; // true or false?! 00189 00190 WriteFile (port->porthandle, &data, 1, &bytesWritten, NULL); 00191 if(bytesWritten==1) return true; 00192 else return false; 00193 } 00194 00195 // 0-7 char data, higher=flags 00196 int SERIAL_getextchar(COMPORT port) { 00197 DWORD errors = 0; // errors from API 00198 DWORD dwRead = 0; // Number of chars read 00199 char chRead; 00200 00201 int retval = 0; 00202 // receive a byte; TODO communicate failure 00203 if (ReadFile (port->porthandle, &chRead, 1, &dwRead, NULL)) { 00204 if (dwRead) { 00205 // check for errors 00206 ClearCommError(port->porthandle, &errors, NULL); 00207 // mask bits are identical 00208 errors &= CE_BREAK|CE_FRAME|CE_RXPARITY|CE_OVERRUN; 00209 retval |= (errors<<8); 00210 retval |= (chRead & 0xff); 00211 retval |= 0x10000; 00212 } 00213 } 00214 return retval; 00215 } 00216 00217 bool SERIAL_setCommParameters(COMPORT port, 00218 int baudrate, char parity, int stopbits, int length) { 00219 00220 DCB dcb; 00221 dcb.DCBlength=sizeof(dcb); 00222 GetCommState(port->porthandle,&dcb); 00223 00224 // parity 00225 switch (parity) { 00226 case 'n': dcb.Parity = NOPARITY; break; 00227 case 'o': dcb.Parity = ODDPARITY; break; 00228 case 'e': dcb.Parity = EVENPARITY; break; 00229 case 'm': dcb.Parity = MARKPARITY; break; 00230 case 's': dcb.Parity = SPACEPARITY; break; 00231 default: 00232 SetLastError(ERROR_INVALID_PARAMETER); 00233 return false; 00234 } 00235 00236 // stopbits 00237 switch(stopbits) { 00238 case SERIAL_1STOP: dcb.StopBits = ONESTOPBIT; break; 00239 case SERIAL_2STOP: dcb.StopBits = TWOSTOPBITS; break; 00240 case SERIAL_15STOP: dcb.StopBits = ONE5STOPBITS; break; 00241 default: 00242 SetLastError(ERROR_INVALID_PARAMETER); 00243 return false; 00244 } 00245 00246 // byte length 00247 if(length > 8 || length < 5) { 00248 SetLastError(ERROR_INVALID_PARAMETER); 00249 return false; 00250 } 00251 dcb.ByteSize = length; 00252 dcb.BaudRate = baudrate; 00253 00254 if (!SetCommState (port->porthandle, &dcb)) return false; 00255 return true; 00256 } 00257 #endif 00258 00259 #if defined (LINUX) || defined (MACOSX) || defined (BSD) || defined (HAIKU) 00260 00261 #include <string.h> // strlen 00262 #include <stdlib.h> 00263 00264 #include <termios.h> 00265 #include <unistd.h> 00266 00267 #include <sys/types.h> 00268 #include <sys/stat.h> 00269 #include <sys/ioctl.h> 00270 00271 #include <errno.h> 00272 #include <fcntl.h> 00273 #include <stdio.h> // sprinf 00274 00275 struct _COMPORT { 00276 int porthandle; 00277 bool breakstatus; 00278 termios backup; 00279 }; 00280 00281 bool SERIAL_open(const char* portname, COMPORT* port) { 00282 int result; 00283 // allocate COMPORT structure 00284 COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); 00285 if(cp == NULL) return false; 00286 00287 cp->breakstatus=false; 00288 00289 size_t len = strlen(portname); 00290 if(len > 240) { 00292 return false; 00293 } 00294 char extended_portname[256] = "/dev/"; 00295 memcpy(extended_portname+5,portname,(size_t)len); 00296 00297 cp->porthandle = open (extended_portname, O_RDWR | O_NOCTTY | O_NONBLOCK); 00298 if (cp->porthandle < 0) goto cleanup_error; 00299 00300 result = tcgetattr(cp->porthandle,&cp->backup); 00301 if (result==-1) goto cleanup_error; 00302 00303 // get port settings 00304 termios termInfo; 00305 memcpy(&termInfo,&cp->backup,sizeof(termios)); 00306 00307 // initialize the port 00308 termInfo.c_cflag = CS8 | CREAD | CLOCAL; // noparity, 1 stopbit 00309 termInfo.c_iflag = PARMRK | INPCK; 00310 termInfo.c_oflag = 0; 00311 termInfo.c_lflag = 0; 00312 termInfo.c_cc[VMIN] = 0; 00313 termInfo.c_cc[VTIME] = 0; 00314 00315 tcflush (cp->porthandle, TCIFLUSH); 00316 tcsetattr (cp->porthandle, TCSANOW, &termInfo); 00317 00318 *port = cp; 00319 return true; 00320 00321 cleanup_error: 00322 if (cp->porthandle != 0) close(cp->porthandle); 00323 free(cp); 00324 return false; 00325 } 00326 00327 void SERIAL_close(COMPORT port) { 00328 // restore original termios, close handle, free the COMPORT struct 00329 if (port->porthandle >= 0) { 00330 tcsetattr(port->porthandle, TCSANOW, &port->backup); 00331 close(port->porthandle); 00332 } 00333 free(port); 00334 } 00335 00336 void SERIAL_getErrorString(char* buffer, size_t length) { 00337 int error = errno; 00338 if(length < 50) return; 00339 memset(buffer,0,(size_t)length); 00340 // get the error message text from the operating system 00341 // TODO (or not) 00342 00343 const char* err5text = "The specified port is already in use.\n"; 00344 const char* err2text = "The specified port does not exist.\n"; 00345 00346 size_t sysmsg_offset = 0; 00347 00348 if(error == EBUSY) { 00349 sysmsg_offset = strlen(err5text); 00350 memcpy(buffer,err5text,(size_t)sysmsg_offset); 00351 00352 } else if(error == 2) { 00353 sysmsg_offset = strlen(err2text); 00354 memcpy(buffer,err2text,(size_t)sysmsg_offset); 00355 } 00356 00357 sprintf(buffer + sysmsg_offset, "System error %d.",error); 00358 00359 } 00360 00361 int SERIAL_getmodemstatus(COMPORT port) { 00362 long flags = 0; 00363 ioctl (port->porthandle, TIOCMGET, &flags); 00364 int retval = 0; 00365 if (flags & TIOCM_CTS) retval |= SERIAL_CTS; 00366 if (flags & TIOCM_DSR) retval |= SERIAL_DSR; 00367 if (flags & TIOCM_RI) retval |= SERIAL_RI; 00368 if (flags & TIOCM_CD) retval |= SERIAL_CD; 00369 return retval; 00370 } 00371 00372 bool SERIAL_sendchar(COMPORT port, char data) { 00373 if(port->breakstatus) return true; // true or false?!; Does POSIX need this check? 00374 int bytesWritten = write(port->porthandle, &data, 1); 00375 if(bytesWritten==1) return true; 00376 else return false; 00377 } 00378 00379 int SERIAL_getextchar(COMPORT port) { 00380 unsigned char chRead = 0; 00381 int dwRead = 0; 00382 unsigned char error = 0; 00383 int retval = 0; 00384 00385 dwRead=read(port->porthandle,&chRead,1); 00386 if (dwRead==1) { 00387 if(chRead==0xff) // error escape 00388 { 00389 dwRead=read(port->porthandle,&chRead,1); 00390 if(chRead==0x00) // an error 00391 { 00392 dwRead=read(port->porthandle,&chRead,1); 00393 if(chRead==0x0) error=SERIAL_BREAK_ERR; 00394 else error=SERIAL_FRAMING_ERR; 00395 } 00396 } 00397 retval |= (error<<8); 00398 retval |= chRead; 00399 retval |= 0x10000; 00400 } 00401 return retval; 00402 } 00403 00404 bool SERIAL_setCommParameters(COMPORT port, 00405 int baudrate, char parity, int stopbits, int length) { 00406 00407 termios termInfo; 00408 int result = tcgetattr(port->porthandle, &termInfo); 00409 if (result==-1) return false; 00410 termInfo.c_cflag = CREAD | CLOCAL; 00411 00412 // parity 00413 // "works on many systems" 00414 #define CMSPAR 010000000000 00415 switch (parity) { 00416 case 'n': break; 00417 case 'o': termInfo.c_cflag |= (PARODD | PARENB); break; 00418 case 'e': termInfo.c_cflag |= PARENB; break; 00419 case 'm': termInfo.c_cflag |= (PARENB | CMSPAR | PARODD); break; 00420 case 's': termInfo.c_cflag |= (PARENB | CMSPAR); break; 00421 default: 00422 return false; 00423 } 00424 // stopbits 00425 switch(stopbits) { 00426 case SERIAL_1STOP: break; 00427 case SERIAL_2STOP: 00428 case SERIAL_15STOP: termInfo.c_cflag |= CSTOPB; break; 00429 default: 00430 return false; 00431 } 00432 // byte length 00433 if(length > 8 || length < 5) return false; 00434 switch (length) { 00435 case 5: termInfo.c_cflag |= CS5; break; 00436 case 6: termInfo.c_cflag |= CS6; break; 00437 case 7: termInfo.c_cflag |= CS7; break; 00438 case 8: termInfo.c_cflag |= CS8; break; 00439 } 00440 // baudrate 00441 int posix_baudrate=0; 00442 switch(baudrate) { 00443 case 115200: posix_baudrate = B115200; break; 00444 case 57600: posix_baudrate = B57600; break; 00445 case 38400: posix_baudrate = B38400; break; 00446 case 19200: posix_baudrate = B19200; break; 00447 case 9600: posix_baudrate = B9600; break; 00448 case 4800: posix_baudrate = B4800; break; 00449 case 2400: posix_baudrate = B2400; break; 00450 case 1200: posix_baudrate = B1200; break; 00451 case 600: posix_baudrate = B600; break; 00452 case 300: posix_baudrate = B300; break; 00453 case 110: posix_baudrate = B110; break; 00454 default: return false; 00455 } 00456 cfsetospeed (&termInfo, (unsigned int)posix_baudrate); 00457 cfsetispeed (&termInfo, (unsigned int)posix_baudrate); 00458 00459 int retval = tcsetattr(port->porthandle, TCSANOW, &termInfo); 00460 if(retval==-1) return false; 00461 return true; 00462 } 00463 00464 void SERIAL_setBREAK(COMPORT port, bool value) { 00465 ioctl(port->porthandle, value?TIOCSBRK:TIOCCBRK); 00466 } 00467 00468 void SERIAL_setDTR(COMPORT port, bool value) { 00469 long flag = TIOCM_DTR; 00470 ioctl(port->porthandle, value?TIOCMBIS:TIOCMBIC, &flag); 00471 } 00472 00473 void SERIAL_setRTS(COMPORT port, bool value) { 00474 long flag = TIOCM_RTS; 00475 ioctl(port->porthandle, value?TIOCMBIS:TIOCMBIC, &flag); 00476 } 00477 #endif 00478 00479 #ifdef OS2 00480 // OS/2 related headers 00481 #define INCL_DOSFILEMGR 00482 #define INCL_DOSERRORS 00483 #define INCL_DOSDEVICES 00484 #define INCL_DOSDEVIOCTL 00485 #define INCL_DOSPROCESS 00486 #include <os2.h> 00487 #include <malloc.h> 00488 #include <string.h> 00489 #include <stdio.h> 00490 00491 struct _COMPORT { 00492 HFILE porthandle; 00493 DCBINFO orig_dcb; 00494 }; 00495 // TODO: THIS IS INCOMPLETE and UNTESTED. 00496 00497 bool SERIAL_open(const char* portname, COMPORT* port) { 00498 // allocate COMPORT structure 00499 COMPORT cp = (_COMPORT*)malloc(sizeof(_COMPORT)); 00500 if(cp == NULL) return false; 00501 cp->porthandle=0; 00502 00503 USHORT errors = 0; 00504 ULONG ulAction = 0; 00505 ULONG ulParmLen = sizeof(DCBINFO); 00506 APIRET rc = DosOpen((PSZ)portname, &cp->porthandle, 00507 &ulAction, 0L, FILE_NORMAL, FILE_OPEN, 00508 OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE | OPEN_FLAGS_SEQUENTIAL, 0L); 00509 if (rc != NO_ERROR) { 00510 goto cleanup_error; 00511 } 00512 00513 rc = DosDevIOCtl(cp->porthandle, IOCTL_ASYNC, ASYNC_GETDCBINFO, 00514 0, 0, 0, &cp->orig_dcb, ulParmLen, &ulParmLen); 00515 if ( rc != NO_ERROR) { 00516 goto cleanup_error; 00517 } 00518 // configure the port for polling 00519 DCBINFO newdcb; 00520 memcpy(&newdcb,&cp->orig_dcb,sizeof(DCBINFO)); 00521 00522 newdcb.usWriteTimeout = 0; 00523 newdcb.usReadTimeout = 0; //65535; 00524 newdcb.fbCtlHndShake = cp->orig_dcb.fbFlowReplace = 0; 00525 newdcb.fbTimeout = 6; 00526 00527 rc = DosDevIOCtl(cp->porthandle, IOCTL_ASYNC, ASYNC_SETDCBINFO, 00528 &newdcb, ulParmLen, &ulParmLen, 0, 0, 0); 00529 if ( rc != NO_ERROR) { 00530 goto cleanup_error; 00531 } 00532 00533 ulParmLen = sizeof(errors); 00534 rc = DosDevIOCtl(cp->porthandle, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 00535 0, 0, 0, &errors, ulParmLen, &ulParmLen); 00536 if ( rc != NO_ERROR) { 00537 goto cleanup_error; 00538 } 00539 00540 *port = cp; 00541 return true; 00542 00543 cleanup_error: 00544 // TODO error string - rc value 00545 if (cp->porthandle != 0) DosClose(cp->porthandle); 00546 free(cp); 00547 return false; 00548 } 00549 00550 void SERIAL_getErrorString(char* buffer, size_t length) { 00551 sprintf(buffer, "TODO: error handling is not fun"); 00552 } 00553 void SERIAL_close(COMPORT port) { 00554 ULONG ulParmLen = sizeof(DCBINFO); 00555 // restore original DCB, close handle, free the COMPORT struct 00556 if (port->porthandle != 0) { 00557 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETDCBINFO, 00558 &port->orig_dcb, ulParmLen, &ulParmLen, 0, 0, 0); 00559 DosClose (port->porthandle); 00560 } 00561 free(port); 00562 } 00563 bool SERIAL_sendchar(COMPORT port, char data) { 00564 ULONG bytesWritten = 0; 00565 00566 APIRET rc = DosWrite(port->porthandle, &data, 1, &bytesWritten); 00567 if (rc == NO_ERROR && bytesWritten > 0) return true; 00568 else return false; 00569 } 00570 00571 void SERIAL_setBREAK(COMPORT port, bool value) { 00572 USHORT error; 00573 ULONG ulParmLen = sizeof(error); 00574 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, 00575 value ? ASYNC_SETBREAKON : ASYNC_SETBREAKOFF, 00576 0,0,0, &error, ulParmLen, &ulParmLen); 00577 } 00578 00579 int SERIAL_getextchar(COMPORT port) { 00580 ULONG dwRead = 0; // Number of chars read 00581 char chRead; 00582 00583 int retval = 0; 00584 // receive a byte; TODO communicate failure 00585 if (DosRead(port->porthandle, &chRead, 1, &dwRead) == NO_ERROR) { 00586 if (dwRead) { 00587 // check for errors; will OS/2 clear the error on reading its data? 00588 // if yes then this is in wrong order 00589 USHORT errors = 0, event = 0; 00590 ULONG ulParmLen = sizeof(errors); 00591 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETCOMMEVENT, 00592 0, 0, 0, &event, ulParmLen, &ulParmLen); 00593 if (event & (64 + 128) ) { // Break (Bit 6) or Frame or Parity (Bit 7) error 00594 Bit8u errreg = 0; 00595 if (event & 64) retval |= SERIAL_BREAK_ERR; 00596 if (event & 128) { 00597 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETCOMMERROR, 00598 0, 0, 0, &errors, ulParmLen, &ulParmLen); 00599 if (errors & 8) retval |= SERIAL_FRAMING_ERR; 00600 if (errors & 4) retval |= SERIAL_PARITY_ERR; 00601 } 00602 } 00603 retval |= (chRead & 0xff); 00604 retval |= 0x10000; 00605 } 00606 } 00607 return retval; 00608 } 00609 00610 00611 int SERIAL_getmodemstatus(COMPORT port) { 00612 UCHAR dptr = 0; 00613 ULONG ulParmLen = sizeof(dptr); 00614 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_GETMODEMINPUT, 00615 0, 0, 0, &dptr, ulParmLen, &ulParmLen); 00616 // bits are the same as return value 00617 return (int)dptr; 00618 } 00619 void SERIAL_setDTR(COMPORT port, bool value) { 00620 UCHAR masks[2]; 00621 ULONG ulParmLen = sizeof(masks); 00622 if(value) { 00623 masks[0]=0x01; 00624 masks[1]=0xFF; 00625 } else { 00626 masks[0]=0x00; 00627 masks[1]=0xFE; 00628 } 00629 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, 00630 0,0,0, &masks, ulParmLen, &ulParmLen); 00631 } 00632 00633 void SERIAL_setRTS(COMPORT port, bool value) { 00634 UCHAR masks[2]; 00635 ULONG ulParmLen = sizeof(masks); 00636 if(value) { 00637 masks[0]=0x02; 00638 masks[1]=0xFF; 00639 } else { 00640 masks[0]=0x00; 00641 masks[1]=0xFD; 00642 } 00643 DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETMODEMCTRL, 00644 0,0,0, &masks, ulParmLen, &ulParmLen); 00645 } 00646 00647 00648 00649 bool SERIAL_setCommParameters(COMPORT port, 00650 int baudrate, char parity, int stopbits, int length) { 00651 // baud 00652 struct { 00653 ULONG baud; 00654 BYTE fraction; 00655 } setbaud; 00656 00657 setbaud.baud = baudrate; 00658 setbaud.fraction = 0; 00659 ULONG ulParmLen = sizeof(setbaud); 00660 APIRET rc = DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_EXTSETBAUDRATE, 00661 &setbaud, ulParmLen, &ulParmLen, 0, 0, 0); 00662 if (rc != NO_ERROR) { 00663 return false; 00664 } 00665 00666 struct { 00667 UCHAR data; 00668 UCHAR parity; 00669 UCHAR stop; 00670 } paramline; 00671 00672 // byte length 00673 if(length > 8 || length < 5) { 00674 // TODO SetLastError(ERROR_INVALID_PARAMETER); 00675 return false; 00676 } 00677 paramline.data = length; 00678 00679 // parity 00680 switch (parity) { 00681 case 'n': paramline.parity = 0; break; 00682 case 'o': paramline.parity = 1; break; 00683 case 'e': paramline.parity = 2; break; 00684 case 'm': paramline.parity = 3; break; 00685 case 's': paramline.parity = 4; break; 00686 default: 00687 // TODO SetLastError(ERROR_INVALID_PARAMETER); 00688 return false; 00689 } 00690 // stopbits 00691 switch(stopbits) { 00692 case SERIAL_1STOP: paramline.stop = 0; break; 00693 case SERIAL_2STOP: paramline.stop = 2; break; 00694 case SERIAL_15STOP: paramline.stop = 1; break; 00695 default: 00696 // TODO SetLastError(ERROR_INVALID_PARAMETER); 00697 return false; 00698 } 00699 // set it 00700 ulParmLen = sizeof(paramline); 00701 rc = DosDevIOCtl(port->porthandle, IOCTL_ASYNC, ASYNC_SETLINECTRL, 00702 ¶mline, ulParmLen, &ulParmLen, 0, 0, 0); 00703 if ( rc != NO_ERROR) 00704 return false; 00705 return true; 00706 } 00707 #endif