Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.apo.nmsu.edu/Telescopes/TCC/html/mcp_multiplexor_8py_source.html
Дата изменения: Tue Sep 15 02:25:37 2015
Дата индексирования: Sun Apr 10 03:34:48 2016
Кодировка:

Поисковые слова: вечный календарь
lsst.tcc: python/tcc/actor/mcpMultiplexor.py Source File
lsst.tcc  1.2.2-3-g89ecb63
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
mcpMultiplexor.py
Go to the documentation of this file.
1 from __future__ import absolute_import, division
2 
3 from collections import deque, OrderedDict
4 import string
5 import syslog
6 
7 from twistedActor import log
8 
9 import RO.Comm.Generic
10 RO.Comm.Generic.setFramework("twisted")
11 from RO.Comm.TCPConnection import TCPConnection
12 from RO.Comm.Generic import TCPServer
13 
14 __all__ = ["MCPMultiplexor"]
15 
16 LocalDebug = False # if true, talk to the azimuth controller started by emulate35m.py
17 
18 AxisPortList = (
19  ( "AZ", 2521),
20  ("ALT", 2522),
21  ("ROT", 2523),
22 )
23 
24 # unprintable chars we see from the MCP (plus a few extras)
25 CharsToStrip = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xfa\xfb\xfc\xfd\xfe\xff'
26 
27 class AxisServer(object):
28  """A server for axis commands
29 
30  Axis commands are prefixed with axis name (and a space) if necessary
31  """
32  AxisList = (val[0] for val in AxisPortList)
33  def __init__(self, axis, port, queueFunc):
34  """Construct an AxisServer
35 
36  For each command received, the server:
37  - prepends the axis name and a space, if not already present
38  - queues the command by calling queueFunc
39 
40  @param[in] axis axis name
41  @param[in] port port on which to listen to commands for this axis
42  @param[in] queueFunc function to call when a command is to be queued;
43  must take three arguments: cmdStr, socket, prefixStr
44  """
45  if axis not in self.AxisList:
46  raise RuntimeError("axis=%r; must be one of %s" % (axis, self.AxisList))
47  self.axisPrefix = axis + " "
48  self.server = TCPServer(
49  sockReadCallback = self._readCallback,
50  stateCallback = self._stateCallback,
51  port = port,
52  )
53  self.queueFunc = queueFunc
54 
55  def _readCallback(self, sock):
56  """Called when a command is received
57  """
58  cmdStr = sock.readLine()
59  if not cmdStr:
60  return
61  if not cmdStr.startswith(self.axisPrefix):
62  prefixStr = self.axisPrefix
63  cmdStr = self.axisPrefix + cmdStr
64  else:
65  prefixStr = ""
66  self.queueFunc(cmdStr, sock, prefixStr)
67 
68  def _stateCallback(self, conn):
69  log.info("%s conn state=%s" % (self.axisPrefix, conn.state,))
70 
71  def close(self):
72  self.server.close()
73 
74 
75 class MCPMultiplexor(object):
76  """Multiplex axis controller ports into one MCP port
77 
78  Axis commands are prefixed with axis name (and a space) if necessary
79  """
80  Facility = syslog.LOG_LOCAL4
81  AxisPortDict = OrderedDict(AxisPortList)
82  def __init__(self, mcpHost, mcpPort):
83  """!Construct an MCPMultiplexor
84 
85  @param[in] mcpHost MCP host
86  @param[in] mcpPort MCP port
87  """
88  self._currCmdSockPrefix = None
89  self._cmdQueue = deque()
90 
91  # dict of axis name: server socket
92  self._axisServerDict = None
93 
94  log.info("starting MCP connection to %s, %s" % (mcpHost, mcpPort))
95  self._mcpConn = TCPConnection(
96  name = "MCP",
97  host = mcpHost,
98  port = mcpPort,
99  readLines = True,
100  stateCallback = self._mcpConnStateCallback,
101  readCallback = self._mcpReadCallback,
102  )
103  self._mcpConn.connect()
104 
105  def _logQueue(self):
106  """Show the current state of the queue
107  """
108  # write prefix and cmdString
109  log.info("currently waiting on axis: %r"%(self._currCmdSockPrefix[0] if self._currCmdSockPrefix is not None else "None"))
110  log.info("queue=[%s] <--next to execute"%(", ".join([cmdTuple[-1] + " " + cmdTuple[0] for cmdTuple in self._cmdQueue])))
111 
112 
113  def _mcpConnStateCallback(self, conn):
114  log.info("MCP conn state=%s" % (conn.state,))
115  if conn.isConnected and not self._axisServerDict:
116  log.info("MCP connection made; starting up axis servers")
117  self._cmdQueue = deque()
118  self._axisServerDict = dict((axis, AxisServer(axis=axis, port=axisPort, queueFunc=self.queueCmd))
119  for axis, axisPort in self.AxisPortDict.iteritems())
120  elif conn.isDisconnected:
121  log.info("MCP connection done; killing axis servers")
122  self._cmdQueue = deque()
123  if self._axisServerDict:
124  for server in self._axisServerDict.itervalues():
125  server.close()
126  self._axisServerDict = None
127 
128  def queueCmd(self, cmdStr, sock, prefixStr):
129  """Add a command to the command queue
130 
131  @param[in] cmdStr command to queue
132  @param[in] sock socket to which to write replies
133  @param[in] prefixStr prefix prepended to cmdStr
134  """
135  log.info("queue %r for %s" % (cmdStr, sock))
136  self._cmdQueue.appendleft((cmdStr, sock, prefixStr))
137  self._logQueue()
138  self._runQueue()
139 
140  def _mcpReadCallback(self, sock, replyStr):
141  """Called when data is read from the MCP
142  """
143  if self._currCmdSockPrefix:
144  log.info("read %r from MCP for %r" % (replyStr, self._currCmdSockPrefix[0]))
145  sock = self._currCmdSockPrefix[1]
146 
147  # strip unprintable chars
148  replyStr = replyStr.translate(string.maketrans("",""), CharsToStrip)
149 
150  # strip prefix string
151  prefixStr = self._currCmdSockPrefix[2]
152  if replyStr and prefixStr and replyStr.startswith(prefixStr):
153  replyStr = replyStr[len(prefixStr):]
154 
155  if not replyStr:
156  return
157 
158  try:
159  log.info("sending %r to %r for %r" % (replyStr, sock, self._currCmdSockPrefix[0]))
160  sock.writeLine(replyStr)
161  except Exception, e:
162  log.warn("Could not write to %s: %s" % (sock, e))
163  if replyStr == "OK" or replyStr.endswith(" OK"):
164  # command is done; clear current command and start a new one
165  self._currCmdSockPrefix = None
166  self._runQueue()
167  else:
168  log.warn("read %r from MCP, unsolicited" % (replyStr,))
169 
170  def _runQueue(self):
171  """Start a new command, if ready to do so, else do nothing
172  """
173  if self._currCmdSockPrefix or not self._cmdQueue:
174  return
175  cmdStr, sock, prefixStr = self._cmdQueue.pop()
176  self._currCmdSockPrefix = (cmdStr, sock, prefixStr)
177  log.info("sending %r to MCP" % (cmdStr,))
178  self._logQueue()
179  self._mcpConn.writeLine(cmdStr)
def __init__
Construct an MCPMultiplexor.