1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
#!/usr/bin/env python
# LeCrunch
# Copyright (C) 2010 Anthony LaTorre
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import struct
import socket
import os
headerformat = '>BBBBL'
errors = { 1 : 'unrecognized command/query header',
2 : 'illegal header path',
3 : 'illegal number',
4 : 'illegal number suffix',
5 : 'unrecognized keyword',
6 : 'string error',
7 : 'GET embedded in another message',
10 : 'arbitrary data block expected',
11 : 'non-digit character in byte count field of ' \
'arbitrary data block',
12 : 'EOI detected during definite length data block transfer',
13 : 'extra bytes detected during definite length data block ' \
'transfer' }
class Scope(object):
"""
A class for low level communication with the oscilliscope over a socket
connection.
"""
def __init__(self, host, port=1861, timeout=2.0):
"""Create a socket object to *host* over *port*"""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.settimeout(timeout)
self.host = host
self.port = port
self.timeout = timeout
def settimeout(self, timeout):
"""Set the *timeout* for the socket connection in seconds."""
self.sock.settimeout(timeout)
self.timeout = timeout
def connect(self):
"""Make the socket connection."""
self.sock.connect((self.host, self.port))
def clear(self):
"""Clear the oscilloscope's output queue."""
self.sock.settimeout(2.0)
try:
while True:
self.sock.recv(100)
except socket.timeout:
pass
self.sock.settimeout(self.timeout)
def close(self):
"""Close the socket connection."""
self.sock.close()
def send(self, str):
"""Format and send the string *str*."""
if not str.endswith('\n'):
str += '\n'
header = struct.pack(headerformat, 129, 1, 1, 0, len(str))
self.sock.sendall(header + str)
def check_last_command(self):
"""
Check that the last command sent was received okay; if not, then
raise an exception with details about the error.
"""
self.send('cmr?')
err = int(self.recv().split(' ')[-1].rstrip('\n'))
if err in errors:
self.close()
raise Exception(errors[err])
def getheader(self):
"""
Unpacks a header string from the oscilloscope into the tuple
(operation, header version, sequence number, spare, total bytes).
"""
return struct.unpack(headerformat, self.sock.recv(8))
def recv(self):
"""
Receive, concatenate, and return a 'logical series' of blocks from
the oscilloscope. A 'logical series' consists of one or more blocks
in which the final block is terminated by an EOI terminator
(i.e. the EOI bit in the header block is set to '1').
"""
reply = ''
while True:
operation, headerver, seqnum, spare, totalbytes = self.getheader()
buffer = ''
while len(buffer) < totalbytes:
buffer += self.sock.recv(totalbytes - len(buffer))
reply += buffer
if operation % 2:
break
return reply
if __name__ == '__main__':
import sys
import setup
scope = Scope(setup.scope_ip)
scope.connect()
scope.clear()
for msg in sys.argv[1:]:
scope.send(msg)
if '?' in msg:
print repr(scope.recv())
scope.check_last_command()
scope.close()
|