如何使用twisted处理R/W的多个串口? [英] How to deal with multiple serial ports for R/W using twisted?

查看:81
本文介绍了如何使用twisted处理R/W的多个串口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通过扭手指教程并看到了 SO 问题:

但是,我(还)不能编写一个可以读取 & 的扭曲程序.从多个串行端口写入,尤其是在协议涉及读取单行或多行并相应地写回设备的情况下.

我想要做的是为 2 个调制解调器打开 2 对(即总共 4 个)串行端口.与调制解调器的通信使用 Hayes AT 命令集.虽然与调制解调器的大多数命令/响应交换是通过命令端口进行的,但对于每个调制解调器,只有通过诊断端口才能获得的诊断信息很少.诊断信息应导致状态机(设备状态、连接状态)被修改.

这是我所理解的潜在方法的粗略框架程序(基于单端口示例):

class CommandProtocol(LineOnlyReceiver):def connectionMade(self):log.msg("连接到命令端口")def lineReceived(self, line):打印代表(行)processCommandLine(行)类诊断协议(LineOnlyReceiver):def connectionMade(self):log.msg("连接到诊断端口")def lineReceived(self, line):打印代表(行)processDiagnosticLine(line)...# modem1 端口cmdPort[0] = SerialPort(CommandProtocol, "/dev/ttyUSB0", reactor, 115200)diagPort[0] = SerialPort(诊断协议,/dev/ttyUSB1",反应器,115200)# modem2 端口cmdPort[1] = SerialPort(CommandProtocol, "/dev/ttyUSB3", reactor, 115200)diagPort[1] = SerialPort(诊断协议,/dev/ttyUSB4",反应器,115200)

但是,我不知所措,我该怎么做:

  • 我如何/在哪里接受来自用户的 CLI 输入,然后触发向调制解调器发送一组 AT 命令?
  • 将在命令端口上接收到的信息关联到 ttyUSB0 &ttyUSB1 用于 modem1,类似地用于 modem2 的另一对?请注意,每个调制解调器都有自己的状态机(设备状态和连接状态)
  • twisted 是否提供任何机制来管理应用程序的多个状态机?
  • 与调制解调器的 USB 串行连接可能因调制解调器被拔出而被破坏,并在重新插入时重新建立.如何检测此类事件并将相应设备端口的监控添加到反应器?目前,我在主应用程序中静态执行此操作.

解决方案

注意示例代码

我没有看到您在将类注册到反应器之前实例化它们.我预计这会失败.这是我的运行代码的类似片段:

# 处理来自串口的消息的东西类 SerialEater(basic.LineReceiver):statusCallback = 无def __init__(self):self.keyinprocess = 无def lineReceived(self, data):self.dealWithSerial(data)def connectionLost(self, reason):如果(反应堆运行):打印串行丢失但反应器仍在运行!原因:"+ str(原因)+时间"+ time.asctime()[...等等...]# 将串口注册为twistedserialhandler = SerialEater() # <------------- 实例化SerialPort(serialhandler, '/dev/ttyUSB0', reactor, baudrate=115200)

<小时><块引用>

我如何/在哪里接受来自用户的 CLI 输入,然后触发向调制解调器发送一组 AT 命令?

很像如何将串行处理程序注册到 Twisted 中,您可以为标准 io 注册处理程序,例如:

# 从标准输入中提取 cbreak 字符输入的东西类 KeyEater(basic.LineReceiver):def __init__(self):self.setRawMode() # 从行模式切换到无论我得到多少"模式def connectionLost(self, reason):如果(反应堆运行):self.sendLine( "键盘丢失但反应器仍在运行!原因:" + str(reason) + " at time " + time.asctime())def rawDataReceived(self, data):键 = str(data).lower()[0]尝试:如果键 == '?':键 = "帮助"[...等等...]# 注册 stdio 处理程序到 Twisted键盘对象 = KeyEater()keyboardobj.serialobj = serialhandlerstdio.StandardIO(keyboardobj,sys.stdin.fileno())

<小时><块引用>

将在命令端口上收到的信息关联到 ttyUSB0 &ttyUSB1 用于 modem1,类似地用于 modem2 的另一对?请注意,每个调制解调器都有自己的状态机(设备状态和连接状态)

在正常使用中,每个连接实例都有自己的状态机(包含在您与连接一起注册到反应器中的类的实例中).

作为程序员,您可以选择如何连接类的状态,但通常是通过推送对合作伙伴类的引用.

下面,这个答案包含可运行的代码,这些代码将说明数据是如何在状态机/接口之间连接的.这也在此 SO 中进行了说明:扭曲中的持久连接

<小时><块引用>

twisted 是否提供任何机制来管理应用程序的多个状态机?

如果应用程序"是指你的扭曲代码",那么答案是肯定的!

典型的 Twisted 应用程序是一组状态机,所有这些都带有一些定义非常好的接口.我开始我的 Twisted 冒险打算编写一个带有两个状态机(一个串行和键盘)的应用程序,但是当我熟悉了 Twisted 正在做的事情时,我意识到添加额外的接口和状态机是微不足道的(通过所有的奇迹tx 库).整个下午,我添加了一个粗略的 Web 界面,一个 websocket 界面,然后在两者上都设置了 SSL,甚至添加了一个 SSH 调试界面.一旦开始,添加接口和状态机就变得微不足道了.

在许多(所有?)情况下,扭曲模型是状态机将驻留在一个实例化的类中,该类与连接绑定并且已注册到(一个且唯一一个)主事件中-循环.

使用产生新状态机的连接类型(想想 http 连接),您注册一个工厂类/状态机以及侦听连接,它们共同使应用程序能够为每个新的类/状态机产生新的类/状态机联系.在大规模运行时,扭曲的应用程序通常需要 10 甚至 100 多个并发状态实例.

如果您尝试将不同的协议和状态粘合在一起(...所有这些都在您选择的事件循环中(select/epoll/kqueue/etc)),Twisted 非常棒

以下是可运行的示例代码,可以说明其中的许多要点.阅读 def main() 之前的注释以了解更多代码背景:

#!/usr/bin/python## Frankenstein-esk 示例代码的合并# 其中的关键来自 Twisted "Chat" 示例#(如:http://twistedmatrix.com/documents/12.0.0/core/examples/chatserver.py)导入 sys # 这样我就可以进入标准输入为 isatty 导入 o​​s #import termios, tty # 访问posix IO设置从随机导入随机从twisted.internet 进口反应堆fromtwisted.internet import stdio # listenXXX 的 stdio equivfromtwisted.protocols import basic # for lineReceiver for keyboard从twisted.internet.protocol 导入协议,ServerFactory类 MyClientConnections(basic.LineReceiver):def __init__(self):self.storedState = "空闲"self.connectionpos = 无def connectionMade(self):self.factory.clients.append(self) # <--- 这里的魔法:# 协议自动链接到它的工厂类,并且# 在这种情况下,用于推送每个新连接#(以此类的形式)放入一个列表中# factory 然后可以访问以获取每个连接self.connectionpos = str(self.factory.clients.index(self)) # 弄清楚# 我在连接数组中的位置打印有新客户!(索引:",self.connectionpos +)"self.transport.write("---\n你的连接:" + self.connectionpos + "\n---\n")def connectionLost(self, reason):打印失去一个客户!"self.factory.clients.remove(self)# 用来假装某些东西是在 telnet 连接上输入的def fakeInput(self, message):self.transport.write("伪造输入:'" + message + "'\n")self.lineReceived(message)#这只是一个定义本身,所以我可以把我的演示电话混在一起def stateUpdate(self, newState, delay):self.storedState = newState# 以下是对进入该界面的伪造数据的黑客攻击reactor.callLater(delay, self.fakeInput, newState + "DONE")def processInput(self, newState):# 这里的所有逻辑都是为了做一个演示的垃圾,真正的代码可能看起来也可能不一样# 这.尽管这个垃圾逻辑是一个示例状态机如果 self.storedState == "空闲":如果 newState == 开始":self.stateUpdate("状态 A", 1)# 向这个连接发送消息self.transport.write("启动状态机\n")# 向它运行的脚本的术语发送一条消息打印连接 ["+ self.connectionpos +] 启动状态机"elif self.storedState == "状态 A":如果 newState == "State A DONE":self.transport.write("开始状态B\n")self.stateUpdate("状态 B", 2)elif self.storedState == "状态 B":如果 newState == "State B DONE":self.transport.write("开始状态C\n")self.stateUpdate("状态 C", 2)elif self.storedState == "状态 C":如果 newState == "State C DONE":self.storedState = "空闲"# 向这个连接发送消息self.transport.write("返回空闲状态\n")# 向它运行的脚本的术语发送一条消息打印连接["+ self.connectionpos +]返回空闲状态"def lineReceived(self, line):# print "received '" + line +"' from connection", self.factory.clients.index(self)self.processInput(行)类 MyServerFactory(ServerFactory):协议 = MyClientConnectionsdef __init__(self):self.clients = [] # 这从上面的类中得到填充def sendToAll(self, message):for c in self.clients: # Read MyClientConnections class for backgroundc.transport.write(消息)def randStart(self, width):对于 self.clients 中的 c:startDelay = random() * 宽度打印启动客户端"+ str(c.connectionpos) +"in" +str(startDelay) +"secs"reactor.callLater(startDelay, c.processInput, "start")# 将键盘设置为 cbreak 模式——只是因为我喜欢那样...类 Cbreaktty(对象):org_termio = 无my_termio = 无def __init__(self, ttyfd):如果(os.isatty(ttyfd)):self.org_termio = (ttyfd, termios.tcgetattr(ttyfd))tty.setcbreak(ttyfd)打印'设置cbreak模式'self.my_termio = (ttyfd, termios.tcgetattr(ttyfd))别的:引发 IOError #不是我可以设置 cbreak 的东西!def retToOrgState(self):(tty, org) = self.org_termio打印'恢复终端设置'termios.tcsetattr(tty, termios.TCSANOW, org)类 KeyEater(basic.LineReceiver):def __init__(self, factoryObj):self.setRawMode() # 从行模式切换到无论我得到多少"模式#以下是twisted中的关键连接思想之一,对象# 包含另一个状态机(实际上是所有的 tcp 状态机)# 已经通过它的 init 传入这个类.self.factoryObj = factoryObjdef rawDataReceived(self, data):键 = str(data).lower()[0]如果键 == 's':# 以下行将调用(从工厂对象中)# 随机开始 defself.factoryObj.randStart(5)elif 键 == 'd':打印连接状态转储"打印 " -  -  -  -  -  -  -  -  -  -  -  - -"对于 self.factoryObj.clients 中的 c:打印 "#" + str(c.connectionpos) + " " + c.storedStateelif 键 == 'q':反应器停止()别的:打印 " -  -  -  -  -  -  - "打印如果您还没有,请通过 a 连接到此脚本"打印"'telnet localhost 5000' 至少一个(多个连接)打印更好)"打印按:"打印"s - 随机启动所有客户端"打印"d - 转储所有连接客户端的状态"打印"q - 干净地关闭"打印注意:您可以在连接、事物中键入命令"打印其中最有用的是‘开始’"打印 " -  -  -  -  -  -  - -"# SO 的定制示例:30397425## 这段代码是风格和技术的大杂烩.两者都提供了不同的例子来说明如何# 有些事情可以做,因为我很懒.它已在 OSX 和 linux 上构建和测试,# 它应该是可移植的(否则可能是 termal cbreak 模式).如果你想问# 关于此代码的问题通过邮件直接与我联系,mike at partialmesh.com## 虽然它不直接使用串口,​​但它使用的tcp连接很好# 平行.## 它应该通过运行脚本然后打开许多windows telnet'ing 来使用# 本地主机 5000.## 一旦运行,在运行脚本的窗口中按任意键,它会给出# 指示.# 正常的用例是输入s"来排队状态机# 启动,然后重复按 'd' 以转储所有状态机的状态## 'start' 可以输入到任何 telnet 连接中,也可以手动启动它们.定义主():client_connection_factory = MyServerFactory()尝试:termstate = Cbreaktty(sys.stdin.fileno())除了 IOError:sys.stderr.write("错误:" + sys.argv[0] + " 仅用于交互式 ttys\n")sys.exit(1)keyboardobj = KeyEater(client_connection_factory)stdio.StandardIO(keyboardobj,sys.stdin.fileno())reactor.listenTCP(5000, client_connection_factory)反应器运行()termstate.retToOrgState()如果 __name__ == '__main__':主要的()

<小时><块引用>

调制解调器的 USB 串行连接可能因拔出调制解调器而损坏,并在重新插入时重新建立.如何检测此类事件并将相应设备端口的监控添加到反应器?目前,我在主应用程序中静态执行此操作.

经过研究,我没有一个简单的答案.我仍然怀疑以下逻辑将接近解决方案,但我今天没有找到实现它的代码.

我的猜测是有一种合理的方法可以确定是否发生了 USB 事件,并确定是否已添加串行设备.但是我怀疑是否有一种很好的方法可以确定它是否是您的串行设备之一 - 更不用说它是您的命令或诊断接口(除非您的构建硬件并且可以控制设备的 USB ID)

在串行端口错误时触发事件(至少根据我在 Linux 上的经验),但我不确定 USB 拔出如何/在哪里注册.

<小时>

其他可能对您有用的链接

Going through the twisted finger tutorial and seen the SO questions:

However, I can't (yet) write a twisted program that can read & write from multiple serial ports, especially where the protocol involves reading single or multiple lines, and writing back to the device accordingly.

What I am trying to do is open 2 pairs (i.e. total of 4) serial ports, for 2 modems. Communication with modems is using Hayes AT command set. While most of the command/response exchanges with modem is via the command-port, there are few diagnostic information that are available only via the diagnostic-port, for each modem. The diagnostic information should lead to a state-machine (device-state, connection-state) to be modified.

Here is a rough skeletal program of what I understand as the potential approach (based on single port examples):

class CommandProtocol(LineOnlyReceiver):
    def connectionMade(self):
        log.msg("Connected to command port")

    def lineReceived(self, line):
        print repr(line)
        processCommandLine(line)

class DiagnosticProtocol(LineOnlyReceiver):
    def connectionMade(self):
        log.msg("Connected to diag port")

    def lineReceived(self, line):
        print repr(line)
        processDiagnosticLine(line)

...

# modem1 ports
cmdPort[0] = SerialPort(CommandProtocol, "/dev/ttyUSB0", reactor, 115200)
diagPort[0] = SerialPort(DiagnosticProtocol, "/dev/ttyUSB1", reactor, 115200)
# modem2 ports
cmdPort[1] = SerialPort(CommandProtocol, "/dev/ttyUSB3", reactor, 115200)
diagPort[1] = SerialPort(DiagnosticProtocol, "/dev/ttyUSB4", reactor, 115200)

However, I am at loss, as to how do I do the following:

  • How/where do I accept CLI input from user, that then triggers sending a set of AT command to the modems ?
  • Correlate the information received on command port for ttyUSB0 & ttyUSB1 for modem1, and similarly for the other pair for modem2 ? Note that each modem has it's own state-machine (device-state and connection-state)
  • Does twisted provide any mechanism for management of multiple state-machines by application ?
  • It is possible that the USB-serial connection to the modem is destroyed due to the modem being unplugged, and re-established on being plugged back-in. How can I detect such events and add the monitoring of the corresponding device-ports to the reactor ? Currently, I'm doing it statically in the main application.

解决方案

Note on your example code

I don't see you instantiating your classes before registering them to the reactor. I expect that will fail badly. Here is a similar snippet of running code of mine:

# stuff to process messages coming from the serial port
class SerialEater(basic.LineReceiver):
    statusCallback = None

    def __init__(self):
        self.keyinprocess = None

    def lineReceived(self, data):
      self.dealWithSerial(data)

    def connectionLost(self, reason):
      if(reactor.running):
        print "Serial lost but reactor still running! reason: " + str(reason) + " at time " + time.asctime()
    [...etc...]



# Register the serialport into twisted
serialhandler = SerialEater()                   # <------------- instantiate
SerialPort(serialhandler, '/dev/ttyUSB0', reactor, baudrate=115200)


How/where do I accept CLI input from user, that then triggers sending a set of AT command to the modems ?

Much like how you can register Serial handlers into Twisted, you can register handlers for standard io, for instance:

# stuff to pull cbreak char input from stdin
class KeyEater(basic.LineReceiver):

    def __init__(self):
      self.setRawMode() # Switch from line mode to "however much I got" mode

    def connectionLost(self, reason):
      if(reactor.running):
        self.sendLine( "Keyboard lost but reactor still running! reason: " + str(reason) + " at time " + time.asctime())

    def rawDataReceived(self, data):
      key = str(data).lower()[0]
      try:
        if key == '?':
          key = "help"
     [...etc...]

# register the stdio handler into twisted
keyboardobj = KeyEater()
keyboardobj.serialobj = serialhandler
stdio.StandardIO(keyboardobj,sys.stdin.fileno())


Correlate the information received on command port for ttyUSB0 & ttyUSB1 for modem1, and similarly for the other pair for modem2 ? Note that each modem has it's own state-machine (device-state and connection-state)

In normal use, each connection-instance is going to have its own state machine (wrapped up in the instance of the class that you register into the reactor along with the connection).

You as the programmer choose how you want to connect the states of the classes, but often its via pushing reference to the partner classes.

Below, this answer contains runnable code that will illustrate how data is connected between state-machines/interface. This is also illustrated in this SO: Persistent connection in twisted


Does twisted provide any mechanism for management of multiple state-machines by application ?

If by "application" you mean "your twisted code" then then the answer is absolutely YES!

The typical Twisted app is an array of state-machines, all with some amazingly well defined interfaces. I started my Twisted adventure intending to write an app with two state-machines (a serial and keyboard), but when I became comfortable with twisted was doing I realized it was trivial to add on extra interfaces and state-machines (through all the wonder of the tx libraries). All in one afternoon I added on a rough web interface, a websocket interface, then laid SSL over both and even added on an SSH debug interface. Once you get a rolling, adding interfaces and state-machines become trivial.

In many (all?) cases, the twisted model is that a state-machine will reside in an instantiated class that is tied to a connection and that has been registered into the (one-and-only-one) main event-loop.

With connection types that spawn off new state-machines (think http connections) you register one factory-class/state-machine along with the listening connection which together enable the app of spawning off new classes/state-machines for each new connection. Twisted applications routinely 10s or even 100s of thousands of concurrent instances of state when run at scale.

Twisted is amazing if your trying to glue together different protocols and states (... with all of it being in a event loop of your choice (select/epoll/kqueue/etc))

The following is runnable sample code that should illustrate many of these points. Read the comments before def main() for more background on the code:

#!/usr/bin/python
#
# Frankenstein-esk amalgam of example code
#   Key of which comes from the Twisted "Chat" example
#   (such as: http://twistedmatrix.com/documents/12.0.0/core/examples/chatserver.py)

import sys # so I can get at stdin
import os # for isatty
import termios, tty # access to posix IO settings
from random import random
from twisted.internet import reactor
from twisted.internet import stdio # the stdio equiv of listenXXX
from twisted.protocols import basic # for lineReceiver for keyboard
from twisted.internet.protocol import Protocol, ServerFactory

class MyClientConnections(basic.LineReceiver):

    def __init__(self):
        self.storedState = "Idle"
        self.connectionpos = None

    def connectionMade(self):
        self.factory.clients.append(self) # <--- magic here :
            # protocol automagically has a link to its factory class, and
            # in this case that is being used to push each new connection
            # (which is in the form of this class) into a list that the
            # factory can then access to get at each of the connections
        self.connectionpos = str(self.factory.clients.index(self)) # figure out 
                                      # where I am in the connection array
        print "Got new client! (index:", self.connectionpos + ")"
        self.transport.write("---\nYour connection: " + self.connectionpos + "\n---\n")

    def connectionLost(self, reason):
        print "Lost a client!"
        self.factory.clients.remove(self)

    # used to pretend that something was typed on a telnet connection
    def fakeInput(self, message):
        self.transport.write("FAKING Input: '" + message + "'\n")
        self.lineReceived(message)

    #this is only in a def on its own so I can lump my demo callLater
    def stateUpdate(self, newState, delay):
        self.storedState = newState
        # the following is a hack to fake data coming in this interface
        reactor.callLater(delay, self.fakeInput, newState + " DONE")

    def processInput(self, newState):
        # all the logic in here is junk to make a demo, real code may or may-not look like
        # this.  This junk logic is an example statemachine though
        if self.storedState == "Idle":
            if newState == "start":
                self.stateUpdate("State A", 1)        
                # send a message to this connection
                self.transport.write("starting state machine\n")
                # send a message to the term in which the script it running
                print "Connection [" + self.connectionpos + "] starting state machine"
        elif self.storedState == "State A":
            if newState == "State A DONE":
                self.transport.write("Beginning state B\n")
                self.stateUpdate("State B", 2)
        elif self.storedState == "State B":
            if newState == "State B DONE":
                self.transport.write("Beginning state C\n")
                self.stateUpdate("State C", 2)
        elif self.storedState == "State C":
            if newState == "State C DONE":
                self.storedState = "Idle"
                # send a message to this connection
                self.transport.write("Returning to Idle state\n")
                # send a message to the term in which the script it running
                print "Connection [" + self.connectionpos + "] return to Idle state"

    def lineReceived(self, line):
        # print "received '" + line +"' from connection", self.factory.clients.index(self)
        self.processInput(line)

class MyServerFactory(ServerFactory):
    protocol = MyClientConnections

    def __init__(self):
        self.clients = [] # this gets filled from the class above

    def sendToAll(self, message):
      for c in self.clients:  # Read MyClientConnections class for background
        c.transport.write(message)

    def randStart(self, width):
      for c in self.clients:
        startDelay = random() * width
        print "Starting client " + str(c.connectionpos) + " in " +str(startDelay) + " secs" 
        reactor.callLater(startDelay, c.processInput, "start")

# to set keyboard into cbreak mode -- just because I like it that way...
class Cbreaktty(object):
    org_termio = None
    my_termio = None

    def __init__(self, ttyfd):
        if(os.isatty(ttyfd)):
            self.org_termio = (ttyfd, termios.tcgetattr(ttyfd))
            tty.setcbreak(ttyfd)
            print '  Set cbreak mode'
            self.my_termio = (ttyfd, termios.tcgetattr(ttyfd))
        else:
          raise IOError #Not something I can set cbreak on!

    def retToOrgState(self):
        (tty, org) = self.org_termio
        print '  Restoring terminal settings'
        termios.tcsetattr(tty, termios.TCSANOW, org)


class KeyEater(basic.LineReceiver):

    def __init__(self, factoryObj):
        self.setRawMode() # Switch from line mode to "however much I got" mode
        # the following is one of the key connecting ideas in twisted, the object
        # that contains another state machine (really all of the tcp statemachines)
        # has been passed into this class via its init.
        self.factoryObj = factoryObj

    def rawDataReceived(self, data):
        key = str(data).lower()[0]
        if key == 's':
            # The following line is going to call (from within the factory object)
            # the random start def
            self.factoryObj.randStart(5)
        elif key == 'd':
            print "State Dump of connections"
            print "-------------------------"
            for c in self.factoryObj.clients:
                print "#" + str(c.connectionpos) + "      " + c.storedState
        elif key == 'q':
            reactor.stop()
        else:
            print "--------------"
            print "  If you haven't already, connect to this script via a"
            print "  'telnet localhost 5000' at least one (multiple connections"
            print "  are better)"
            print "Press:"
            print "      s  - randomly start all clients"
            print "      d  - dump the state of all connected clients"
            print "      q  - to cleanly shutdown"
            print " Note: you can type commands in the connections, things"
            print "       most useful of which is 'start'"
            print "---------------"

# Custom tailored example for SO:30397425
# 
# This code is a mishmash of styles and techniques. Both to provide different examples of how
# something can be done and because I'm lazy.  Its been built and tested on OSX and linux,
# it should be portable (other then perhaps termal cbreak mode).  If you want to ask
# questions about this code contact me directly via mail to mike at partialmesh.com
#
# While it isn't directly using serial ports, the tcp connections that its using are a good
# parallel.
#
# It should be used by running the script and then opening up many windows telnet'ing into
# localhost 5000.
#
# Once running press any key in the window where the script was run and it will give
# instructions.  
# The normal use case would be to type "s" to queue statemachine
# start-ups, then repeatedly press 'd' to dump the status of all the state machines
#
# 'start' can be typed into any of the telnet connections to start them by hand too.


def main():
    client_connection_factory = MyServerFactory()

    try:
      termstate = Cbreaktty(sys.stdin.fileno())
    except IOError:
      sys.stderr.write("Error: " + sys.argv[0] + " only for use on interactive ttys\n")
      sys.exit(1)

    keyboardobj = KeyEater(client_connection_factory)

    stdio.StandardIO(keyboardobj,sys.stdin.fileno())
    reactor.listenTCP(5000, client_connection_factory)
    reactor.run()
    termstate.retToOrgState()
if __name__ == '__main__':
  main()


It is possible that the USB-serial connection to the modem is destroyed due to the modem being unplugged, and re-established on being plugged back-in. How can I detect such events and add the monitoring of the corresponding device-ports to the reactor ? Currently, I'm doing it statically in the main application.

After research I don't have an easy answer. I still suspect that the following logic will be close to a solution but I didn't have any luck finding code that implements this today.

My guess is there will be a reasonable way to figure out if a USB event has occurred, and work out if a serial device has been added. But I doubt there will a good way to figure out if it is one of your serial devices - much less if its your Command or Diagnostic interface (Unless your building hardware and can control the USB IDs of the devices)

Events are fired on errors with serial ports (at least from my experience on linux), but I'm unsure how/where a USB unplug would register.


Other links that might be of use to you

这篇关于如何使用twisted处理R/W的多个串口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆