1 """
2 module ckbot.port2port
3
4 This module provides point-to-point connectivity tools for the rest of
5 the ckbot classes. In particular, it encapsulates the differences
6 between serial ports in Linux, OS X and other common operating
7 environments, as well as offering a UDP transport and an xbee wrapper
8 for serial links.
9
10 All connections provided by this module are subclasses of Connection
11 class.
12 """
13
14 from serial import Serial
15 from socket import socket, error as SocketError, AF_INET, SOCK_DGRAM
16 from glob import glob as GLOB_GLOB
17 from sys import platform, stderr
18 from os import sep
19 from json import loads as json_loads
20
21
22 try:
23 import _winreg as winreg
24 except:
25 winreg = None
26
28 """
29 Abstract superclass of all Connection objects
30 """
31
33 """Make the connection active"""
34 pass
35
37 """Test if connection is open"""
38 return False
39
41 """(pure) Attempt to write the specified message through the
42 connection. Returns number of byte written
43 """
44 raise RuntimeError("Pure method called")
45
46 - def read( self, length ):
47 """(pure) Attempt to read the specified number of bytes.
48 r
49 Return number of bytes actually read
50 """
51 return 0
52
54 """Disconnect; further traffic may raise an exception
55 """
56 pass
57
59 """Try to reconnect with some configuration changes"""
60 pass
61
63 """
64 Concrete Connection subclass representing a serial port
65 """
66 - def __init__(self, glob=None, *args, **kw):
67
68 port_path = None
69 if glob is not None:
70 port_path = (GLOB_GLOB(glob)+[None])[0]
71 if port_path is None:
72
73 plat = platform.lower()
74 if "linux" in plat:
75 port_path = (GLOB_GLOB("/dev/ttyUSB*")+[None])[0]
76 elif "win32" in plat:
77
78 path = 'HARDWARE\\DEVICEMAP\\SERIALCOMM'
79 key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, path)
80 port_path = winreg.EnumValue(key,0)[1]
81 elif "darwin" in plat:
82
83 port_path = (GLOB_GLOB("/dev/tty.usbserial*")+GLOB_GLOB("/dev/tty.usbmodem*")+[None])[0]
84 else:
85 raise IOError('Unknown OS -- cannot auto-configure serial')
86
87 if port_path is None:
88 raise IOError("No serial port found and no glob hint given")
89 Serial.__init__(self, port_path, *args, **kw)
90 Connection.__init__(self)
91 if self.isOpen():
92 self.path = port_path
93 else:
94 self.path = "<<COULD-NOT-OPEN>>"
95
96 """Since pySerial decided to break things, lets un-break them"""
97 if not hasattr(Serial,'getSupportedBaudRates'):
99 if type(self.BAUDRATES[0]) is int:
100 return list(self.BAUDRATES)
101 return [ (b,None) for b in self.BAUDRATES ]
102
104 r = object.__repr__(self)
105 return "%s %s %d:%d%s>" % (r[:-1],self.path, self.baudrate,self.stopbits,self.parity )
106
108 """Factory method for creating a Connection from a string or dictionary
109
110 Formats:
111 udp={dst="host", dport=<port>, sport=<sport>} -- set up a UDP
112 connection.
113 tty={glob=<glob>, baudrate=<baud>, stopbits = <n>, parity = 'N'|'E'|'O', timeout=0.5 } -- set up a tty connection
114
115 In dictionary format, the Connection type is given by the TYPE key, e.g.
116 dict( TYPE='tty', baudrate=9600 )
117 other: assumed to be a Serial device glob pattern
118 """
119 if type(spec) is str:
120 spl = spec.split("=",1)
121 if len(spl)==1:
122
123 res = SerialConnection(spec)
124 if not res.isOpen():
125 raise IOError("Could not open '%s'" % spec)
126 return res
127 args = json_loads( spl[1] )
128 T = spl[0]
129 elif type(spec) is not dict:
130 raise TypeError('spec must be a string or a dictionary')
131 else:
132 args = spec.copy()
133 T = args['TYPE']
134 del args['TYPE']
135
136 if T.lower() == 'udp':
137 res = UDPConnection( **args )
138 elif T.lower() == 'tty':
139 if not args.has_key('glob'):
140 res = SerialConnection(**args)
141 if not res.isOpen():
142 raise IOError("Could not open default port")
143 else:
144 kw = args.copy()
145 g = kw['glob']
146 del kw['glob']
147 res = SerialConnection(g,**kw)
148 if not res.isOpen():
149 raise IOError("Could no open '%s'" % g)
150 else:
151 raise ValueError('Unknown Connection type %s' % repr(T))
152
153 args['TYPE']=T
154 res.newConnection_spec = args
155 return res
156
157
160 raise RuntimeError("UNIMPLEMENTED")
161