📄 serialio-posix.cpp
字号:
/* * Roadnav * SerialIO-POSIX.cpp * * Copyright (c) 2004 - 2007 Richard L. Lynch <rllynch@users.sourceforge.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ ///////////////////////////////////////////////////////////////////////////////// \file////// Serial support functions for POSIX compliant OSes.////// Works under Linux, also reported to work under Mac OSX./////////////////////////////////////////////////////////////////////////////////#ifdef HAVE_CONFIG_H# include <config.h>#endif#include <wx/wx.h>#include "libroadnav/Debug.h"#include "SerialIO.h"#include "App.h"#if defined(__LINUX__) || defined(__DARWIN__) || defined(__FREEBSD__) || defined(__SUN__)#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_TERMIOS_H#include <termios.h>#endif#ifdef HAVE_DIRENT_H#include <dirent.h>#endif#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif#ifdef HAVE_SYS_FCNTL_H#include <sys/fcntl.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endifstatic int g_hCom = -1;static wxString g_strSerialError;#if defined(__DARWIN__) && defined(HAVE_IOKIT_IOBSD_H) && defined(HAVE_IOKIT_IOKITLIB_H) && defined(HAVE_IOKIT_SERIAL_IOSERIALKEYS_H) && defined(HAVE_COREFOUNDATION_COREFOUNDATION_H)#define USE_IOKIT#endif#ifdef USE_IOKIT#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <errno.h>#include <paths.h>#include <termios.h>#include <sysexits.h>#include <sys/param.h>#include <sys/select.h>#include <sys/time.h>#include <time.h>#include <CoreFoundation/CoreFoundation.h>#include <IOKit/IOKitLib.h>#include <IOKit/serial/IOSerialKeys.h>#include <IOKit/IOBSD.h>bool MakeOSXSerialEnumerator(io_iterator_t * matchingServices){ kern_return_t kernResult; mach_port_t masterPort; CFMutableDictionaryRef classesToMatch; kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); if (KERN_SUCCESS != kernResult) return true; // Serial devices are instances of class IOSerialBSDClient. classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); if (classesToMatch != NULL) CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), CFSTR(kIOSerialBSDAllTypes)); kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, matchingServices); if (KERN_SUCCESS != kernResult) return true; return false;}bool EnumerateOSXSerialPort(io_iterator_t serialPortIterator, int iDesiredPort, char * deviceFilePath, CFIndex maxPathSize){ io_object_t modemService; int iCurrentPort = 0; // Initialize the returned path *deviceFilePath = 0; // Iterate across all modems found. while ((modemService = IOIteratorNext(serialPortIterator))) { CFTypeRef deviceFilePathAsCFString; deviceFilePathAsCFString = IORegistryEntryCreateCFProperty(modemService, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0); if (deviceFilePathAsCFString) { Boolean result; result = CFStringGetCString((CFStringRef) deviceFilePathAsCFString, deviceFilePath, maxPathSize, kCFStringEncodingASCII); CFRelease(deviceFilePathAsCFString); if (result) { // conversion successful if (strcmp(deviceFilePath, "/dev/cu.modem")) { // it's not cu.modem if (iCurrentPort == iDesiredPort) return false; iCurrentPort++; } } } IOObjectRelease(modemService); } return true;}#endifwxString GetLastSerialIOError(){ return g_strSerialError;}//////////////////////////////////////////////////////////////////////////////////// \brief Get the name of the nth serial port in the computer/////////////////////////////////////////////////////////////////////////////////wxString EnumSerialPort(int n){#ifdef USE_IOKIT io_iterator_t serialPortIterator; char deviceFilePath[MAXPATHLEN]; if (!MakeOSXSerialEnumerator(&serialPortIterator)) { if (!EnumerateOSXSerialPort(serialPortIterator, n, deviceFilePath, sizeof(deviceFilePath))) { return wxString(deviceFilePath, *wxConvCurrent); } IOObjectRelease(serialPortIterator); // Release the iterator. } return wxT("");#else struct dirent ** sdNameList; int nNameList; // get list of files // can't use wxDir since it doesn't understand virtual filesystems under OSX. nNameList = scandir("/dev", &sdNameList, NULL, NULL); if (nNameList > 0) { // current entry in list int iEntry = 0; // number of viable entries seen int iCount = 0; for (iEntry = 0; iEntry < nNameList; iEntry++) { int hCom; bool bFileNameOkay = false; // ensure the filename looks right#if defined(__DARWIN__) if (!strncmp(sdNameList[iEntry]->d_name, "cu.", 3)) bFileNameOkay = true; // Don't list the modem if (!strcmp(sdNameList[iEntry]->d_name, "cu.modem")) bFileNameOkay = false; #else if (!strncmp(sdNameList[iEntry]->d_name, "ttyS", 4)) bFileNameOkay = true; if (!strncmp(sdNameList[iEntry]->d_name, "ttyUSB", 6)) bFileNameOkay = true;#endif if (bFileNameOkay) { char szFullFileName[256]; *szFullFileName = 0; if (strlen(sdNameList[iEntry]->d_name) < 250) { sprintf(szFullFileName, "/dev/%s", sdNameList[iEntry]->d_name); // try to open hCom = open(szFullFileName, O_RDWR); if (hCom >= 0) { struct termios sPTS; // can we get its attributes? if (!tcgetattr(hCom, &sPTS)) { // looks good then iCount++; // is this the one? if (iCount > n) { // yes, store name int iFreeEntry; wxString strRtn = wxString(szFullFileName, *wxConvCurrent); // free the results from scandir for (iFreeEntry = 0; iFreeEntry < nNameList; iFreeEntry++) free(sdNameList[iFreeEntry]); free(sdNameList); // close the file close(hCom); return strRtn; } } close(hCom); } } } } // free the results from scandir int iFreeEntry; for (iFreeEntry = 0; iFreeEntry < nNameList; iFreeEntry++) free(sdNameList[iFreeEntry]); free(sdNameList); } return wxT("");#endif}//////////////////////////////////////////////////////////////////////////////////// \brief Initialize serial port (Linux)/////////////////////////////////////////////////////////////////////////////////bool InitSerialIO(){ struct termios sPTS; wxString strPort; int sbBaudRate; int iBaudRate; LibRoadnavDebug0(wxT("SerialIO"), wxT("Initializing")); g_pConfig->Read(wxT("GPSSerialPort"), &strPort, wxT("")); g_pConfig->Read(wxT("GPSBaudRate"), &iBaudRate, 4800); switch (iBaudRate) { case 1200: sbBaudRate = B1200; break; case 2400: sbBaudRate = B2400; break; case 4800: sbBaudRate = B4800; break; case 9600: sbBaudRate = B9600; break; case 19200: sbBaudRate = B19200; break; case 38400: sbBaudRate = B38400; break; default: iBaudRate = 0; sbBaudRate = 0; } if (strPort == wxT("") || iBaudRate <= 0) { LibRoadnavDebug2(wxT("SerialIO"), wxT("Input parameters invalid (%s, %d)"), strPort.c_str(), iBaudRate); g_strSerialError = wxT("Invalid serial port or baud rate"); g_hCom = -1; return true; } LibRoadnavDebug2(wxT("SerialIO"), wxT("Trying to open %s at %d"), strPort.c_str(), iBaudRate); g_hCom = open(strPort.mb_str(*wxConvCurrent), O_RDWR); if (g_hCom < 0) { g_strSerialError = wxString(strerror(errno), *wxConvCurrent); LibRoadnavDebug2(wxT("SerialIO"), wxT("Error opening %s: %s"), strPort.c_str(), g_strSerialError.c_str()); return true; } tcgetattr(g_hCom, &sPTS); cfsetospeed(&sPTS, sbBaudRate); cfsetispeed(&sPTS, sbBaudRate); tcsetattr(g_hCom, TCSANOW, &sPTS); fcntl(g_hCom, F_SETFL, O_NONBLOCK); return false;}//////////////////////////////////////////////////////////////////////////////////// \brief Read up to nBuffer bytes into szBuffer (Linux).////// Should block if nothing is available, and return as soon as anything is/// available./////////////////////////////////////////////////////////////////////////////////int ReadSerial(char * szBuffer, int nBuffer){ int n; LibRoadnavDebug1(wxT("SerialIO"), wxT("Trying to read %d bytes"), nBuffer); if (g_hCom < 0) { LibRoadnavDebug0(wxT("SerialIO"), wxT("Invalid handle")); wxThread::Sleep(1000); *szBuffer = 0; return 0; } n = read(g_hCom, szBuffer, nBuffer - 1); LibRoadnavDebug1(wxT("SerialIO"), wxT("Got %d bytes"), n); if (n < 0) { g_strSerialError = wxString(strerror(errno), *wxConvCurrent); LibRoadnavDebug1(wxT("SerialIO"), wxT("Error reading: %s"), g_strSerialError.c_str()); n = 0; wxThread::Sleep(100); } szBuffer[n] = 0; return n;}//////////////////////////////////////////////////////////////////////////////////// \brief Clean up serial stuff (Linux)/////////////////////////////////////////////////////////////////////////////////bool ShutdownSerialIO(){ LibRoadnavDebug0(wxT("SerialIO"), wxT("Shutting down")); if (g_hCom >= 0) { close(g_hCom); g_hCom = -1; } return false;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -