1import wxctb, sys, re
2
3DCD = wxctb.LinestateDcd
4CTS = wxctb.LinestateCts
5DSR = wxctb.LinestateDsr
6DTR = wxctb.LinestateDtr
7RING = wxctb.LinestateRing
8RTS = wxctb.LinestateRts
9NULL = wxctb.LinestateNull
10
11def abstract():
12    import inspect
13    caller = inspect.getouterframes(inspect.currentframe())[1][3]
14    raise NotImplementedError(caller + ' must be implemented in subclass')
15
16class IOBase:
17    def __init__(self):
18        self.device = None
19        # set timeout to 1000ms (the default)
20        self.timeout = 1000
21
22    def __del__(self):
23        pass
24
25    def Close(self):
26        if self.device:
27            self.device.Close()
28
29    def GetTimeout(self):
30        """
31        Returns the internal timeout value in milliseconds
32        """
33        return self.timeout
34
35    def Ioctl(self,cmd,arg):
36        if self.device:
37            self.device.Ioctl(cmd,arg)
38
39    def Open(self):
40        abstract()
41
42    def PutBack(self,char):
43        return self.device.PutBack(char)
44
45    def Read(self,length):
46        """
47        Try to read the given count of data (length) and returns the
48        successfully readed number of data. The function never blocks.
49        For example:
50        readed = dev.Read(100)
51        """
52        buf = "\x00"*(length+1)
53        rd = self.device.Read(buf,length)
54        return buf[0:rd]
55
56    def ReadBinary(self,eos="\n"):
57        """
58        Special SCPI command. Read the next data coded as a SCPI
59        binary format.
60        A binary data transfer will be startet by '#'. The next byte
61        tells the count of bytes for the binary length header,
62        following by the length bytes. After these the data begins.
63        For example:
64        #500004xxxx
65        The header length covers 5 Byte, the length of the binary
66        data is 4 (x means the binary data bytes)
67        """
68        try:
69            eoslen = len(eos)
70            b=self.Readv(2)
71            if len(b) == 2:
72                hl = int(b[1])
73                b = self.Readv(hl)
74                if len(b) == hl:
75                    dl = int(b)
76                    # don't left over the eos string or character in the
77                    # device input buffer
78                    data = self.Readv(dl+eoslen)
79                    # check, if the binary data block is complete
80                    if data[dl] == '#':
81                        # not complete, another block is following
82                        for c in data[dl:dl+eoslen]:
83                            self.PutBack(c)
84
85                        data = data[:dl] + self.ReadBinary()
86                    return data
87        except:
88            pass
89        return ''
90
91    def ReadUntilEOS(self,eos="\n",quota=0):
92        """
93        ReadUntilEOS(eosString=\"\\n\",timeout=1000)
94        Reads data until the given eos string was received (default is
95        the linefeed character (0x0a) or the internal timeout
96        (default 1000ms) was reached.
97        ReadUntilEOS returns the result as the following tuple:
98        ['received string',state,readedBytes]
99        If a timeout occurred, state is 0, otherwise 1
100        """
101        return self.device.ReadUntilEOS("",0,eos,self.timeout,quota)
102
103    def Readv(self,length):
104        """
105        Try to read the given count of data. Readv blocks until all data
106        was readed successfully or the internal timeout, set with the
107        class member function SetTimeout(timeout), was reached.
108        Returns the readed data.
109        """
110        buf = "\x00"*length
111        rd = self.device.Readv(buf,length,self.timeout)
112        return buf[0:rd]
113
114    def ResetBus(self):
115        """
116        If the underlaying interface needs some special reset operations
117        (for instance the GPIB distinguish between a normal device reset
118        and a special bus reset), you can put some code here)
119        """
120        pass
121
122    def SetTimeout(self,timeout):
123        """
124        Set the internal timeout value in milliseconds for all blocked
125        operations like ReadUntilEOS, Readv and Writev.
126        """
127        self.timeout = timeout
128
129    def Write(self,string):
130        """
131        Writes the given string to the device and returns immediately.
132        Write returns the number of data bytes successfully written or a
133        negativ number if an error occured. For some circumstances, not
134        the complete string was written.
135        So you have to verify the return value to check this out.
136        """
137        return self.device.Write(string,len(string))
138
139    def Writev(self,string):
140        """
141        Writes the given string to the device. The function blocks until
142        the complete string was written or the internal timeout, set with
143        SetTimeout(timeout), was reached.
144        Writev returns the number of data successfully written or a
145        negativ value, if an errors occurred.
146        """
147        return self.device.Writev(string,len(string),self.timeout)
148
149class SerialPort(IOBase):
150    def __init__(self):
151        IOBase.__init__(self)
152
153    def __del__(self):
154        self.Close()
155
156    def ChangeLineState(self,lineState):
157        """
158        Change (toggle) the state of each the lines given in the
159        linestate parameter. Possible values are DTR and/or RTS.
160        For example to toggle the RTS line only:
161        dev.ChangeLineState(RTS)
162        """
163        self.device.ChangeLineState(lineState)
164
165    def ClrLineState(self,lineState):
166        """
167        Clear the lines given in the linestate parameter. Possible
168        values are DTR and/or RTS. For example to clear only
169        the RTS line:
170        dev.ClrLineState(RTS)
171        """
172        self.device.ClrLineState(lineState)
173
174    def GetAvailableBytes(self):
175        """
176        Returns the available bytes in the input queue of the serial
177        driver.
178        """
179        n = wxctb.new_intp()
180        wxctb.intp_assign(n, 0)
181        self.device.Ioctl(wxctb.CTB_SER_GETINQUE,n)
182        return wxctb.intp_value(n)
183
184    def GetCommErrors(self):
185        """
186        Get the internal communication errors like breaks, framing,
187        parity or overrun errors.
188        Returns the count of each error as a tuple like this:
189        (b,f,o,p) = dev.GetCommErrors()
190        b: breaks, f: framing errors,  o: overruns, p: parity errors
191        """
192        einfo = wxctb.SerialPort_EINFO()
193        self.device.Ioctl(wxctb.CTB_SER_GETEINFO,einfo)
194        return einfo.brk,einfo.frame,einfo.overrun,einfo.parity
195
196    def GetLineState(self):
197        """
198        Returns the current linestates of the CTS, DCD, DSR and RING
199        signal line as an integer value with the appropriate bits or
200        -1 on error.
201        For example:
202        lines = dev.GetLineState()
203        if lines & CTS:
204            print \"CTS is on\"
205        """
206        return self.device.GetLineState()
207
208    def Open(self,devname,baudrate,protocol='8N1',handshake='no_handshake'):
209        """
210        Open the device devname with the given baudrate, the protocol
211        like '8N1' (default) and the use of the handshake [no_handshake
212        (default), rtscts or xonxoff]
213        For example:
214        At Linux:
215        dev = SerialPort()
216        dev.Open(\"/dev/ttyS0\",115200)
217        or with a datalen of 7 bits, even parity, 2 stopbits and rts/cts
218        handshake:
219        dev.Open(\"/dev/ttyS0\",115200,'7E2',True)
220        At Windows:
221        dev = SerialPort()
222        dev.Open(\"COM1\",115200)
223        dev.Open(\"COM1\",115200,'7E2',True)
224        Returns the handle on success or a negativ value on failure.
225        """
226        # the following parity values are valid:
227        # N:None, O:Odd, E:Even, M:Mark, S:Space
228        parity = {'N':0,'O':1,'E':2,'M':3,'S':4}
229        # the regular expression ensures a valid value for the datalen
230        # (5...8 bit) and the count of stopbits (1,2)
231        reg=re.compile(r"(?P<w>[8765])"r"(?P<p>[NOEMS])"r"(?P<s>[12])")
232        self.device = wxctb.SerialPort()
233        dcs = wxctb.SerialPort_DCS()
234        dcs.baud = baudrate
235        res = reg.search(protocol)
236        # handle the given protocol
237        if res:
238            dcs.wordlen = int(res.group('w'))
239            dcs.stopbits = int(res.group('s'))
240            dcs.parity = parity[res.group('p')]
241        # valid handshake are no one, rts/cts or xon/xoff
242        if handshake == 'rtscts':
243            dcs.rtscts = True
244        elif handshake == 'xonxoff':
245            dcs.xonxoff = True
246
247        return self.device.Open(devname,dcs)
248
249    def Reset(self):
250        """
251        Send a break for 0.25s.
252        """
253        self.device.SendBreak(0)
254
255    def SetBaudrate(self,baudrate):
256        """
257        Set the baudrate for the device.
258        """
259        self.device.SetBaudrate(baudrate)
260
261    def SetLineState(self,lineState):
262        """
263        Set the lines given in the linestate parameter. Possible
264        values are DTR and/or RTS. For example to set both:
265        dev.SetLineState( DTR | RTS)
266        """
267        self.device.SetLineState(lineState)
268
269    def SetParityBit(self,parity):
270        """
271        Set the parity bit explicitly to 0 or 1. Use this function, if
272        you would like to simulate a 9 bit wordlen at what the ninth bit
273        was represented by the parity bit value. For example:
274        dev.SetParityBit( 0 )
275        dev.Write('some data sent with parity 0')
276        dev.SetParityBit( 1 )
277        dev.Write('another sequence with parity 1')
278        """
279        return self.device.SetParityBit( parity )
280
281class GpibDevice(IOBase):
282    """
283    GPIB class
284    """
285    def __init__(self):
286        IOBase.__init__(self)
287
288    def __del__(self):
289        self.Close()
290
291    def FindListeners(self,board = 0):
292        """
293        Returns the address of the connected devices as a list.
294        If no device is listening, the list is empty. If an error
295        occurs an IOError exception raised. For example:
296        g = GPIB()
297        listeners = g.FindListeners()
298        """
299        listeners = wxctb.GPIB_x_FindListeners(board)
300        if listeners < 0:
301            raise IOError("GPIB board error")
302        result = []
303        for i in range(1,31):
304            if listeners & (1 << i):
305                result.append(i)
306        return result
307
308    def GetEosChar(self):
309        """
310        Get the internal EOS termination character (see SetEosChar).
311        For example:
312        g = GPIB()
313        g.Open(\"gpib1\",1)
314        eos = g.GetEosChar()
315        """
316        eos = wxctb.new_intp()
317        wxctb.intp_assign(eos, 0)
318        self.device.Ioctl(wxctb.CTB_GPIB_GET_EOS_CHAR,eos)
319        return wxctb.intp_value(eos)
320
321    def GetEosMode(self):
322        """
323        Get the internal EOS mode (see SetEosMode).
324        For example:
325        g = GPIB()
326        g.Open(\"gpib1\",1)
327        eos = g.GetEosMode()
328        """
329        mode = wxctb.new_intp()
330        wxctb.intp_assign(mode, 0)
331        self.device.Ioctl(wxctb.CTB_GPIB_GET_EOS_MODE,mode)
332        return wxctb.intp_value(mode)
333
334    def GetError(self):
335        errorString = " "*256
336        self.device.GetError(errorString,256)
337        return errorString
338
339    def GetSTB(self):
340        """
341        Returns the value of the internal GPIB status byte register.
342        """
343        stb = wxctb.new_intp()
344        wxctb.intp_assign(stb, 0)
345        self.device.Ioctl(wxctb.CTB_GPIB_GETRSP,stb)
346        return wxctb.intp_value(stb)
347
348    # This is only for internal usage!!!
349    def Ibrd(self,length):
350        buf = "\x00"*length
351        state = self.device.Ibrd(buf,length)
352        return state,buf
353
354    # This is only for internal usage!!!
355    def Ibwrt(self,string):
356        return self.device.Ibwrt(string,len(string))
357
358    def Open(self,devname,adr,eosChar=10,eosMode=0x08|0x04):
359        """
360        Open(gpibdevice,address,eosChar,eosMode)
361        Opens a connected device at the GPIB bus. gpibdevice means the
362        controller, (mostly \"gpib1\"), address the address of the desired
363        device in the range 1...31. The eosChar defines the EOS character
364        (default is linefeed), eosMode may be a combination of bits ORed
365        together. The following bits can be used:
366        0x04: Terminate read when EOS is detected.
367        0x08: Set EOI (End or identify line) with EOS on write function
368        0x10: Compare all 8 bits of EOS byte rather than low 7 bits
369              (all read and write functions). Default is 0x12
370        For example:
371        dev = GPIB()
372        dev.Open(\"gpib1\",17)
373        Opens the device with the address 17, linefeed as EOS (default)
374        and eos mode with 0x04 and 0x08.
375        Open returns >= 0 or a negativ value, if something going wrong.
376        """
377        self.device = wxctb.GpibDevice()
378        dcs = wxctb.Gpib_DCS()
379        dcs.m_address1 = adr
380        dcs.m_eosChar = eosChar
381        dcs.m_eosMode = eosMode
382        result = self.device.Open(devname,dcs)
383        return result
384
385    def Reset(self):
386        """
387        Resets the connected device. In the GPIB definition, the device
388        should be reset to it's initial state, so you can restart a
389        formely lost communication.
390        """
391        self.device.Ioctl(wxctb.CTB_RESET,None)
392
393    def ResetBus(self):
394        """
395        The command asserts the GPIB interface clear (IFC) line for
396        ast least 100us if the GPIB board is the system controller.
397        This initializes the GPIB and makes the interface CIC and
398        active controller with ATN asserted.
399        Note! The IFC signal resets only the GPIB interface functions
400        of the bus devices and not the internal device functions.
401        For a device reset you should use the Reset() command above.
402        """
403        self.device.Ioctl(wxctb.CTB_GPIB_RESET_BUS,None)
404
405    def SetEosChar(self,eos):
406        """
407        Configure the end-of-string (EOS) termination character.
408        Note! Defining an EOS byte does not cause the driver to
409        automatically send that byte at the end of write I/O
410        operations. The application is responsible for placing the
411        EOS byte at the end of the data strings that it defines.
412        (National Instruments NI-488.2M Function Reference Manual)
413        For example:
414        g = GPIB()
415        g.Open(\"gpib1\",1)
416        eos = g.GetEosChar(0x10)
417        """
418        intp = wxctb.new_intp()
419        wxctb.intp_assign(intp, eos)
420        return self.device.Ioctl(wxctb.CTB_GPIB_SET_EOS_CHAR,intp)
421
422    def SetEosMode(self,mode):
423        """
424        Set the EOS mode (handling).m_eosMode may be a combination
425        of bits ORed together. The following bits can be used:
426        0x04: Terminate read when EOS is detected.
427        0x08: Set EOI (End or identify line) with EOS on write function
428        0x10: Compare all 8 bits of EOS byte rather than low 7 bits
429        (all read and write functions). For example:
430        g = GPIB()
431        g.Open(\"gpib1\",1)
432        eos = g.GetEosMode(0x04 | 0x08)
433        """
434        intp = wxctb.new_intp()
435        wxctb.intp_assign(intp, mode)
436        return self.device.Ioctl(wxctb.CTB_GPIB_SET_EOS_MODE,intp)
437
438def GetKey():
439    """
440    Returns the current pressed key or '\0', if no key is pressed.
441    You can simply create a query loop with:
442    while GetKey() == '\0':
443        ... make some stuff ...
444
445    """
446    return wxctb.GetKey()
447
448def GetVersion():
449    """
450    Returns the version of the ctb python module. The numbering
451    has the following format: x.y.z
452    x.y means the version of the underlaying ctb lib, z the version
453    of the python port.
454    """
455    return "0.16"
456