blob: ea123cbdfcdde230ba9976989b5cbc54ecd2e28f [file] [log] [blame]
Guido van Rossum605b1271993-05-12 12:35:44 +00001import fcntl
2import IOCTL
3from IOCTL import *
4import sys
5import struct
6import select
7
8DEVICE='/dev/ttyd2'
9
10def packttyargs(*args):
11 if type(args) <> type(()):
12 raise 'Incorrect argtype for packttyargs'
13 if type(args[0]) == type(1):
14 iflag, oflag, cflag, lflag, line, chars = args
15 elif type(args[0]) == type(()):
16 if len(args) <> 1:
17 raise 'Only 1 argument expected'
18 iflag, oflag, cflag, lflag, line, chars = args[0]
19 elif type(args[0]) == type([]):
20 if len(args) <> 1:
21 raise 'Only 1 argument expected'
22 [iflag, oflag, cflag, lflag, line, chars] = args[0]
23 str = struct.pack('hhhhb', iflag, oflag, cflag, lflag, line)
24 for c in chars:
25 str = str + c
26 return str
27
28def nullttyargs():
29 chars = ['\0']*IOCTL.NCCS
30 return packttyargs(0, 0, 0, 0, 0, chars)
31
32def unpackttyargs(str):
33 args = str[:-IOCTL.NCCS]
34 rawchars = str[-IOCTL.NCCS:]
35 chars = []
36 for c in rawchars:
37 chars.append(c)
38 iflag, oflag, cflag, lflag, line = struct.unpack('hhhhb', args)
39 return (iflag, oflag, cflag, lflag, line, chars)
40
41def initline(name):
42 fp = open(name, 'r')
43 ofp = open(name, 'w')
44 fd = fp.fileno()
45 rv = fcntl.ioctl(fd, IOCTL.TCGETA, nullttyargs())
46 iflag, oflag, cflag, lflag, line, chars = unpackttyargs(rv)
47 iflag = iflag & ~(INPCK|ISTRIP|INLCR|IUCLC|IXON|IXOFF)
48 oflag = oflag & ~OPOST
49 cflag = B9600|CS8|CREAD|CLOCAL
50 lflag = lflag & ~(ISIG|ICANON|ECHO|TOSTOP)
51 chars[VMIN] = chr(1)
52 chars[VTIME] = chr(0)
53 arg = packttyargs(iflag, oflag, cflag, lflag, line, chars)
54 dummy = fcntl.ioctl(fd, IOCTL.TCSETA, arg)
55 return fp, ofp
56
57#ifp, ofp = initline('/dev/ttyd2')
58#while 1:
59# print 'GO'
60# inset, d, d = select.select([sys.stdin, ifp], [], [])
61# if sys.stdin in inset:
62# cmd = eval(sys.stdin.readline(100))
63# print 'CMD:', `cmd`
64# if cmd:
65# ofp.write(cmd)
66# ofp.flush()
67# if ifp in inset:
68# data = ifp.read(1)
69# print 'LEN', len(data), 'DATA', `data`
70
71error = 'VCR.error'
72
73# Commands/replies:
74COMPLETION = '\x01'
75ACK ='\x0a'
76NAK ='\x0b'
77
78NUMBER_N = 0x30
79ENTER = '\x40'
80
81EXP_7= '\xde'
82EXP_8= '\xdf'
83
84CL ='\x56'
85CTRL_ENABLE = EXP_8 + '\xc6'
86SEARCH_DATA = EXP_8 + '\x93'
87ADDR_SENSE = '\x60'
88
89PLAY ='\x3a'
90STOP ='\x3f'
91EJECT='\x2a'
92FF ='\xab'
93REW ='\xac'
94STILL='\x4f'
95STEP_FWD ='\xad'
96FM_SELECT=EXP_8 + '\xc8'
97FM_STILL=EXP_8 + '\xcd'
98DM_OFF=EXP_8 + '\xc9'
99DM_SET=EXP_8 + '\xc4'
100FWD_SHUTTLE='\xb5'
101REV_SHUTTLE='\xb6'
102
Jack Jansena1e1f731993-06-08 12:47:06 +0000103class VCR:
Guido van Rossum605b1271993-05-12 12:35:44 +0000104 def init(self):
105 self.ifp, self.ofp = initline(DEVICE)
106 return self
107
108 def _cmd(self, cmd):
109## print '>>>',`cmd`
110 self.ofp.write(cmd)
111 self.ofp.flush()
112
113 def _waitdata(self, len, tout):
114 rep = ''
115 while len > 0:
116 ready, d1, d2 = select.select([self.ifp], [], [], tout)
117 if ready == []:
118## if rep:
119## print 'FLUSHED:', `rep`
120 return None
121 data = self.ifp.read(1)
122## print '<<<',`data`
123 if data == NAK:
124 return NAK
125 rep = rep + data
126 len = len - 1
127 return rep
128
129 def _reply(self, len):
130 data = self._waitdata(len, 10)
131 if data == None:
132 raise error, 'Lost contact with VCR'
133 return data
134
135 def _getnumber(self, len):
136 data = self._reply(len)
137 number = 0
138 for c in data:
139 digit = ord(c) - NUMBER_N
140 if digit < 0 or digit > 9:
141 raise error, 'Non-digit in number'+`c`
142 number = number*10 + digit
143 return number
144
145 def _iflush(self):
146 dummy = self._waitdata(10000, 1)
147## if dummy:
148## print 'IFLUSH:', dummy
149
150 def simplecmd(self,cmd):
151 for ch in cmd:
152 self._cmd(ch)
153 rep = self._reply(1)
154 if rep == NAK:
155 return 0
156 elif rep <> ACK:
157 raise error, 'Unexpected reply:' + `rep`
158 return 1
159
160 def _number(self, number, digits):
161 if number < 0:
162 raise error, 'Unexpected negative number:'+ `number`
163 maxnum = pow(10, digits)
164 if number > maxnum:
165 raise error, 'Number too big'
166 while maxnum > 1:
167 number = number % maxnum
168 maxnum = maxnum / 10
169 digit = number / maxnum
170 ok = self.simplecmd(chr(NUMBER_N + digit))
171 if not ok:
172 raise error, 'Error while transmitting number'
173
174 def wait(self):
175 self._iflush()
176 while 1:
177## print 'SENDCL'
178 self._cmd(CL)
179 rep = self._waitdata(1, 2)
180## print `rep`
181 if rep in ( None, CL, NAK ):
182 continue
183 break
184 if rep <> ACK:
185 raise error, 'Unexpected reply:' + `rep`
186 dummy = self.simplecmd(CTRL_ENABLE)
187
188 def waitready(self):
189 rep = self._waitdata(1, 60)
190 if rep == None:
191 raise error, 'Command not finished in one minute'
192 if rep not in (COMPLETION, ACK):
193 self._iflush()
194 raise error, 'Unexpected waitready reply:' + `rep`
195
196 def play(self): return self.simplecmd(PLAY)
197 def stop(self): return self.simplecmd(STOP)
198 def ff(self): return self.simplecmd(FF)
199 def rew(self): return self.simplecmd(REW)
200 def eject(self):return self.simplecmd(EJECT)
201 def still(self):return self.simplecmd(STILL)
202 def step(self): return self.simplecmd(STEP_FWD)
203
204 def goto(self, (h, m, s, f)):
205 if not self.simplecmd(SEARCH_DATA):
206 return 0
207 self._number(h, 2)
208 self._number(m, 2)
209 self._number(s, 2)
210 self._number(f, 2)
211 if not self.simplecmd(ENTER):
212 return 0
213 self.waitready()
214 return 1
215
216 # XXXX TC_SENSE doesn't seem to work
217 def faulty_where(self):
218 self._cmd(TC_SENSE)
219 h = self._getnumber(2)
220 m = self._getnumber(2)
221 s = self._getnumber(2)
222 f = self._getnumber(2)
223 return (h, m, s, f)
224
225 def where(self):
226 return self.addr2tc(self.sense())
227
228 def sense(self):
229 self._cmd(ADDR_SENSE)
230 num = self._getnumber(5)
231 return num
232
233 def addr2tc(self, num):
234 f = num % 25
235 num = num / 25
236 s = num % 60
237 num = num / 60
238 m = num % 60
239 h = num / 60
240 return (h, m, s, f)
241
242 def tc2addr(self, (h, m, s, f)):
243 return ((h*60 + m)*60 + s)*25 + f
244
245 def fmmode(self, mode):
246 if mode == 'off':
247 arg = 0
248 elif mode == 'buffer':
249 arg = 1
250 elif mode == 'dnr':
251 arg = 2
252 else:
253 raise error, 'fmmode arg should be off, buffer or dnr'
254 if not self.simplecmd(FM_SELECT):
255 return 0
256 self._number(arg, 1)
257 if not self.simplecmd(ENTER):
258 return 0
259 return 1
260
261 def fmstill(self):
262 if not self.simplecmd(FM_STILL):
263 return 0
264 self.waitready()
265 return 1
266
267 def dmcontrol(self, mode):
268 if mode == 'off':
269 return self.simplecmd(DM_OFF)
270 if mode == 'multi freeze':
271 num = 1000
272 elif mode == 'zoom freeze':
273 num = 2000
274 elif mode == 'digital slow':
275 num = 3000
276 elif mode == 'freeze':
277 num = 4011
278 else:
279 raise error, 'unknown dmcontrol argument: ' + `mode`
280 if not self.simplecmd(DM_SET):
281 return 0
282 self._number(num, 4)
283 if not self.simplecmd(ENTER):
284 return 0
285 return 1
286
287 def fwdshuttle(self, num):
288 if not self.simplecmd(FWD_SHUTTLE):
289 return 0
290 self._number(num, 1)
291 return 1
292
293 def revshuttle(self, num):
294 if not self.simplecmd(REV_SHUTTLE):
295 return 0
296 self._number(num, 1)
297 return 1