Skip to content

Commit 2fd4782

Browse files
Mirko Dietrichventhur
Mirko Dietrich
authored andcommitted
Added g-STIMbox module
1 parent a4f4fd6 commit 2fd4782

File tree

3 files changed

+313
-0
lines changed

3 files changed

+313
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ ThumbsDB
44
\#*#
55
.#*
66
*pyc
7+
doc/_build

doc/lib/gstimbox.rst

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
:mod:`gstimbox` --- Driver for g-STIMbox
2+
========================================
3+
4+
.. automodule:: lib.gstimbox
5+
:synopsis: Hardware driver for g-STIMbox
6+
:members:
7+
8+
moduleauthor:: Mirko Dietrich <mirko.dietrich(AT)bccn-berlin(DOT)de>

src/lib/gstimbox.py

+304
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
# gstimbox.py -
2+
# Copyright (C) 2010 Mirko Dietrich
3+
#
4+
# This program is free software; you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation; either version 2 of the License, or
7+
# (at your option) any later version.
8+
#
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
#
14+
# You should have received a copy of the GNU General Public License along
15+
# with this program; if not, write to the Free Software Foundation, Inc.,
16+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17+
18+
"""
19+
g-STIMbox is a stimulator digital I/O box with an USB interface
20+
manufactured by `g.tec medical engineering GmbH
21+
<http://www.gtec.at/>`_. The device features 14 digital inputs and 16
22+
digital outputs. This module encapsulates a proprietary DLL
23+
(Dynamic-link library) that operates exclusively under `Microsoft
24+
Windows <http://www.microsoft.com/windows/>`_.
25+
26+
g-STIMbox Installation
27+
======================
28+
29+
In order to install the device follow these steps:
30+
31+
#. Get ``USB_Driver.exe`` from the g-STIMbox driver package and execute it
32+
with administrator privileges. It will install the driver for the USB
33+
serial port.
34+
#. Connect the g-STIMbox device to a free USB socket.
35+
#. Open the *device manager* and find *USB Serial Port* under section *Ports*.
36+
It should specify the virtual COM port the device is connected to in
37+
brackets (e.g. COM3 meaning port number 3).
38+
#. Now you can already test the device by calling ``gSTIMboxDemo1.exe`` that
39+
is also included in the driver package.
40+
41+
For this Python module to work follow these steps:
42+
43+
#. Make sure the ``gSTIMbox.dll`` file is available when using the device. The
44+
easiest way is to put the file into the system folder (on most Windows
45+
installations this is ``C:\Windows\System``). Another way is to copy it to
46+
the same folder where this module resides.
47+
#. Run the :mod:`demo feedback <Feedbacks.GstimboxDemo.GstimboxDemo>` or
48+
have a look at section :ref:`gstimbox-usage`.
49+
50+
For further information refer to the PDF manual shipped with the
51+
device.
52+
53+
.. _gstimbox-usage:
54+
55+
Usage
56+
=====
57+
58+
Output modes
59+
------------
60+
61+
This example shows both output port operation modes (manual,
62+
frequency).
63+
64+
The output ports can be either controlled manually (ON/OFF) or
65+
assigned a specific frequency. It's possible to have different ports
66+
operate on different modes simultaneously (e.g. port 1 and 3 work in
67+
manual mode while 2 and 4 work in frequency mode).
68+
69+
Example code::
70+
71+
from sys import stdout
72+
from time import sleep
73+
from gstimbox import GStimbox
74+
75+
comport = 3
76+
b = GStimbox(comport)
77+
print "Connected to g-STIMbox (serial port %d)" % comport
78+
print "Driver version %s, firmware version %s" % \
79+
(b.getDriverVersion(), b.getHWVersion())
80+
print "Micro-controller frequency demo running..."
81+
stdout.flush()
82+
port = [0, 1, 2, 3, 4, 5, 6, 7]
83+
freq = [1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5]
84+
mode = [1, 1, 1, 1, 1, 1, 1, 1]
85+
b.reset()
86+
b.setFrequency(port, freq)
87+
b.setMode(port, mode)
88+
sleep(10)
89+
b.reset()
90+
print "Manual ON/OFF demo running..."
91+
stdout.flush()
92+
state = [0 for i in range(16)]
93+
for i in range(5):
94+
for j in range(8):
95+
state[j] = 1
96+
b.setPortState(state)
97+
sleep(0.1)
98+
for j in range(8):
99+
state[j] = 0
100+
b.setPortState(state)
101+
sleep(0.1)
102+
b.reset()
103+
print "Demo finished."
104+
105+
.. _gstimbox-usage-input:
106+
107+
Processing input
108+
----------------
109+
110+
In order to handle input from the g-STIMbox input ports a callback
111+
function must be specified. The callback function receives a single
112+
argument, a list of 14 values (e.g. ``[0, 1, 0, 1, 0, 0, 0, 0, 0, 0,
113+
0, 0, 0, 0]``). Each value maps to the corresponding input port
114+
(e.g. list index ``0`` corresponds to input port 1). In the example
115+
input ports 2 and 4 are active while all others are not. Note that the
116+
callback function is triggered on every state change (that is on
117+
pressing *and* releasing of a button).
118+
119+
The following example prints out the complete input state vector and
120+
activates all output ports if button on input port 1 is active
121+
(pressed).
122+
123+
Example code::
124+
125+
from sys import stdout
126+
from time import sleep
127+
from gstimbox import GStimbox
128+
129+
def input_callback(input_vector):
130+
global b
131+
print "Input vector changed:"
132+
print input_vector
133+
b.setPortState([input_vector[0] for i in range(16)])
134+
stdout.flush()
135+
136+
comport = 3
137+
b = GStimbox(comport, input_callback)
138+
print "Connected to g-STIMbox (serial port %d)" % comport
139+
print "Driver version %s, firmware version %s" % \
140+
(b.getDriverVersion(), b.getHWVersion())
141+
b.reset()
142+
print "Use a button connected to input port 1 to activate all output ports."
143+
print "This program will exit after 15 seconds."
144+
stdout.flush()
145+
sleep(15)
146+
b.reset()
147+
print "Demo finished."
148+
149+
"""
150+
151+
from ctypes import cdll, CFUNCTYPE, POINTER, c_void_p, c_int, c_double, c_char
152+
153+
class GStimbox:
154+
"""Create a connection to the g-STIMbox.
155+
156+
The serial port number defaults to ``3``. A callback function
157+
can be specified that handles signals from the input
158+
connectors (see :ref:`gstimbox-usage-input`).
159+
160+
"""
161+
162+
def __init__(self, port=3, callback=None):
163+
self.input_callback = callback
164+
try:
165+
self.dll = cdll.LoadLibrary("gSTIMbox")
166+
except WindowsError:
167+
raise GStimboxError("Could not find gSTIMbox.dll. Exiting...")
168+
if callback is not None:
169+
self.__register_input_callback(callback)
170+
r = self.dll.gSTIMboxinit(port, self.__cfunc_input_callback)
171+
else:
172+
r = self.dll.gSTIMboxinit(port)
173+
if (r != None):
174+
self.__device_handle = r
175+
else:
176+
raise GStimboxError("Could not connect to g-STIMbox.")
177+
178+
def __del__(self):
179+
self.reset()
180+
self.close()
181+
182+
def __input_callback(self, input_vector):
183+
r = [ord(input_vector[i]) for i in range(14)]
184+
self.__user_input_callback(r)
185+
186+
def __register_input_callback(self, input_callback):
187+
if not callable(input_callback):
188+
raise TypeError("Argument input_callback must be callable.")
189+
self.__user_input_callback = input_callback
190+
# create C function
191+
self.__INPUT_CB_TYPE = CFUNCTYPE(c_void_p, POINTER(c_char))
192+
self.__cfunc_input_callback = \
193+
self.__INPUT_CB_TYPE(self.__input_callback)
194+
195+
def reset(self):
196+
"""Reset device."""
197+
r = self.dll.gSTIMboxreset(self.__device_handle)
198+
if (r != 1):
199+
raise GStimboxError("Could not disconnect from g-STIMbox.")
200+
201+
def setMode(self, port, mode):
202+
"""Set the operation mode of output ports.
203+
204+
port is a list of port numbers to change (eg. ``[0, 2,
205+
3]``). Valid port numbers range from 0 to 15.
206+
207+
modes is a list of modes for the ports defined in the port
208+
variable. A mode value can be either ``0`` (controlled
209+
manually, see portState()) or ``1`` (microprocessor controlled
210+
frequency, see setFrequency()).
211+
212+
"""
213+
num = len(port)
214+
if type(port) != list:
215+
raise TypeError("Argument port must be a list.")
216+
if type(mode) != list:
217+
raise TypeError("Argument mode must be a list.")
218+
if num != len(mode):
219+
raise ValueError(
220+
"Arguments port and mode must be of same length.")
221+
port_carr = (c_int * num)()
222+
mode_carr = (c_int * num)()
223+
for i in range(num):
224+
port_carr[i] = c_int(port[i])
225+
mode_carr[i] = c_int(mode[i])
226+
r = self.dll.gSTIMboxsetMode(
227+
self.__device_handle, num, port_carr, mode_carr)
228+
if (r != 1):
229+
raise GStimboxError("Could not set modes on g-STIMbox.")
230+
231+
def setPortState(self, state):
232+
"""Set ON/OFF state for ports running in mode ``0`` (see
233+
setMode()).
234+
235+
state is a list with a length of 16. Valid values for a state
236+
is an integer of either ``0`` or ``1``.
237+
238+
eg. ``state = [0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]``
239+
240+
"""
241+
if type(state) != list:
242+
raise TypeError("Argument state must be a list.")
243+
if len(state) != 16:
244+
raise TypeError("Argument state must be of length 16.")
245+
state_carr = (c_int * 16)()
246+
for i in range(16):
247+
state_carr[i] = c_int(state[i])
248+
r = self.dll.gSTIMboxsetPortState(self.__device_handle, state_carr)
249+
if (r != 1):
250+
raise GStimboxError("Could not set port states on g-STIMbox.")
251+
252+
def setFrequency(self, port, freq):
253+
"""Set the frequencies for output ports.
254+
255+
port - list of port numbers to change. Valid port numbers
256+
range from 0 to 15. (eg. ``[0, 6, 7]``)
257+
258+
freq - list of frequencies which are to be assigned to the
259+
ports. Allowed values range from 1 to 50. The function rounds
260+
these frequencies to one digit after the comma. The length of
261+
``freq`` must equal the length of port list. (eg. ``[1, 2.7,
262+
5.8]``)
263+
264+
"""
265+
num = len(port)
266+
if type(port) != list:
267+
raise TypeError("Argument port must be a list.")
268+
if type(freq) != list:
269+
raise TypeError("Argument freq must be a list.")
270+
if num != len(freq):
271+
raise ValueError(
272+
"Arguments port and freq must be of same length.")
273+
port_carr = (c_int * num)()
274+
freq_carr = (c_double * num)()
275+
for i in range(num):
276+
port_carr[i] = c_int(port[i])
277+
freq_carr[i] = c_double(freq[i])
278+
r = self.dll.gSTIMboxsetFrequency(
279+
self.__device_handle, num, port_carr, freq_carr)
280+
if (r != 1):
281+
raise GStimboxError("Could not set frequencies on g-STIMbox.")
282+
283+
def close(self):
284+
"""Close device connection."""
285+
r = self.dll.gSTIMboxclose(self.__device_handle)
286+
if (r != 1):
287+
raise GStimboxError("Could not disconnect from g-STIMbox.")
288+
289+
def getHWVersion(self):
290+
"""Returns firmware version."""
291+
fun = self.dll.gSTIMboxgetHWVersion
292+
fun.restype = c_double
293+
return fun()
294+
295+
def getDriverVersion(self):
296+
"""Returns API library version."""
297+
fun = self.dll.gSTIMboxgetDriverVersion
298+
fun.restype = c_double
299+
return fun()
300+
301+
302+
class GStimboxError(Exception):
303+
"""g-STIMbox device communication error."""
304+
pass

0 commit comments

Comments
 (0)