def Close(self): """Closes the serial port and stops all event processing.""" self.keepAlive = False SetEvent(self.stopEvent) if currentThread() != self: self.join(1.0) if self.hFile: #Restore original timeout values: SetCommTimeouts(self.hFile, self.oldCommTimeouts) #Close COM-Port: if not self._CloseHandle(self.hFile): self.hFile = None raise SerialError()
def Open(self, port=0, baudrate=9600, mode="8N1"): """ Opens the serial port. After the port is opened, you have to call :meth:`Start` to start the actual event processing of this class. :Arguments: port The port to open as an integer starting at one (0 = COM1) baudrate The baudrate to use as an integer. Defaults to 9600. mode The serial port mode settings to use. This should be a string created by the joining of the following parts: #. byte size '5', '6', '7' or '8' #. parity mode * 'N' for no parity, * 'E' for even parity, * 'O' for odd parity, * 'M' for mark parity, * 'S' for space parity #. stop bits * '1' for one stop bit * '1.5' for one and a half stop bit * '2' for two stop bits Example values: '8N1' (default), '8E1', '7N1.5' """ #the "//./COMx" format is required for devices >= 9 #not all versions of windows seem to support this properly #so that the first few ports are used with the DOS device name if port < 9: deviceStr = 'COM%d' % (port + 1) else: deviceStr = '\\\\.\\COM%d' % (port + 1) try: self.hFile = self._CreateFile( deviceStr, GENERIC_READ | GENERIC_WRITE, 0, # exclusive access None, # default security attributes OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0) except Exception: self.hFile = None # cause __del__ is called anyway raise eg.Exceptions.SerialOpenFailed() if self.hFile == INVALID_HANDLE_VALUE: self.hFile = None raise eg.Exceptions.SerialOpenFailed() dcb = self.dcb GetCommState(self.hFile, byref(dcb)) dcb.fBinary = True dcb.fParity = False dcb.fOutxCtsFlow = False dcb.fOutxDsrFlow = False dcb.fDtrControl = DTR_CONTROL_DISABLE dcb.fDsrSensitivity = False dcb.fTXContinueOnXoff = True dcb.fOutX = False dcb.fInX = False dcb.fErrorChar = False dcb.fNull = False dcb.fRtsControl = False dcb.fAbortOnError = False dcb.BaudRate = baudrate dcb.ByteSize = int(mode[0]) dcb.Parity = PARITY_S2V_DICT[mode[1].upper()] dcb.StopBits = STOPBITS_S2V_DICT[mode[2:]] SetCommState(self.hFile, byref(dcb)) GetCommTimeouts(self.hFile, byref(self.oldCommTimeouts)) commTimeouts = COMMTIMEOUTS(0, 0, 0, 100, 100) SetCommTimeouts(self.hFile, byref(commTimeouts))
class SerialThread(Thread): """ Eased handling of serial port communication. """ # These functions are bound to the class, so instances or subclasses # can replace them. This is needed for code that uses the FTDI.DLL # driver for example. _ReadFile = ReadFile _WriteFile = WriteFile _ClearCommError = ClearCommError _CreateFile = CreateFile _CloseHandle = CloseHandle # Cache list for GetAllPorts _serialPortList = None SerialError = SerialError @classmethod def GetAllPorts(cls): """ Returns a list with all available serial ports. """ serialPortList = cls._serialPortList if serialPortList is not None: return serialPortList serialPortList = [] commconfig = COMMCONFIG() commconfig.dwSize = sizeof(COMMCONFIG) lpCC = pointer(commconfig) dwSize = DWORD(0) lpdwSize = byref(dwSize) for i in range(0, 255): name = 'COM%d' % (i+1) res = GetDefaultCommConfig(name, lpCC, lpdwSize) if res == 1 or (res == 0 and GetLastError() == 122): serialPortList.append(i) cls._serialPortList = serialPortList return serialPortList def __init__(self, hFile=0): Thread.__init__(self, target=self.ReceiveThreadProc) self.hFile = int(hFile) self.osWriter = OVERLAPPED() self.osWriter.hEvent = CreateEvent(None, 0, 0, None) self.osReader = OVERLAPPED() self.osReader.hEvent = CreateEvent(None, 1, 0, None) self.dwRead = DWORD() self.comstat = COMSTAT() self.dcb = DCB() self.dcb.DCBlength = sizeof(DCB) self.oldCommTimeouts = COMMTIMEOUTS() self.readEventCallback = None self.readEventLock = Lock() self.readEventLock.acquire() self.readCondition = Condition() self.buffer = "" self.keepAlive = True self.stopEvent = CreateEvent(None, 1, 0, None) self.callbackThread = Thread( target=self.CallbackThreadProc, name="SerialReceiveThreadProc" ) def __enter__(self): self.SuspendReadEvents() return self def __exit__(self, dummyExcType, dummyExcValue, dummyTraceback): self.ResumeReadEvents() return False def Open(self, port=0, baudrate=9600, mode="8N1"): """ Opens the serial port. After the port is opened, you have to call :meth:`Start` to start the actual event processing of this class. :Arguments: port The port to open as an integer starting at one (0 = COM1) baudrate The baudrate to use as an integer. Defaults to 9600. mode The serial port mode settings to use. This should be a string created by the joining of the following parts: #. byte size '5', '6', '7' or '8' #. parity mode * 'N' for no parity, * 'E' for even parity, * 'O' for odd parity, * 'M' for mark parity, * 'S' for space parity #. stop bits * '1' for one stop bit * '1.5' for one and a half stop bit * '2' for two stop bits Example values: '8N1' (default), '8E1', '7N1.5' """ #the "//./COMx" format is required for devices >= 9 #not all versions of windows seem to support this properly #so that the first few ports are used with the DOS device name if port < 9: deviceStr = 'COM%d' % (port + 1) else: deviceStr = '\\\\.\\COM%d' % (port + 1) try: self.hFile = self._CreateFile( deviceStr, GENERIC_READ | GENERIC_WRITE, 0, # exclusive access None, # default security attributes OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0 ) except Exception, exc: self.hFile = None # cause __del__ is called anyway raise eg.Exceptions.SerialOpenFailed() if self.hFile == INVALID_HANDLE_VALUE: self.hFile = None raise eg.Exceptions.SerialOpenFailed() dcb = self.dcb GetCommState(self.hFile, byref(dcb)) dcb.fBinary = True dcb.fParity = False dcb.fOutxCtsFlow = False dcb.fOutxDsrFlow = False dcb.fDtrControl = DTR_CONTROL_DISABLE dcb.fDsrSensitivity = False dcb.fTXContinueOnXoff = True dcb.fOutX = False dcb.fInX = False dcb.fErrorChar = False dcb.fNull = False dcb.fRtsControl = False dcb.fAbortOnError = False dcb.BaudRate = baudrate dcb.ByteSize = int(mode[0]) dcb.Parity = PARITY_S2V_DICT[mode[1].upper()] dcb.StopBits = STOPBITS_S2V_DICT[mode[2:]] SetCommState(self.hFile, byref(dcb)) GetCommTimeouts(self.hFile, byref(self.oldCommTimeouts)) commTimeouts = COMMTIMEOUTS(0, 0, 0, 100, 100) SetCommTimeouts(self.hFile, byref(commTimeouts))