blob: d99fce67208bfe4c2009fd9130d5597b2d1b0654 [file] [log] [blame]
Guido van Rossum605b1271993-05-12 12:35:44 +00001import fcntl
2import IOCTL
3from IOCTL import *
4import sys
5import struct
6import select
Guido van Rossumfa041701993-06-10 13:32:32 +00007import posix
Guido van Rossum605b1271993-05-12 12:35:44 +00008
9DEVICE='/dev/ttyd2'
10
Guido van Rossumfa041701993-06-10 13:32:32 +000011class UnixFile:
12 def open(self, name, mode):
13 self.fd = posix.open(name, mode)
14 return self
15
16 def read(self, len):
17 return posix.read(self.fd, len)
18
19 def write(self, data):
20 dummy = posix.write(self.fd, data)
21
22 def flush(self):
23 pass
24
25 def fileno(self):
26 return self.fd
27
28 def close(self):
29 dummy = posix.close(self.fd)
30
Guido van Rossum605b1271993-05-12 12:35:44 +000031def packttyargs(*args):
32 if type(args) <> type(()):
33 raise 'Incorrect argtype for packttyargs'
34 if type(args[0]) == type(1):
35 iflag, oflag, cflag, lflag, line, chars = args
36 elif type(args[0]) == type(()):
37 if len(args) <> 1:
38 raise 'Only 1 argument expected'
39 iflag, oflag, cflag, lflag, line, chars = args[0]
40 elif type(args[0]) == type([]):
41 if len(args) <> 1:
42 raise 'Only 1 argument expected'
43 [iflag, oflag, cflag, lflag, line, chars] = args[0]
44 str = struct.pack('hhhhb', iflag, oflag, cflag, lflag, line)
45 for c in chars:
46 str = str + c
47 return str
48
49def nullttyargs():
50 chars = ['\0']*IOCTL.NCCS
51 return packttyargs(0, 0, 0, 0, 0, chars)
52
53def unpackttyargs(str):
54 args = str[:-IOCTL.NCCS]
55 rawchars = str[-IOCTL.NCCS:]
56 chars = []
57 for c in rawchars:
58 chars.append(c)
59 iflag, oflag, cflag, lflag, line = struct.unpack('hhhhb', args)
60 return (iflag, oflag, cflag, lflag, line, chars)
61
62def initline(name):
Guido van Rossumfa041701993-06-10 13:32:32 +000063 fp = UnixFile().open(name, 2)
64 ofp = fp
Guido van Rossum605b1271993-05-12 12:35:44 +000065 fd = fp.fileno()
66 rv = fcntl.ioctl(fd, IOCTL.TCGETA, nullttyargs())
67 iflag, oflag, cflag, lflag, line, chars = unpackttyargs(rv)
68 iflag = iflag & ~(INPCK|ISTRIP|INLCR|IUCLC|IXON|IXOFF)
69 oflag = oflag & ~OPOST
70 cflag = B9600|CS8|CREAD|CLOCAL
71 lflag = lflag & ~(ISIG|ICANON|ECHO|TOSTOP)
72 chars[VMIN] = chr(1)
73 chars[VTIME] = chr(0)
74 arg = packttyargs(iflag, oflag, cflag, lflag, line, chars)
75 dummy = fcntl.ioctl(fd, IOCTL.TCSETA, arg)
76 return fp, ofp
77
78#ifp, ofp = initline('/dev/ttyd2')
79#while 1:
80# print 'GO'
81# inset, d, d = select.select([sys.stdin, ifp], [], [])
82# if sys.stdin in inset:
83# cmd = eval(sys.stdin.readline(100))
84# print 'CMD:', `cmd`
85# if cmd:
86# ofp.write(cmd)
87# ofp.flush()
88# if ifp in inset:
89# data = ifp.read(1)
90# print 'LEN', len(data), 'DATA', `data`
91
92error = 'VCR.error'
93
94# Commands/replies:
95COMPLETION = '\x01'
96ACK ='\x0a'
97NAK ='\x0b'
98
99NUMBER_N = 0x30
100ENTER = '\x40'
101
102EXP_7= '\xde'
103EXP_8= '\xdf'
104
105CL ='\x56'
106CTRL_ENABLE = EXP_8 + '\xc6'
107SEARCH_DATA = EXP_8 + '\x93'
108ADDR_SENSE = '\x60'
109
110PLAY ='\x3a'
111STOP ='\x3f'
112EJECT='\x2a'
113FF ='\xab'
114REW ='\xac'
115STILL='\x4f'
Guido van Rossumfa041701993-06-10 13:32:32 +0000116STEP_FWD ='\x2b' # Was: '\xad'
Guido van Rossum605b1271993-05-12 12:35:44 +0000117FM_SELECT=EXP_8 + '\xc8'
118FM_STILL=EXP_8 + '\xcd'
119DM_OFF=EXP_8 + '\xc9'
120DM_SET=EXP_8 + '\xc4'
121FWD_SHUTTLE='\xb5'
122REV_SHUTTLE='\xb6'
Guido van Rossumfa041701993-06-10 13:32:32 +0000123EM_SELECT=EXP_8 + '\xc0'
124N_FRAME_REC=EXP_8 + '\x92'
125
126IN_ENTRY=EXP_7 + '\x90'
127IN_ENTRY_RESET=EXP_7 + '\x91'
128IN_ENTRY_SET=EXP_7 + '\x98'
129IN_ENTRY_INC=EXP_7 + '\x94'
130IN_ENTRY_DEC=EXP_7 + '\x95'
131IN_ENTRY_SENSE=EXP_7 + '\x9a'
132
133OUT_ENTRY=EXP_7 + '\x92'
134OUT_ENTRY_RESET=EXP_7 + '\x93'
135OUT_ENTRY_SET=EXP_7 + '\x99'
136OUT_ENTRY_INC=EXP_7 + '\x96'
137OUT_ENTRY_DEC=EXP_7 + '\x98'
138OUT_ENTRY_SENSE=EXP_7 + '\x9b'
139
140DEBUG=0
Guido van Rossum605b1271993-05-12 12:35:44 +0000141
Jack Jansena1e1f731993-06-08 12:47:06 +0000142class VCR:
Guido van Rossum605b1271993-05-12 12:35:44 +0000143 def init(self):
144 self.ifp, self.ofp = initline(DEVICE)
145 return self
146
147 def _cmd(self, cmd):
Guido van Rossumfa041701993-06-10 13:32:32 +0000148 if DEBUG:
149 print '>>>',`cmd`
Guido van Rossum605b1271993-05-12 12:35:44 +0000150 self.ofp.write(cmd)
151 self.ofp.flush()
152
153 def _waitdata(self, len, tout):
154 rep = ''
155 while len > 0:
156 ready, d1, d2 = select.select([self.ifp], [], [], tout)
157 if ready == []:
158## if rep:
159## print 'FLUSHED:', `rep`
160 return None
Guido van Rossumfa041701993-06-10 13:32:32 +0000161 # XXXX Niet goed: er is meer gebufferd!
Guido van Rossum605b1271993-05-12 12:35:44 +0000162 data = self.ifp.read(1)
Guido van Rossumfa041701993-06-10 13:32:32 +0000163 if DEBUG:
164 print '<<<',`data`
Guido van Rossum605b1271993-05-12 12:35:44 +0000165 if data == NAK:
166 return NAK
167 rep = rep + data
168 len = len - 1
169 return rep
170
171 def _reply(self, len):
172 data = self._waitdata(len, 10)
173 if data == None:
174 raise error, 'Lost contact with VCR'
175 return data
176
177 def _getnumber(self, len):
178 data = self._reply(len)
179 number = 0
180 for c in data:
181 digit = ord(c) - NUMBER_N
182 if digit < 0 or digit > 9:
183 raise error, 'Non-digit in number'+`c`
184 number = number*10 + digit
185 return number
186
187 def _iflush(self):
Guido van Rossumfa041701993-06-10 13:32:32 +0000188 dummy = self._waitdata(10000, 0)
Guido van Rossum605b1271993-05-12 12:35:44 +0000189## if dummy:
190## print 'IFLUSH:', dummy
191
192 def simplecmd(self,cmd):
Guido van Rossumfa041701993-06-10 13:32:32 +0000193 self._iflush()
Guido van Rossum605b1271993-05-12 12:35:44 +0000194 for ch in cmd:
195 self._cmd(ch)
196 rep = self._reply(1)
197 if rep == NAK:
198 return 0
199 elif rep <> ACK:
200 raise error, 'Unexpected reply:' + `rep`
201 return 1
202
Guido van Rossumfa041701993-06-10 13:32:32 +0000203 def replycmd(self, cmd):
204 if not self.simplecmd(cmd[:-1]):
205 return 0
206 self._cmd(cmd[-1])
207
Guido van Rossum605b1271993-05-12 12:35:44 +0000208 def _number(self, number, digits):
209 if number < 0:
210 raise error, 'Unexpected negative number:'+ `number`
211 maxnum = pow(10, digits)
212 if number > maxnum:
213 raise error, 'Number too big'
214 while maxnum > 1:
215 number = number % maxnum
216 maxnum = maxnum / 10
217 digit = number / maxnum
218 ok = self.simplecmd(chr(NUMBER_N + digit))
219 if not ok:
220 raise error, 'Error while transmitting number'
221
222 def wait(self):
223 self._iflush()
224 while 1:
225## print 'SENDCL'
226 self._cmd(CL)
227 rep = self._waitdata(1, 2)
228## print `rep`
229 if rep in ( None, CL, NAK ):
230 continue
231 break
232 if rep <> ACK:
233 raise error, 'Unexpected reply:' + `rep`
234 dummy = self.simplecmd(CTRL_ENABLE)
235
236 def waitready(self):
237 rep = self._waitdata(1, 60)
238 if rep == None:
239 raise error, 'Command not finished in one minute'
240 if rep not in (COMPLETION, ACK):
241 self._iflush()
242 raise error, 'Unexpected waitready reply:' + `rep`
243
244 def play(self): return self.simplecmd(PLAY)
245 def stop(self): return self.simplecmd(STOP)
246 def ff(self): return self.simplecmd(FF)
247 def rew(self): return self.simplecmd(REW)
248 def eject(self):return self.simplecmd(EJECT)
249 def still(self):return self.simplecmd(STILL)
250 def step(self): return self.simplecmd(STEP_FWD)
251
252 def goto(self, (h, m, s, f)):
253 if not self.simplecmd(SEARCH_DATA):
254 return 0
255 self._number(h, 2)
256 self._number(m, 2)
257 self._number(s, 2)
258 self._number(f, 2)
259 if not self.simplecmd(ENTER):
260 return 0
261 self.waitready()
262 return 1
263
264 # XXXX TC_SENSE doesn't seem to work
265 def faulty_where(self):
266 self._cmd(TC_SENSE)
267 h = self._getnumber(2)
268 m = self._getnumber(2)
269 s = self._getnumber(2)
270 f = self._getnumber(2)
271 return (h, m, s, f)
272
273 def where(self):
274 return self.addr2tc(self.sense())
275
276 def sense(self):
277 self._cmd(ADDR_SENSE)
278 num = self._getnumber(5)
279 return num
280
281 def addr2tc(self, num):
282 f = num % 25
283 num = num / 25
284 s = num % 60
285 num = num / 60
286 m = num % 60
287 h = num / 60
288 return (h, m, s, f)
289
290 def tc2addr(self, (h, m, s, f)):
291 return ((h*60 + m)*60 + s)*25 + f
292
293 def fmmode(self, mode):
294 if mode == 'off':
295 arg = 0
296 elif mode == 'buffer':
297 arg = 1
298 elif mode == 'dnr':
299 arg = 2
300 else:
301 raise error, 'fmmode arg should be off, buffer or dnr'
302 if not self.simplecmd(FM_SELECT):
303 return 0
304 self._number(arg, 1)
305 if not self.simplecmd(ENTER):
306 return 0
307 return 1
308
Guido van Rossumfa041701993-06-10 13:32:32 +0000309 def editmode(self, mode):
310 if mode == 'off':
311 a0 = a1 = a2 = 0
312 elif mode == 'format':
313 a0 = 4
314 a1 = 7
315 a2 = 4
316 elif mode == 'asmbl':
317 a0 = 1
318 a1 = 7
319 a2 = 4
320 elif mode == 'insert-video':
321 a0 = 2
322 a1 = 4
323 a2 = 0
324 else:
325 raise 'editmode should be off,format,asmbl or insert-video'
326 if not self.simplecmd(EM_SELECT):
327 return 0
328 self._number(a0, 1)
329 self._number(a1, 1)
330 self._number(a2, 1)
331 if not self.simplecmd(ENTER):
332 return 0
333 return 1
334
335 def nframerec(self, num):
336 if not self.simplecmd(N_FRAME_REC):
337 return 0
338 self._number(num, 4)
339 if not self.simplecmd(ENTER):
340 return 0
341 self.waitready()
342 return 1
343
Guido van Rossum605b1271993-05-12 12:35:44 +0000344 def fmstill(self):
345 if not self.simplecmd(FM_STILL):
346 return 0
347 self.waitready()
348 return 1
349
350 def dmcontrol(self, mode):
351 if mode == 'off':
352 return self.simplecmd(DM_OFF)
353 if mode == 'multi freeze':
354 num = 1000
355 elif mode == 'zoom freeze':
356 num = 2000
357 elif mode == 'digital slow':
358 num = 3000
359 elif mode == 'freeze':
360 num = 4011
361 else:
362 raise error, 'unknown dmcontrol argument: ' + `mode`
363 if not self.simplecmd(DM_SET):
364 return 0
365 self._number(num, 4)
366 if not self.simplecmd(ENTER):
367 return 0
368 return 1
369
370 def fwdshuttle(self, num):
371 if not self.simplecmd(FWD_SHUTTLE):
372 return 0
373 self._number(num, 1)
374 return 1
375
376 def revshuttle(self, num):
377 if not self.simplecmd(REV_SHUTTLE):
378 return 0
379 self._number(num, 1)
380 return 1
Guido van Rossumfa041701993-06-10 13:32:32 +0000381
382 def getentry(self, which):
383 if which == 'in':
384 cmd = IN_ENTRY_SENSE
385 elif which == 'out':
386 cmd = OUT_ENTRY_SENSE
387 self.replycmd(cmd)
388 h = self._getnumber(2)
389 print 'h=',h
390 m = self._getnumber(2)
391 print 'm=',m
392 s = self._getnumber(2)
393 print 's=',s
394 f = self._getnumber(2)
395 print 'f=',f
396 return (h, m, s, f)
397
398 def inentry(self, arg):
399 return self.ioentry(arg, (IN_ENTRY, IN_ENTRY_RESET, \
400 IN_ENTRY_SET, IN_ENTRY_INC, IN_ENTRY_DEC))
401
402 def outentry(self, arg):
403 return self.ioentry(arg, (OUT_ENTRY, OUT_ENTRY_RESET, \
404 OUT_ENTRY_SET, OUT_ENTRY_INC, OUT_ENTRY_DEC))
405
406 def ioentry(self, arg, (Load, Clear, Set, Inc, Dec)):
407 if type(arg) == type(()):
408 h, m, s, f = arg
409 if not self.simplecmd(Set):
410 return 0
411 self._number(h,2)
412 self._number(m,2)
413 self._number(s,2)
414 self._number(f,2)
415 if not self.simplecmd(ENTER):
416 return 0
417 return 1
418 elif arg == 'reset':
419 cmd = Clear
420 elif arg == 'load':
421 cmd = Load
422 elif arg == '+':
423 cmd = Inc
424 elif arg == '-':
425 cmd = Dec
426 else:
427 raise error, 'Arg should be +,-,reset,load or (h,m,s,f)'
428 return self.simplecmd(cmd)