BOOL is_port_available(int nPort) { TCHAR szPort[15]; COMMCONFIG cc; DWORD dwCCSize; sprintf(szPort, "COM%d", nPort); // Check if this port is available dwCCSize = sizeof(cc); return GetDefaultCommConfig(szPort, &cc, &dwCCSize); }
// This function searches through com ports 1 to 128 and determines if they // exist or not. The list of existing ports is sent as a response. std::vector<string> GetComPorts() { vector<string> ports; int index = 1; // Go through each possible port (assuming no more than 64 ports on a system) for (int i = 1; i <= 64; ++i) { char* buffer = new char[8]; string port = "COM"; port += itoa(i, buffer, 10); // First get the size DWORD dwSize = 0; LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[1]; BOOL ret = GetDefaultCommConfig(port.c_str(), lpCC, &dwSize); delete [] lpCC; // Now test the port lpCC = (LPCOMMCONFIG) new BYTE[dwSize]; ret = GetDefaultCommConfig(port.c_str(), lpCC, &dwSize); // If the port exists, add to the vector if (ret != null) { string pusher = itoa(index++, buffer, 10); pusher += ". "; pusher += port; ports.push_back(pusher); } delete[] buffer; delete [] lpCC; } return ports; }
BOOL CEnumerateSerial::UsingGetDefaultCommConfig(CSimpleArray<UINT>& ports) #endif { //Make sure we clear out any elements which may already be in the array #if defined CENUMERATESERIAL_USE_STL ports.clear(); #else ports.RemoveAll(); #endif //Up to 255 COM ports are supported so we iterate through all of them seeing //if we can get the default configuration for (UINT i=1; i<256; i++) { //Form the Raw device name CString sPort; sPort.Format(_T("COM%u"), i); COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); if (GetDefaultCommConfig(sPort, &cc, &dwSize)) { #if defined CENUMERATESERIAL_USE_STL ports.push_back(i); #else ports.Add(i); #endif } } //Return the success indicator return TRUE; }
PortNameList SerialEnumeratorWindows::listPorts() { PortNameList retList; char comBufName[7]; DWORD size; for (int i = 1; i < 256; i++) { // allocate and reset COMMCONFIG CommConfig; size = sizeof CommConfig; snprintf(comBufName, COMBUFSIZE, "COM%d", i); if (GetDefaultCommConfig( comBufName, &CommConfig, &size) || size > sizeof CommConfig) { PortName nameStr(comBufName, COMBUFSIZE); retList.push_back(nameStr); } } return retList; }
void CSerialPort::GetDefaultConfig(int nPort, COMMCONFIG& config) { //Validate our parameters ASSERT(nPort>0 && nPort<=255); //Create the device name as a string CString sPort; sPort.Format(_T("COM%d"), nPort); DWORD dwSize = sizeof(COMMCONFIG); if (!GetDefaultCommConfig(sPort, &config, &dwSize)) { TRACE(_T("Failed in call to GetDefaultCommConfig\n")); AfxThrowSerialException(); } }
bool setCommConfiguration(const char* device, RssconwindowsPortdata* pdata, DCB* port) { COMMCONFIG commConfig = {0}; DWORD dwSize = sizeof(commConfig); commConfig.dwSize = dwSize; if (!GetDefaultCommConfig(device, &commConfig, &dwSize)) { fputs("Failed to get default port settings.\n", stderr); pdata->lastError = GetLastError(); return false; } if (!SetCommConfig(pdata->portHandle, &commConfig, dwSize)) { fputs("Failed to set default port settings.\n", stderr); pdata->lastError = GetLastError(); return false; } return true; }
QVector<QString> SerialConnection::enumerate() { QVector<QString> ports; #ifdef _WIN32 COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); for (size_t i=1; i<20; i++) { QString szPort = QString("COM%1").arg(QString::number(i)); if (GetDefaultCommConfig(szPort.toStdWString().c_str(), &cc, &dwSize)) ports.push_back(szPort); } #else QDir dir("/dev"); QStringList filters; filters << "ttyUSB*" << "ttyACM*" << "tty.usb*";// << "cu.usb*"; dir.setFilter(QDir::Files|QDir::System); dir.setNameFilters(filters); QFileInfoList list = dir.entryInfoList(); for (int i = 0; i < list.size(); ++i) ports.push_back(list.at(i).absoluteFilePath()); #endif return ports; }
std::vector<std::string> GetSerialPorts(bool &bUseDirectPath) { bUseDirectPath=false; std::vector<std::string> ret; #if defined WIN32 //windows std::vector<int> ports; std::vector<std::string> friendlyNames; char szPortName[40]; EnumSerialFromWMI(ports, friendlyNames); bool bFoundPort = false; if (!ports.empty()) { bFoundPort = true; std::vector<int>::const_iterator itt; for (itt = ports.begin(); itt != ports.end(); ++itt) { sprintf(szPortName, "COM%d", *itt); ret.push_back(szPortName); } } if (bFoundPort) return ret; //Scan old fashion way (SLOW!) COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); for (int ii = 0; ii < 256; ii++) { sprintf(szPortName, "COM%d", ii); if (GetDefaultCommConfig(szPortName, &cc, &dwSize)) { bFoundPort = true; sprintf(szPortName, "COM%d", ii); //Check if we did not already have it std::vector<std::string>::const_iterator itt; bool bFound = false; for (itt = ret.begin(); itt != ret.end(); ++itt) { if (*itt == szPortName) { bFound = true; break; } } if (!bFound) ret.push_back(szPortName); // add port } } // Method 2: CreateFile, slow // --------- if (!bFoundPort) { for (int ii = 0; ii < 256; ii++) { sprintf(szPortName, "\\\\.\\COM%d", ii); bool bSuccess = false; HANDLE hPort = ::CreateFile(szPortName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if (hPort == INVALID_HANDLE_VALUE) { DWORD dwError = GetLastError(); //Check to see if the error was because some other app had the port open if (dwError == ERROR_ACCESS_DENIED) bSuccess = TRUE; } else { //The port was opened successfully bSuccess = TRUE; //Don't forget to close the port, since we are going to do nothing with it anyway CloseHandle(hPort); } if (bSuccess) { bFoundPort = true; sprintf(szPortName, "COM%d", ii); ret.push_back(szPortName); // add port } // -------------- } } // Method 3: EnumSerialPortsWindows, often fails // --------- if (!bFoundPort) { std::vector<SerialPortInfo> serialports; EnumSerialPortsWindows(serialports); if (!serialports.empty()) { std::vector<SerialPortInfo>::const_iterator itt; for (itt = serialports.begin(); itt != serialports.end(); ++itt) { ret.push_back(itt->szPortName); // add port } } } #else //scan /dev for /dev/ttyUSB* or /dev/ttyS* or /dev/tty.usbserial* or /dev/ttyAMA* bool bHaveTtyAMAfree=false; std::string sLine = ""; std::ifstream infile; infile.open("/boot/cmdline.txt"); if (infile.is_open()) { if (!infile.eof()) { getline(infile, sLine); bHaveTtyAMAfree=(sLine.find("ttyAMA0")==std::string::npos); } } DIR *d=NULL; d=opendir("/dev"); if (d != NULL) { struct dirent *de=NULL; // Loop while not NULL while ((de = readdir(d))) { std::string fname = de->d_name; if (fname.find("ttyUSB")!=std::string::npos) { ret.push_back("/dev/" + fname); } else if (fname.find("tty.usbserial")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/" + fname); } else if (fname.find("ttyACM")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/" + fname); } #ifdef __FreeBSD__ else if (fname.find("ttyU")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/" + fname); } #endif #ifdef __APPLE__ else if (fname.find("cu.")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/" + fname); } #endif if (bHaveTtyAMAfree) { if (fname.find("ttyAMA0")!=std::string::npos) { ret.push_back("/dev/" + fname); bUseDirectPath=true; } } } closedir(d); } //also scan in /dev/usb d=opendir("/dev/usb"); if (d != NULL) { struct dirent *de=NULL; // Loop while not NULL while ((de = readdir(d))) { std::string fname = de->d_name; if (fname.find("ttyUSB")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/usb/" + fname); } } closedir(d); } #endif return ret; }
// Open a port, by name. Return 0 on success, non-zero for error int Serial::Open(const wxString& name) { Close(); #if defined(LINUX) struct serial_struct kernel_serial_settings; int bits; port_fd = open(name.mb_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if (port_fd < 0) { if (errno == EACCES) { error_msg = _("Unable to access ") + wxString(name,wxConvUTF8) + _(", insufficient permission"); // TODO: we could look at the permission bits and owner // to make a better message here } else if (errno == EISDIR) { error_msg = _("Unable to open ") + wxString(name,wxConvUTF8) + _(", Object is a directory, not a serial port"); } else if (errno == ENODEV || errno == ENXIO) { error_msg = _("Unable to open ") + wxString(name,wxConvUTF8) + _(", Serial port hardware not installed"); } else if (errno == ENOENT) { error_msg = _("Unable to open ") + wxString(name,wxConvUTF8) + _(", Device name does not exist"); } else { error_msg = _("Unable to open ") + wxString(name,wxConvUTF8) + _(", ") + wxString(strerror(errno),wxConvUTF8); } return -1; } if (ioctl(port_fd, TIOCMGET, &bits) < 0) { close(port_fd); error_msg = _("Unable to query serial port signals"); return -1; } bits &= ~(TIOCM_DTR | TIOCM_RTS); if (ioctl(port_fd, TIOCMSET, &bits) < 0) { close(port_fd); error_msg = _("Unable to control serial port signals"); return -1; } if (tcgetattr(port_fd, &settings_orig) != 0) { close(port_fd); error_msg = _("Unable to query serial port settings (perhaps not a serial port)"); return -1; } memset(&settings, 0, sizeof(settings)); settings.c_iflag = IGNBRK | IGNPAR; settings.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; Set_baud(baud_rate); if (ioctl(port_fd, TIOCGSERIAL, &kernel_serial_settings) == 0) { kernel_serial_settings.flags |= ASYNC_LOW_LATENCY; ioctl(port_fd, TIOCSSERIAL, &kernel_serial_settings); } tcflush(port_fd, TCIFLUSH); #elif defined(MACOSX) int bits; port_fd = open(name.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); if (port_fd < 0) { error_msg = _("Unable to open ") + name + _(", ") + strerror(errno); return -1; } if (ioctl(port_fd, TIOCEXCL) == -1) { close(port_fd); error_msg = _("Unable to get exclussive access to port ") + name; return -1; } if (ioctl(port_fd, TIOCMGET, &bits) < 0) { close(port_fd); error_msg = _("Unable to query serial port signals on ") + name; return -1; } bits &= ~(TIOCM_DTR | TIOCM_RTS); if (ioctl(port_fd, TIOCMSET, &bits) < 0) { close(port_fd); error_msg = _("Unable to control serial port signals on ") + name; return -1; } if (tcgetattr(port_fd, &settings_orig) < 0) { close(port_fd); error_msg = _("Unable to access baud rate on port ") + name; return -1; } memset(&settings, 0, sizeof(settings)); settings.c_cflag = CS8 | CLOCAL | CREAD | HUPCL; settings.c_iflag = IGNBRK | IGNPAR; Set_baud(baud_rate); tcflush(port_fd, TCIFLUSH); #elif defined(WINDOWS) COMMCONFIG cfg; COMMTIMEOUTS timeouts; int got_default_cfg=0, port_num; char buf[1024], name_createfile[64], name_commconfig[64], *p; DWORD len; snprintf(buf, sizeof(buf), _("%s"), name.c_str()); p = strstr(buf, _("COM")); if (p && sscanf(p + 3, _("%d"), &port_num) == 1) { printf(_("port_num = %d\n"), port_num); snprintf(name_createfile, sizeof(name_createfile), _("\\\\.\\COM%d"), port_num); snprintf(name_commconfig, sizeof(name_commconfig), _("COM%d"), port_num); } else { snprintf(name_createfile, sizeof(name_createfile), _("%s"), name.c_str()); snprintf(name_commconfig, sizeof(name_commconfig), _("%s"), name.c_str()); } len = sizeof(COMMCONFIG); if (GetDefaultCommConfig(name_commconfig, &cfg, &len)) { // this prevents unintentionally raising DTR when opening // might only work on COM1 to COM9 got_default_cfg = 1; memcpy(&port_cfg_orig, &cfg, sizeof(COMMCONFIG)); cfg.dcb.fDtrControl = DTR_CONTROL_DISABLE; cfg.dcb.fRtsControl = RTS_CONTROL_DISABLE; SetDefaultCommConfig(name_commconfig, &cfg, sizeof(COMMCONFIG)); } else { printf(_("error with GetDefaultCommConfig\n")); } port_handle = CreateFile(name_createfile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (port_handle == INVALID_HANDLE_VALUE) { win32_err(buf); error_msg = _("Unable to open ") + name + _(", ") + buf; return -1; } len = sizeof(COMMCONFIG); if (!GetCommConfig(port_handle, &port_cfg, &len)) { CloseHandle(port_handle); win32_err(buf); error_msg = _("Unable to read communication config on ") + name + _(", ") + buf; return -1; } if (!got_default_cfg) { memcpy(&port_cfg_orig, &port_cfg, sizeof(COMMCONFIG)); } // http://msdn2.microsoft.com/en-us/library/aa363188(VS.85).aspx port_cfg.dcb.BaudRate = baud_rate; port_cfg.dcb.fBinary = TRUE; port_cfg.dcb.fParity = FALSE; port_cfg.dcb.fOutxCtsFlow = FALSE; port_cfg.dcb.fOutxDsrFlow = FALSE; port_cfg.dcb.fDtrControl = DTR_CONTROL_DISABLE; port_cfg.dcb.fDsrSensitivity = FALSE; port_cfg.dcb.fTXContinueOnXoff = TRUE; // ??? port_cfg.dcb.fOutX = FALSE; port_cfg.dcb.fInX = FALSE; port_cfg.dcb.fErrorChar = FALSE; port_cfg.dcb.fNull = FALSE; port_cfg.dcb.fRtsControl = RTS_CONTROL_DISABLE; port_cfg.dcb.fAbortOnError = FALSE; port_cfg.dcb.ByteSize = 8; port_cfg.dcb.Parity = NOPARITY; port_cfg.dcb.StopBits = ONESTOPBIT; if (!SetCommConfig(port_handle, &port_cfg, sizeof(COMMCONFIG))) { CloseHandle(port_handle); win32_err(buf); error_msg = _("Unable to write communication config to ") + name + _(", ") + buf; return -1; } if (!EscapeCommFunction(port_handle, CLRDTR | CLRRTS)) { CloseHandle(port_handle); win32_err(buf); error_msg = _("Unable to control serial port signals on ") + name + _(", ") + buf; return -1; } // http://msdn2.microsoft.com/en-us/library/aa363190(VS.85).aspx // setting to all zeros means timeouts are not used //timeouts.ReadIntervalTimeout = 0; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(port_handle, &timeouts)) { CloseHandle(port_handle); win32_err(buf); error_msg = _("Unable to write timeout settings to ") + name + _(", ") + buf; return -1; } #endif port_name = name; port_is_open = 1; return 0; }
// Return a list of all serial ports wxArrayString Serial::port_list() { wxArrayString list; #if defined(LINUX) // This is ugly guessing, but Linux doesn't seem to provide anything else. // If there really is an API to discover serial devices on Linux, please // email [email protected] with the info. Please? // The really BAD aspect is all ports get DTR raised briefly, because linux // has no way to open the port without raising DTR, and there isn't any way // to tell if the device file really represents hardware without opening it. // maybe sysfs or udev provides a useful API?? DIR *dir; struct dirent *f; struct stat st; unsigned int i, len[NUM_DEVNAMES]; char s[512]; int fd, bits; termios mytios; dir = opendir("/dev/"); if (dir == NULL) return list; for (i=0; i<NUM_DEVNAMES; i++) len[i] = strlen(devnames[i]); // Read all the filenames from the /dev directory... while ((f = readdir(dir)) != NULL) { // ignore everything that doesn't begin with "tty" if (strncmp(f->d_name, "tty", 3)) continue; // ignore anything that's not a known serial device name for (i=0; i<NUM_DEVNAMES; i++) { if (!strncmp(f->d_name + 3, devnames[i], len[i])) break; } if (i >= NUM_DEVNAMES) continue; snprintf(s, sizeof(s), "/dev/%s", f->d_name); // check if it's a character type device (almost certainly is) if (stat(s, &st) != 0 || !(st.st_mode & S_IFCHR)) continue; // now see if we can open the file - if the device file is // populating /dev but doesn't actually represent a loaded // driver, this is where we will detect it. fd = open(s, O_RDONLY | O_NOCTTY | O_NONBLOCK); if (fd < 0) { // if permission denied, give benefit of the doubt // (otherwise the port will be invisible to the user // and we won't have a to alert them to the permssion // problem) if (errno == EACCES) list.Add(wxString(s,wxConvUTF8)); // any other error, assume it's not a real device continue; } // does it respond to termios requests? (probably will since // the name began with tty). Some devices where a single // driver exports multiple names will open but this is where // we can really tell if they work with real hardare. if (tcgetattr(fd, &mytios) != 0) { close(fd); continue; } // does it respond to reading the control signals? If it's // some sort of non-serial terminal (eg, pseudo terminals) // this is where we will detect it's not really a serial port if (ioctl(fd, TIOCMGET, &bits) < 0) { close(fd); continue; } // it passed all the tests, it's a serial port, or some sort // of "terminal" that looks exactly like a real serial port! close(fd); // unfortunately, Linux always raises DTR when open is called. // not nice! Every serial port is going to get DTR raised // and then lowered. I wish there were a way to prevent this, // but it seems impossible. list.Add(wxString(s,wxConvUTF8)); } closedir(dir); #elif defined(MACOSX) // adapted from SerialPortSample.c, by Apple // http://developer.apple.com/samplecode/SerialPortSample/listing2.html // and also testserial.c, by Keyspan // http://www.keyspan.com/downloads-files/developer/macosx/KesypanTestSerial.c // www.rxtx.org, src/SerialImp.c seems to be based on Keyspan's testserial.c // neither keyspan nor rxtx properly release memory allocated. // more documentation at: // http://developer.apple.com/documentation/DeviceDrivers/Conceptual/WorkingWSerial/WWSerial_SerialDevs/chapter_2_section_6.html mach_port_t masterPort; CFMutableDictionaryRef classesToMatch; io_iterator_t serialPortIterator; if (IOMasterPort(NULL, &masterPort) != KERN_SUCCESS) return list; // a usb-serial adaptor is usually considered a "modem", // especially when it implements the CDC class spec classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); if (!classesToMatch) return list; CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDModemType)); if (IOServiceGetMatchingServices(masterPort, classesToMatch, &serialPortIterator) != KERN_SUCCESS) return list; macos_ports(&serialPortIterator, list); IOObjectRelease(serialPortIterator); // but it might be considered a "rs232 port", so repeat this // search for rs232 ports classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); if (!classesToMatch) return list; CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDRS232Type)); if (IOServiceGetMatchingServices(masterPort, classesToMatch, &serialPortIterator) != KERN_SUCCESS) return list; macos_ports(&serialPortIterator, list); IOObjectRelease(serialPortIterator); #elif defined(WINDOWS) // http://msdn.microsoft.com/en-us/library/aa365461(VS.85).aspx // page with 7 ways - not all of them work! // http://www.naughter.com/enumser.html // may be possible to just query the windows registary // http://it.gps678.com/2/ca9c8631868fdd65.html // search in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM // Vista has some special new way, vista-only // http://msdn2.microsoft.com/en-us/library/aa814070(VS.85).aspx char *buffer, *p; //DWORD size = QUERYDOSDEVICE_BUFFER_SIZE; DWORD ret; buffer = (char *)malloc(QUERYDOSDEVICE_BUFFER_SIZE); if (buffer == NULL) return list; memset(buffer, 0, QUERYDOSDEVICE_BUFFER_SIZE); ret = QueryDosDeviceA(NULL, buffer, QUERYDOSDEVICE_BUFFER_SIZE); if (ret) { printf("Detect Serial using QueryDosDeviceA: "); for (p = buffer; *p; p += strlen(p) + 1) { printf(": %s", p); if (strncmp(p, "COM", 3)) continue; list.Add(wxString(p) + ":"); } } else { char buf[1024]; win32_err(buf); printf("QueryDosDeviceA failed, error \"%s\"\n", buf); printf("Detect Serial using brute force GetDefaultCommConfig probing: "); for (int i=1; i<=32; i++) { printf("try %s", buf); COMMCONFIG cfg; DWORD len; snprintf(buf, sizeof(buf), "COM%d", i); if (GetDefaultCommConfig(buf, &cfg, &len)) { wxString name; name.Printf("COM%d:", i); list.Add(name); printf(": %s", buf); } } } free(buffer); #endif list.Sort(); return list; }
wxArrayString *EnumerateSerialPorts(void) { wxArrayString *preturn = new wxArrayString; #ifdef __WXGTK__ // Looking for user privilege openable devices in /dev wxString sdev; for(int idev=0 ; idev < 8 ; idev++) { sdev.Printf(_T("/dev/ttyS%1d"), idev); int fd = open(sdev.mb_str(), O_RDWR|O_NDELAY|O_NOCTTY); if(fd > 0) { /* add to the output array */ preturn->Add(wxString(sdev)); close(fd); } } for(int idev=0 ; idev < 8 ; idev++) { sdev.Printf(_T("/dev/ttyUSB%1d"), idev); int fd = open(sdev.mb_str(), O_RDWR|O_NDELAY|O_NOCTTY); if(fd > 0) { /* add to the output array */ preturn->Add(wxString(sdev)); close(fd); } } // Looking for BlueTooth GPS devices for(int idev=0 ; idev < 8 ; idev++) { sdev.Printf(_T("/dev/rfcomm%1d"), idev); int fd = open(sdev.mb_str(), O_RDWR|O_NDELAY|O_NOCTTY); if(fd > 0) { /* add to the output array */ preturn->Add(wxString(sdev)); close(fd); } } // A Fallback position, in case udev has failed or something..... if(preturn->IsEmpty()) { preturn->Add( _T("/dev/ttyS0")); preturn->Add( _T("/dev/ttyS1")); preturn->Add( _T("/dev/ttyUSB0")); preturn->Add( _T("/dev/ttyUSB1")); } #endif #ifdef PROBE_PORTS__WITH_HELPER /* * For modern Linux/(Posix??) systems, we may use * the system files /proc/tty/driver/serial * and /proc/tty/driver/usbserial to identify * available serial ports. * A complicating factor is that most (all??) linux * systems require root privileges to access these files. * We will use a helper program method here, despite implied vulnerability. */ char buf[256]; // enough to hold one line from serial devices list char left_digit; char right_digit; int port_num; FILE *f; pid_t pID = vfork(); if (pID == 0) // child { // Temporarily gain root privileges seteuid(file_user_id); // Execute the helper program execlp("ocpnhelper", "ocpnhelper", "-SB", NULL); // Return to user privileges seteuid(user_user_id); wxLogMessage(_T("Warning: ocpnhelper failed....")); _exit(0); // If exec fails then exit forked process. } wait(NULL); // for the child to quit // Read and parse the files /* * see if we have any traditional ttySx ports available */ f = fopen("/var/tmp/serial", "r"); if (f != NULL) { wxLogMessage(_T("Parsing copy of /proc/tty/driver/serial...")); /* read in each line of the file */ while(fgets(buf, sizeof(buf), f) != NULL) { wxString sm(buf, wxConvUTF8); sm.Prepend(_T(" ")); sm.Replace(_T("\n"), _T(" ")); wxLogMessage(sm); /* if the line doesn't start with a number get the next line */ if (buf[0] < '0' || buf[0] > '9') continue; /* * convert digits to an int */ left_digit = buf[0]; right_digit = buf[1]; if (right_digit < '0' || right_digit > '9') port_num = left_digit - '0'; else port_num = (left_digit - '0') * 10 + right_digit - '0'; /* skip if "unknown" in the string */ if (strstr(buf, "unknown") != NULL) continue; /* upper limit of 15 */ if (port_num > 15) continue; /* create string from port_num */ wxString s; s.Printf(_T("/dev/ttyS%d"), port_num); /* add to the output array */ preturn->Add(wxString(s)); } fclose(f); } /* * Same for USB ports */ f = fopen("/var/tmp/usbserial", "r"); if (f != NULL) { wxLogMessage(_T("Parsing copy of /proc/tty/driver/usbserial...")); /* read in each line of the file */ while(fgets(buf, sizeof(buf), f) != NULL) { wxString sm(buf, wxConvUTF8); sm.Prepend(_T(" ")); sm.Replace(_T("\n"), _T(" ")); wxLogMessage(sm); /* if the line doesn't start with a number get the next line */ if (buf[0] < '0' || buf[0] > '9') continue; /* * convert digits to an int */ left_digit = buf[0]; right_digit = buf[1]; if (right_digit < '0' || right_digit > '9') port_num = left_digit - '0'; else port_num = (left_digit - '0') * 10 + right_digit - '0'; /* skip if "unknown" in the string */ if (strstr(buf, "unknown") != NULL) continue; /* upper limit of 15 */ if (port_num > 15) continue; /* create string from port_num */ wxString s; s.Printf(_T("/dev/ttyUSB%d"), port_num); /* add to the output array */ preturn->Add(wxString(s)); } fclose(f); } // As a fallback, in case seteuid doesn't work.... // provide some defaults // This is currently the case for GTK+, which // refuses to run suid. sigh... if(preturn->IsEmpty()) { preturn->Add( _T("/dev/ttyS0")); preturn->Add( _T("/dev/ttyS1")); preturn->Add( _T("/dev/ttyUSB0")); preturn->Add( _T("/dev/ttyUSB1")); } // Clean up the temporary files created by helper. pid_t cpID = vfork(); if (cpID == 0) // child { // Temporarily gain root privileges seteuid(file_user_id); // Execute the helper program execlp("ocpnhelper", "ocpnhelper", "-U", NULL); // Return to user privileges seteuid(user_user_id); _exit(0); // If exec fails then exit forked process. } #endif // __WXGTK__ #ifdef __WXOSX__ #include "macutils.h" char* paPortNames[MAX_SERIAL_PORTS] ; int iPortNameCount ; memset(paPortNames,0x00,sizeof(paPortNames)) ; iPortNameCount = FindSerialPortNames(&paPortNames[0],MAX_SERIAL_PORTS) ; for (int iPortIndex=0 ; iPortIndex<iPortNameCount ; iPortIndex++) { wxString sm(paPortNames[iPortIndex], wxConvUTF8); preturn->Add(sm); free(paPortNames[iPortIndex]) ; } #endif //__WXOSX__ #ifdef __WXMSW__ /************************************************************************* * Windows provides no system level enumeration of available serial ports * There are several ways of doing this. * *************************************************************************/ #include <windows.h> // Method 1: Use GetDefaultCommConfig() // Try first {g_nCOMPortCheck} possible COM ports, check for a default configuration for (int i=1; i<g_nCOMPortCheck; i++) { wxString s; s.Printf(_T("COM%d"), i); COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); if (GetDefaultCommConfig(s.fn_str(), &cc, &dwSize)) preturn->Add(wxString(s)); } #if 0 // Method 2: Use FileOpen() // Try all 255 possible COM ports, check to see if it can be opened, or if // not, that an expected error is returned. BOOL bFound; for (int j=1; j<256; j++) { char s[20]; sprintf(s, "\\\\.\\COM%d", j); // Open the port tentatively BOOL bSuccess = FALSE; HANDLE hComm = ::CreateFile(s, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); // Check for the error returns that indicate a port is there, but not currently useable if (hComm == INVALID_HANDLE_VALUE) { DWORD dwError = GetLastError(); if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE || dwError == ERROR_SHARING_VIOLATION || dwError == ERROR_SEM_TIMEOUT) bFound = TRUE; } else { bFound = TRUE; CloseHandle(hComm); } if (bFound) preturn->Add(wxString(s)); } #endif // Search for Garmin device driver on Windows platforms HDEVINFO hdeviceinfo = INVALID_HANDLE_VALUE; hdeviceinfo = SetupDiGetClassDevs( (GUID *) &GARMIN_DETECT_GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); if (hdeviceinfo != INVALID_HANDLE_VALUE) { wxLogMessage(_T("EnumerateSerialPorts() Found Garmin USB Driver.")); preturn->Add(_T("GARMIN")); // Add generic Garmin selectable device g_bGarminPersistance = true; // And record the existance } #if 0 SP_DEVICE_INTERFACE_DATA deviceinterface; deviceinterface.cbSize = sizeof(deviceinterface); if (SetupDiEnumDeviceInterfaces(hdeviceinfo, NULL, (GUID *) &GARMIN_DETECT_GUID, 0, &deviceinterface)) { wxLogMessage(_T("Found Garmin Device.")); preturn->Add(_T("GARMIN")); // Add generic Garmin selectable device g_bGarminPersistance = true; // And record the existance } #endif #endif //__WXMSW__ return preturn; }
int _init_uart(char* nm, char* speed) { char fullNm[20]; DCB dcb; DWORD dwErr; COMMTIMEOUTS tmo; COMSTAT comStat; COMMCONFIG ccfg; DWORD ccfgLen; int portNum = 0; char* scannm; char* shownm; char modemode; // skip COM if specified and scan number and mode (optional) scannm = strnicmp(nm, "COM", 3) ? nm : nm+3; sscanf(scannm, "%i%c%c", &portNum, &modemode, &serial_mode); if (modemode == '!') defaultyes = 1; // omit Yes/No before programming // port number specified ? if(portNum) { sprintf(fullNm, "\\\\.\\COM%d", portNum); nm = fullNm; } // name to show in error messages shownm = nm; // do not show backslashes in error message if(!strncmp(shownm, "\\\\.\\", 4)) shownm += 4; // try not to make pulse on DTR line during open ccfgLen = sizeof(ccfg); if(GetDefaultCommConfig(shownm, &ccfg, &ccfgLen)) { ccfg.dcb.fDtrControl = DTR_CONTROL_DISABLE; if(!SetDefaultCommConfig(shownm, &ccfg, ccfgLen)) fprintf(logfile, "Warning: can not preset default comm config (%s)\n", shownm); } //else //fprintf(logfile, "Warning: can not get default comm config (%s)\n", shownm); // open port port = CreateFile(nm, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(port == INVALID_HANDLE_VALUE) { //fprintf(logfile, "Can't open serial port %s\n", shownm); return -1; } // init queues PurgeComm(port, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR); // prepare DCB dcb.DCBlength = sizeof(dcb); // sizeof(DCB) dcb.BaudRate = CBR_9600; // current baud rate dcb.fBinary = TRUE; // binary mode, no EOF check dcb.fParity = FALSE; // disable parity checking dcb.fOutxCtsFlow = FALSE; // CTS output flow control dcb.fOutxDsrFlow = FALSE; // DSR output flow control dcb.fDtrControl = DTR_CONTROL_DISABLE; // DTR flow control type dcb.fDsrSensitivity = FALSE; // DSR sensitivity dcb.fTXContinueOnXoff = FALSE; // XOFF continues Tx dcb.fOutX = FALSE; // XON/XOFF out flow control dcb.fInX = FALSE; // XON/XOFF in flow control dcb.fErrorChar = FALSE; // enable error replacement dcb.fNull = FALSE; // enable null stripping dcb.fRtsControl = RTS_CONTROL_ENABLE; // RTS flow control dcb.fAbortOnError = FALSE; // abort reads/writes on error dcb.XonLim = 100; // transmit XON threshold dcb.XoffLim = 100; // transmit XOFF threshold dcb.ByteSize = 8; // number of bits/, 4-8 dcb.Parity = NOPARITY; // 0-4=no,odd,even,mark,space dcb.StopBits = ONESTOPBIT; // 0,1,2 = 1, 1.5, 2 dcb.XonChar = 17; // Tx and Rx XON acter dcb.XoffChar = 19; // Tx and Rx XOFF acter dcb.ErrorChar = 0; // error replacement acter dcb.EofChar = 0; // end of input acter dcb.EvtChar = 0; // received event acter // speed string specified ? if(speed) { if(sscanf(speed, "%lu", &dcb.BaudRate) != 1) { fprintf(logfile, "Invalid speed specified (%s)\n", speed); return -1; } } if(!SetCommState(port, &dcb)) { fprintf(logfile, "Can't setup serial port (%s @ %s)\n", shownm, speed); return -1; } if(!SetupComm(port, 512, 512)) { fprintf(logfile, "Can't setup serial port queues.\n"); return -1; } tmo.ReadIntervalTimeout = 100; // between two characters tmo.ReadTotalTimeoutMultiplier = 1; tmo.ReadTotalTimeoutConstant = 500; tmo.WriteTotalTimeoutMultiplier = 1; tmo.WriteTotalTimeoutConstant = 1000; if(!SetCommTimeouts(port, &tmo)) { fprintf(logfile, "Can't set serial port timeouts (%s)\n", shownm); return -1; } if(!SetCommMask(port, EV_TXEMPTY)) { fprintf(logfile, "Can't set serial port waitmask (%s)\n", shownm); return -1; } // we are ready ! EscapeCommFunction(port, CLRDTR); ClearCommError(port, &dwErr, &comStat); return 1; }
std::vector<std::string> GetSerialPorts(bool &bUseDirectPath) { bUseDirectPath=false; std::vector<std::string> ret; #if defined WIN32 //windows COMMCONFIG cc; DWORD dwSize = sizeof(COMMCONFIG); char szPortName[40]; for (int ii=0; ii<256; ii++) { sprintf(szPortName,"COM%d",ii); if (GetDefaultCommConfig(szPortName, &cc, &dwSize)) { sprintf(szPortName,"COM%d",ii); ret.push_back(szPortName); } } #else //scan /dev for /dev/ttyUSB* or /dev/ttyS* or /dev/tty.usbserial* or /dev/ttyAMA* bool bHaveTtyAMAfree=false; std::string sLine = ""; std::ifstream infile; infile.open("/boot/cmdline.txt"); if (infile.is_open()) { if (!infile.eof()) { getline(infile, sLine); bHaveTtyAMAfree=(sLine.find("ttyAMA0")==std::string::npos); } } DIR *d=NULL; d=opendir("/dev"); if (d != NULL) { struct dirent *de=NULL; // Loop while not NULL while ((de = readdir(d))) { std::string fname = de->d_name; if (fname.find("ttyUSB")!=std::string::npos) { ret.push_back("/dev/" + fname); } if (fname.find("tty.usbserial")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/" + fname); } if (bHaveTtyAMAfree) { if (fname.find("ttyAMA0")!=std::string::npos) { ret.push_back("/dev/" + fname); bUseDirectPath=true; } } } closedir(d); } //also scan in /dev/usb d=opendir("/dev/usb"); if (d != NULL) { struct dirent *de=NULL; // Loop while not NULL while ((de = readdir(d))) { std::string fname = de->d_name; if (fname.find("ttyUSB")!=std::string::npos) { bUseDirectPath=true; ret.push_back("/dev/usb/" + fname); } } closedir(d); } #endif return ret; }
int ArduinoSerial::openPort(const char *portName) { _portName = std::string(portName); _portOpened = false; triedToConfigureAgain = false; closeSerial(); fd = 0; _numberOfChannels = 1; #if defined(__APPLE__) || defined(__linux__) struct termios options; fd = open(portName, O_RDWR | O_NOCTTY | O_NDELAY);//O_SHLOCK sleep(2); int bits; #endif #ifdef __APPLE__ std::stringstream sstm; if (fd < 0) { sstm << "Unable to open " << portName << ", " << strerror(errno); errorString = sstm.str(); std::cout<<"Unable to open "<<portName<<", "<<strerror(errno)<<"\n"; return -1; } if (ioctl(fd, TIOCEXCL) == -1) { close(fd); sstm << "Unable to get exclussive access to port " << portName;; errorString = sstm.str(); std::cout<<"Unable to get exclussive access to port "<<portName<<"\n"; return -1; } if (ioctl(fd, TIOCMGET, &bits) < 0) { close(fd); sstm <<"Unable to query serial port signals on " << portName; errorString = sstm.str(); std::cout<<"Unable to query serial port signals on "<<portName<<"\n"; return -1; } bits &= ~(TIOCM_DTR | TIOCM_RTS); if (ioctl(fd, TIOCMSET, &bits) < 0) { close(fd); sstm <<"Unable to control serial port signals on " << portName; errorString = sstm.str(); std::cout<<"Unable to control serial port signals on "<<portName<<"\n"; return -1; } struct termios settings_orig; if (tcgetattr(fd, &settings_orig) < 0) { close(fd); sstm <<"Unable to access baud rate on port " << portName; errorString = sstm.str(); std::cout<<"Unable to access baud rate on port "<<portName<<"\n"; return -1; } #endif #ifdef __linux__ // struct serial_struct kernel_serial_settings; struct termios settings_orig; //struct termios settings; if (fd < 0) { if (errno == EACCES) { std::cout<<"Unable to access "<< portName<< ", insufficient permission"; // TODO: we could look at the permission bits and owner // to make a better message here } else if (errno == EISDIR) { std::cout<< "Unable to open " << portName << ", Object is a directory, not a serial port"; } else if (errno == ENODEV || errno == ENXIO) { std::cout<< "Unable to open " << portName << ", Serial port hardware not installed"; } else if (errno == ENOENT) { std::cout<< "Unable to open " << portName << ", Device name does not exist"; } else { std::cout<< "Unable to open " << portName; //<< } return -1; } if (ioctl(fd, TIOCMGET, &bits) < 0) { close(fd); std::cout<< "Unable to query serial port signals"; return -1; } bits &= ~(TIOCM_DTR | TIOCM_RTS); if (ioctl(fd, TIOCMSET, &bits) < 0) { close(fd); std::cout<< "Unable to control serial port signals"; return -1; } if (tcgetattr(fd, &settings_orig) != 0) { close(fd); std::cout<< "Unable to query serial port settings (perhaps not a serial port)"; return -1; } /*memset(&settings, 0, sizeof(settings)); settings.c_iflag = IGNBRK | IGNPAR; settings.c_cflag = CS8 | CREAD | HUPCL | CLOCAL; Set_baud(baud_rate); if (ioctl(port_fd, TIOCGSERIAL, &kernel_serial_settings) == 0) { kernel_serial_settings.flags |= ASYNC_LOW_LATENCY; ioctl(port_fd, TIOCSSERIAL, &kernel_serial_settings); } tcflush(port_fd, TCIFLUSH);*/ #endif #if defined(__APPLE__) || defined(__linux__) if (fd == -1) { std::cout<<"Can't open serial port\n"; return -1; } fcntl(fd, F_SETFL, 0); // clear all flags on descriptor, enable direct I/O tcgetattr(fd, &options); // read serial port options // enable receiver, set 8 bit data, ignore control lines options.c_cflag |= (CLOCAL | CREAD | CS8); // disable parity generation and 2 stop bits options.c_cflag &= ~(PARENB | CSTOPB); //cfsetispeed(&options, B9600); //cfsetospeed(&options, B9600); cfsetispeed(&options, B230400); cfsetospeed(&options, B230400); // set the new port options tcsetattr(fd, TCSANOW, &options); #endif #ifdef _WIN32 COMMCONFIG cfg; COMMTIMEOUTS timeouts; int got_default_cfg=0, port_num; char buf[1024], name_createfile[64], name_commconfig[64], *p; DWORD len; snprintf(buf, sizeof(buf), "%s", _portName.c_str()); p = strstr(buf, "COM"); if (p && sscanf(p + 3, "%d", &port_num) == 1) { printf("port_num = %d\n", port_num); snprintf(name_createfile, sizeof(name_createfile), "\\\\.\\COM%d", port_num); snprintf(name_commconfig, sizeof(name_commconfig), "COM%d", port_num); } else { snprintf(name_createfile, sizeof(name_createfile), "%s", _portName.c_str()); snprintf(name_commconfig, sizeof(name_commconfig), "%s", _portName.c_str()); } len = sizeof(COMMCONFIG); if (GetDefaultCommConfig(name_commconfig, &cfg, &len)) { // this prevents unintentionally raising DTR when opening // might only work on COM1 to COM9 got_default_cfg = 1; memcpy(&port_cfg_orig, &cfg, sizeof(COMMCONFIG)); cfg.dcb.fDtrControl = DTR_CONTROL_DISABLE; cfg.dcb.fRtsControl = RTS_CONTROL_DISABLE; SetDefaultCommConfig(name_commconfig, &cfg, sizeof(COMMCONFIG)); } else { printf("error with GetDefaultCommConfig\n"); } port_handle = CreateFile(name_createfile, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (port_handle == INVALID_HANDLE_VALUE) { win32_err(buf); //error_msg = "Unable to open " + _portName + ", " + buf; return -1; } len = sizeof(COMMCONFIG); if (!GetCommConfig(port_handle, &port_cfg, &len)) { CloseHandle(port_handle); win32_err(buf); //error_msg = "Unable to read communication config on " + _portName + ", " + buf; return -1; } if (!got_default_cfg) { memcpy(&port_cfg_orig, &port_cfg, sizeof(COMMCONFIG)); } // http://msdn2.microsoft.com/en-us/library/aa363188(VS.85).aspx port_cfg.dcb.BaudRate = 230400; port_cfg.dcb.fBinary = TRUE; port_cfg.dcb.fParity = FALSE; port_cfg.dcb.fOutxCtsFlow = FALSE; port_cfg.dcb.fOutxDsrFlow = FALSE; port_cfg.dcb.fDtrControl = DTR_CONTROL_DISABLE; port_cfg.dcb.fDsrSensitivity = FALSE; port_cfg.dcb.fTXContinueOnXoff = TRUE; // ??? port_cfg.dcb.fOutX = FALSE; port_cfg.dcb.fInX = FALSE; port_cfg.dcb.fErrorChar = FALSE; port_cfg.dcb.fNull = FALSE; port_cfg.dcb.fRtsControl = RTS_CONTROL_DISABLE; port_cfg.dcb.fAbortOnError = FALSE; port_cfg.dcb.ByteSize = 8; port_cfg.dcb.Parity = NOPARITY; port_cfg.dcb.StopBits = ONESTOPBIT; if (!SetCommConfig(port_handle, &port_cfg, sizeof(COMMCONFIG))) { CloseHandle(port_handle); win32_err(buf); //error_msg = "Unable to write communication config to " + name + ", " + buf; return -1; } if (!EscapeCommFunction(port_handle, CLRDTR | CLRRTS)) { CloseHandle(port_handle); win32_err(buf); //error_msg = "Unable to control serial port signals on " + name + ", " + buf; return -1; } // http://msdn2.microsoft.com/en-us/library/aa363190(VS.85).aspx // setting to all zeros means timeouts are not used //timeouts.ReadIntervalTimeout = 0; timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadTotalTimeoutMultiplier = 0; timeouts.ReadTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutConstant = 0; if (!SetCommTimeouts(port_handle, &timeouts)) { CloseHandle(port_handle); win32_err(buf); //error_msg = "Unable to write timeout settings to " + name + ", " + buf; return -1; } #endif // _WIN32 circularBuffer[0] = '\n'; cBufHead = 0; cBufTail = 0; serialCounter = 0; _portOpened = true; setNumberOfChannelsAndSamplingRate(1, maxSamplingRate()); return fd; }
void ModelViewController::DetectComPorts(bool init) { bool bDirty = init; vector<std::string> currentComports; #ifdef WIN32 int highestCom = 0; for(int i = 1; i <=9 ; i++ ) { TCHAR strPort[32] = {0}; _stprintf(strPort, _T("COM%d"), i); DWORD dwSize = 0; LPCOMMCONFIG lpCC = (LPCOMMCONFIG) new BYTE[1]; GetDefaultCommConfig(strPort, lpCC, &dwSize); int r = GetLastError(); delete [] lpCC; lpCC = (LPCOMMCONFIG) new BYTE[dwSize]; GetDefaultCommConfig(strPort, lpCC, &dwSize); delete [] lpCC; if( r != 87 ) { ToolkitLock guard; highestCom = i; if( this ) // oups extremely ugly, should move this code to a static method and a callback { const_cast<Fl_Menu_Item*>(gui->portInput->menu())[i-1].activate(); const_cast<Fl_Menu_Item*>(gui->portInputSimple->menu())[i-1].activate(); } } else { ToolkitLock guard; if( this ) // oups extremely ugly, should move this code to a static method and a callback { const_cast<Fl_Menu_Item*>(gui->portInput->menu())[i-1].deactivate(); const_cast<Fl_Menu_Item*>(gui->portInputSimple->menu())[i-1].deactivate(); } } } currentComports.push_back(string("COM"+highestCom)); #elif defined(__APPLE__) const char *ttyPattern[] = {"tty.", NULL}; #else // Linux const char *ttyPattern[] = {"ttyUSB", "ttyACM", NULL}; #endif #ifndef WIN32 DIR *d = opendir ("/dev"); if (d) { // failed struct dirent *e; while ((e = readdir (d))) { //fprintf (stderr, "name '%s'\n", e->d_name); for (const char **ttyPidx = ttyPattern; *ttyPidx != NULL; ++ttyPidx) { if (strstr(e->d_name,*ttyPidx)) { string device = string("/dev/") + e->d_name; currentComports.push_back(device); } } } closedir(d); if ( currentComports.size() != this->comports.size() ) bDirty = true; } if ( bDirty && gui) { ToolkitLock guard; static Fl_Menu_Item emptyList[] = { {0,0,0,0,0,0,0,0,0} }; bool bWasEmpty = !comports.size(); gui->portInputSimple->menu(emptyList); gui->portInput->menu(emptyList); comports.clear(); for (size_t indx = 0; indx < currentComports.size(); ++indx) { string menuLabel = string(currentComports[indx]); gui->portInput->add(strdup(menuLabel.c_str())); gui->portInputSimple->add(strdup(menuLabel.c_str())); comports.push_back(currentComports[indx]); } // auto-select a new com-port if (bWasEmpty && comports.size()) { ProcessControl.m_sPortName = ValidateComPort(comports[0]); CopySettingsToGUI(); } } #endif }
int fb_SerialOpen( FB_FILE *handle, int iPort, FB_SERIAL_OPTIONS *options, const char *pszDevice, void **ppvHandle ) { DWORD dwDefaultTxBufferSize = 16384; DWORD dwDefaultRxBufferSize = 16384; DWORD dwDesiredAccess = 0; DWORD dwShareMode = 0; char *pszDev, *p; HANDLE hDevice; int res; /* The IRQ stuff is not supported on Windows ... */ if( options->IRQNumber!=0 ) return fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); res = fb_ErrorSetNum( FB_RTERROR_OK ); switch( handle->access ) { case FB_FILE_ACCESS_READ: dwDesiredAccess = GENERIC_READ; break; case FB_FILE_ACCESS_WRITE: dwDesiredAccess = GENERIC_WRITE; break; case FB_FILE_ACCESS_READWRITE: case FB_FILE_ACCESS_ANY: dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; break; } switch( handle->lock ) { case FB_FILE_LOCK_SHARED: dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; break; case FB_FILE_LOCK_READ: dwShareMode = FILE_SHARE_WRITE; break; case FB_FILE_LOCK_WRITE: dwShareMode = FILE_SHARE_READ; break; case FB_FILE_LOCK_READWRITE: break; } /* Get device name without ":" */ pszDev = calloc(strlen( pszDevice ) + 5, 1); if( iPort == 0 ) { iPort = 1; strcpy( pszDev, "COM1:" ); } else { if( iPort > 9 ) strcpy(pszDev, "\\\\.\\"); else *pszDev = '\0'; strcat(pszDev, pszDevice); p = strchr( pszDev, ':'); if( p ) *p = '\0'; } #if 0 /* FIXME: Use default COM properties by default */ COMMCONFIG cc; if( !GetDefaultCommConfig( pszDev, &cc, &dwSizeCC ) ) { } #endif /* Open device */ hDevice = CreateFileA( pszDev, dwDesiredAccess, dwShareMode, NULL, OPEN_EXISTING, 0, NULL ); free( pszDev ); if( hDevice==INVALID_HANDLE_VALUE ) return fb_ErrorSetNum( FB_RTERROR_FILENOTFOUND ); /* Set rx/tx buffer sizes */ if( res==FB_RTERROR_OK ) { COMMPROP prop; if( !GetCommProperties( hDevice, &prop ) ) { res = fb_ErrorSetNum( FB_RTERROR_NOPRIVILEDGES ); } else { if( prop.dwCurrentTxQueue ) { dwDefaultTxBufferSize = prop.dwCurrentTxQueue; } else if( prop.dwMaxTxQueue ) { dwDefaultTxBufferSize = prop.dwMaxTxQueue; } if( prop.dwCurrentRxQueue ) { dwDefaultRxBufferSize = prop.dwCurrentRxQueue; } else if( prop.dwMaxRxQueue ) { dwDefaultRxBufferSize = prop.dwMaxRxQueue; } if( options->TransmitBuffer ) dwDefaultTxBufferSize = options->TransmitBuffer; if( options->ReceiveBuffer ) dwDefaultRxBufferSize = options->ReceiveBuffer; if( !SetupComm( hDevice, dwDefaultRxBufferSize, dwDefaultTxBufferSize ) ) { res = fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } } } /* set timeouts */ if( res==FB_RTERROR_OK ) { COMMTIMEOUTS timeouts; if( !GetCommTimeouts( hDevice, &timeouts ) ) { res = fb_ErrorSetNum( FB_RTERROR_NOPRIVILEDGES ); } else { if( options->DurationCTS!=0 ) { timeouts.ReadIntervalTimeout = options->DurationCTS; timeouts.ReadTotalTimeoutMultiplier = timeouts.ReadTotalTimeoutConstant = 0; } if( !SetCommTimeouts( hDevice, &timeouts ) ) { res = fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } } } /* setup generic COM port configuration */ if( res==FB_RTERROR_OK ) { DCB dcb; if( !GetCommState( hDevice, &dcb ) ) { res = fb_ErrorSetNum( FB_RTERROR_NOPRIVILEDGES ); } else { dcb.BaudRate = options->uiSpeed; dcb.fBinary = !options->AddLF; /* FIXME: Windows only supports binary mode */ dcb.fParity = options->CheckParity; dcb.fOutxCtsFlow = options->DurationCTS!=0; dcb.fDtrControl = ( (options->KeepDTREnabled) ? DTR_CONTROL_ENABLE : DTR_CONTROL_DISABLE ); /* Not sure about this one ... */ dcb.fDsrSensitivity = options->DurationDSR!=0; dcb.fOutxDsrFlow = FALSE; /* No XON/XOFF */ dcb.fOutX = FALSE; dcb.fInX = FALSE; dcb.fNull = FALSE; /* Not sure about this one ... */ dcb.fRtsControl = ( ( options->SuppressRTS ) ? RTS_CONTROL_DISABLE : RTS_CONTROL_HANDSHAKE ); dcb.fAbortOnError = FALSE; dcb.ByteSize = (BYTE) options->uiDataBits; switch ( options->Parity ) { case FB_SERIAL_PARITY_NONE: dcb.Parity = NOPARITY; break; case FB_SERIAL_PARITY_EVEN: dcb.Parity = EVENPARITY; break; case FB_SERIAL_PARITY_ODD: dcb.Parity = ODDPARITY; break; case FB_SERIAL_PARITY_SPACE: dcb.Parity = SPACEPARITY; break; case FB_SERIAL_PARITY_MARK: dcb.Parity = MARKPARITY; break; } switch ( options->StopBits ) { case FB_SERIAL_STOP_BITS_1: dcb.StopBits = ONESTOPBIT; break; case FB_SERIAL_STOP_BITS_1_5: dcb.StopBits = ONE5STOPBITS; break; case FB_SERIAL_STOP_BITS_2: dcb.StopBits = TWOSTOPBITS; break; } if( !SetCommState( hDevice, &dcb ) ) { res = fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } else { EscapeCommFunction( hDevice, SETDTR ); } } } if( !fb_hSerialCheckLines( hDevice, options ) ) { res = fb_ErrorSetNum( FB_RTERROR_ILLEGALFUNCTIONCALL ); } if( res!=FB_RTERROR_OK ) { CloseHandle( hDevice ); } else { W32_SERIAL_INFO *pInfo = calloc( 1, sizeof(W32_SERIAL_INFO) ); DBG_ASSERT( ppvHandle!=NULL ); *ppvHandle = pInfo; pInfo->hDevice = hDevice; pInfo->iPort = iPort; pInfo->pOptions = options; } return res; }