digital-trigger 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- digital_trigger-0.1.3/LICENSE +21 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/PKG-INFO +59 -32
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/README.md +57 -32
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/pyproject.toml +1 -1
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger/trigger.py +25 -4
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/PKG-INFO +59 -32
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/SOURCES.txt +1 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/setup.cfg +0 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger/__init__.py +0 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/dependency_links.txt +0 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/requires.txt +0 -0
- {digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Max Lovell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digital-trigger
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Simple class for simplified pySerial interface for use in TTL event marking using e.g. PsychoPy.
|
|
5
5
|
Author-email: Max Lovell <max_lovell@hotmail.co.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Classifier: Topic :: Scientific/Engineering
|
|
20
20
|
Requires-Python: >=3.8
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
22
23
|
Requires-Dist: pyserial>=3.0
|
|
24
|
+
Dynamic: license-file
|
|
23
25
|
|
|
24
26
|
# digital-trigger
|
|
25
27
|
|
|
@@ -36,14 +38,6 @@ Requires Python 3.8+ and [`pyserial`](https://pypi.org/project/pyserial/) (insta
|
|
|
36
38
|
In PsychoPy you can install packages in the Builder GUI by going to:
|
|
37
39
|
Tools > Plugins and packages manager > Packages > Open PIP terminal, and run `pip install digital-trigger`
|
|
38
40
|
|
|
39
|
-
To find COM port number:
|
|
40
|
-
- run the command `python -m serial.tools.list_ports -v`
|
|
41
|
-
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
42
|
-
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
43
|
-
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
44
|
-
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
45
|
-
|
|
46
|
-
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
47
41
|
|
|
48
42
|
## Usage
|
|
49
43
|
|
|
@@ -60,34 +54,21 @@ from digital_trigger import Trigger
|
|
|
60
54
|
port = Trigger('COM4', names=['cond_1', 'cond_2', 'stim_1', 'stim_2'])
|
|
61
55
|
```
|
|
62
56
|
|
|
63
|
-
Note you can only do this once per experiment.
|
|
64
|
-
|
|
65
|
-
Probably best to have a single code block jsut for this in your first routine even.
|
|
66
|
-
|
|
67
|
-
#### Begin Routine
|
|
68
|
-
```
|
|
69
|
-
trigger_opened = False
|
|
70
|
-
trigger_closed = False
|
|
71
|
-
```
|
|
57
|
+
Note you can only do this once per experiment or you will get an 'access/permission denied' error.
|
|
58
|
+
Watch out if you insert the same routine twice as a copy.
|
|
72
59
|
|
|
73
60
|
#### Each Frame
|
|
74
61
|
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if image.status == STARTED and not trigger_opened:
|
|
78
|
-
win.callOnFlip(port.open, 'stim_1')
|
|
79
|
-
trigger_opened = True
|
|
62
|
+
if image.status == STARTED and port.is_closed(condition):
|
|
63
|
+
win.callOnFlip(port.open, condition)
|
|
80
64
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
win.callOnFlip(port.close, 'stim_1')
|
|
84
|
-
trigger_closed = True
|
|
65
|
+
if image.status == FINISHED and port.is_open(condition):
|
|
66
|
+
win.callOnFlip(port.close, condition)
|
|
85
67
|
```
|
|
86
68
|
|
|
87
|
-
|
|
69
|
+
OR, more simply:
|
|
88
70
|
```
|
|
89
|
-
|
|
90
|
-
port.close('stim_1')
|
|
71
|
+
port.sync_to_component(condition, image, win)
|
|
91
72
|
```
|
|
92
73
|
|
|
93
74
|
#### End Experiment
|
|
@@ -119,7 +100,44 @@ with Trigger('COM4', names=['stim_1']) as port:
|
|
|
119
100
|
port.open('stim_1')
|
|
120
101
|
```
|
|
121
102
|
|
|
122
|
-
|
|
103
|
+
## Issues
|
|
104
|
+
|
|
105
|
+
### Finding COM port number
|
|
106
|
+
To find COM port number:
|
|
107
|
+
- run the command `python -m serial.tools.list_ports -v`
|
|
108
|
+
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
109
|
+
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
110
|
+
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
111
|
+
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
112
|
+
|
|
113
|
+
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
114
|
+
|
|
115
|
+
### Module not found on Mac
|
|
116
|
+
`ModuleNotFoundError: No module named 'digital_trigger'` error on Mac: PsychoPy 2025 issue with install path typo.
|
|
117
|
+
Confirm by running this inside a code component in psychopy:
|
|
118
|
+
```
|
|
119
|
+
import sys
|
|
120
|
+
print(sys.executable)
|
|
121
|
+
for p in sys.path:
|
|
122
|
+
print(" ", p)
|
|
123
|
+
```
|
|
124
|
+
see if package is installed to python3.1 instead of python3.10.
|
|
125
|
+
- also `show digital-trigger` in PsychoPy's pip terminal (after running `install digital-trigger`) should also state that the package is installed.
|
|
126
|
+
- try `find ~/.psychopy3 /Applications/PsychoPy.app -name "digital_trigger*" 2>/dev/null` in terminal
|
|
127
|
+
|
|
128
|
+
Either install directly using `/Applications/PsychoPy.app/Contents/MacOS/python -m pip install \
|
|
129
|
+
--target ~/.psychopy3/packages/lib/python/site-packages \
|
|
130
|
+
digital-trigger`
|
|
131
|
+
or move the directory by running this in a terminal:
|
|
132
|
+
```
|
|
133
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger \
|
|
134
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
135
|
+
|
|
136
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger-0.1.2.dist-info \
|
|
137
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Resources:
|
|
123
141
|
- https://www.blackboxtoolkit.com/support_usb_ttl_module.html
|
|
124
142
|
- https://www.blackboxtoolkit.com/docs/pdf/USBTTLv1r19.pdf
|
|
125
143
|
- https://psychopy.org/developers/pluginDevGuide.html#plugindevguide
|
|
@@ -139,9 +157,11 @@ re-run build:
|
|
|
139
157
|
rm -rf dist # clear old builds so nothing stale is uploaded
|
|
140
158
|
python3 -m build
|
|
141
159
|
ls dist # confirm the new version number is shown
|
|
142
|
-
twine upload --repository testpypi dist/*
|
|
143
160
|
```
|
|
144
161
|
|
|
162
|
+
Push to PyPi test with `twine upload --repository testpypi dist/*`
|
|
163
|
+
Push to PyPi with `twine upload dist/*`
|
|
164
|
+
|
|
145
165
|
#### test
|
|
146
166
|
|
|
147
167
|
```
|
|
@@ -172,5 +192,12 @@ print('ok', t.bitmask)
|
|
|
172
192
|
#### release
|
|
173
193
|
```
|
|
174
194
|
cd /path/to/project # back to the project folder
|
|
195
|
+
rm -rf dist
|
|
196
|
+
python -m build
|
|
175
197
|
twine upload dist/* # no --repository = real PyPI
|
|
176
198
|
```
|
|
199
|
+
OR github:
|
|
200
|
+
Releases > Draft a new release.
|
|
201
|
+
Choose a tag: type v0.1.3, click "Create new tag: v0.1.3 on publish".
|
|
202
|
+
Title: v0.1.3. Description: brief notes on what changed.
|
|
203
|
+
Click Publish release.
|
|
@@ -13,14 +13,6 @@ Requires Python 3.8+ and [`pyserial`](https://pypi.org/project/pyserial/) (insta
|
|
|
13
13
|
In PsychoPy you can install packages in the Builder GUI by going to:
|
|
14
14
|
Tools > Plugins and packages manager > Packages > Open PIP terminal, and run `pip install digital-trigger`
|
|
15
15
|
|
|
16
|
-
To find COM port number:
|
|
17
|
-
- run the command `python -m serial.tools.list_ports -v`
|
|
18
|
-
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
19
|
-
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
20
|
-
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
21
|
-
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
22
|
-
|
|
23
|
-
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
24
16
|
|
|
25
17
|
## Usage
|
|
26
18
|
|
|
@@ -37,34 +29,21 @@ from digital_trigger import Trigger
|
|
|
37
29
|
port = Trigger('COM4', names=['cond_1', 'cond_2', 'stim_1', 'stim_2'])
|
|
38
30
|
```
|
|
39
31
|
|
|
40
|
-
Note you can only do this once per experiment.
|
|
41
|
-
|
|
42
|
-
Probably best to have a single code block jsut for this in your first routine even.
|
|
43
|
-
|
|
44
|
-
#### Begin Routine
|
|
45
|
-
```
|
|
46
|
-
trigger_opened = False
|
|
47
|
-
trigger_closed = False
|
|
48
|
-
```
|
|
32
|
+
Note you can only do this once per experiment or you will get an 'access/permission denied' error.
|
|
33
|
+
Watch out if you insert the same routine twice as a copy.
|
|
49
34
|
|
|
50
35
|
#### Each Frame
|
|
51
36
|
```
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if image.status == STARTED and not trigger_opened:
|
|
55
|
-
win.callOnFlip(port.open, 'stim_1')
|
|
56
|
-
trigger_opened = True
|
|
37
|
+
if image.status == STARTED and port.is_closed(condition):
|
|
38
|
+
win.callOnFlip(port.open, condition)
|
|
57
39
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
win.callOnFlip(port.close, 'stim_1')
|
|
61
|
-
trigger_closed = True
|
|
40
|
+
if image.status == FINISHED and port.is_open(condition):
|
|
41
|
+
win.callOnFlip(port.close, condition)
|
|
62
42
|
```
|
|
63
43
|
|
|
64
|
-
|
|
44
|
+
OR, more simply:
|
|
65
45
|
```
|
|
66
|
-
|
|
67
|
-
port.close('stim_1')
|
|
46
|
+
port.sync_to_component(condition, image, win)
|
|
68
47
|
```
|
|
69
48
|
|
|
70
49
|
#### End Experiment
|
|
@@ -96,7 +75,44 @@ with Trigger('COM4', names=['stim_1']) as port:
|
|
|
96
75
|
port.open('stim_1')
|
|
97
76
|
```
|
|
98
77
|
|
|
99
|
-
|
|
78
|
+
## Issues
|
|
79
|
+
|
|
80
|
+
### Finding COM port number
|
|
81
|
+
To find COM port number:
|
|
82
|
+
- run the command `python -m serial.tools.list_ports -v`
|
|
83
|
+
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
84
|
+
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
85
|
+
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
86
|
+
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
87
|
+
|
|
88
|
+
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
89
|
+
|
|
90
|
+
### Module not found on Mac
|
|
91
|
+
`ModuleNotFoundError: No module named 'digital_trigger'` error on Mac: PsychoPy 2025 issue with install path typo.
|
|
92
|
+
Confirm by running this inside a code component in psychopy:
|
|
93
|
+
```
|
|
94
|
+
import sys
|
|
95
|
+
print(sys.executable)
|
|
96
|
+
for p in sys.path:
|
|
97
|
+
print(" ", p)
|
|
98
|
+
```
|
|
99
|
+
see if package is installed to python3.1 instead of python3.10.
|
|
100
|
+
- also `show digital-trigger` in PsychoPy's pip terminal (after running `install digital-trigger`) should also state that the package is installed.
|
|
101
|
+
- try `find ~/.psychopy3 /Applications/PsychoPy.app -name "digital_trigger*" 2>/dev/null` in terminal
|
|
102
|
+
|
|
103
|
+
Either install directly using `/Applications/PsychoPy.app/Contents/MacOS/python -m pip install \
|
|
104
|
+
--target ~/.psychopy3/packages/lib/python/site-packages \
|
|
105
|
+
digital-trigger`
|
|
106
|
+
or move the directory by running this in a terminal:
|
|
107
|
+
```
|
|
108
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger \
|
|
109
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
110
|
+
|
|
111
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger-0.1.2.dist-info \
|
|
112
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Resources:
|
|
100
116
|
- https://www.blackboxtoolkit.com/support_usb_ttl_module.html
|
|
101
117
|
- https://www.blackboxtoolkit.com/docs/pdf/USBTTLv1r19.pdf
|
|
102
118
|
- https://psychopy.org/developers/pluginDevGuide.html#plugindevguide
|
|
@@ -116,9 +132,11 @@ re-run build:
|
|
|
116
132
|
rm -rf dist # clear old builds so nothing stale is uploaded
|
|
117
133
|
python3 -m build
|
|
118
134
|
ls dist # confirm the new version number is shown
|
|
119
|
-
twine upload --repository testpypi dist/*
|
|
120
135
|
```
|
|
121
136
|
|
|
137
|
+
Push to PyPi test with `twine upload --repository testpypi dist/*`
|
|
138
|
+
Push to PyPi with `twine upload dist/*`
|
|
139
|
+
|
|
122
140
|
#### test
|
|
123
141
|
|
|
124
142
|
```
|
|
@@ -149,5 +167,12 @@ print('ok', t.bitmask)
|
|
|
149
167
|
#### release
|
|
150
168
|
```
|
|
151
169
|
cd /path/to/project # back to the project folder
|
|
170
|
+
rm -rf dist
|
|
171
|
+
python -m build
|
|
152
172
|
twine upload dist/* # no --repository = real PyPI
|
|
153
|
-
```
|
|
173
|
+
```
|
|
174
|
+
OR github:
|
|
175
|
+
Releases > Draft a new release.
|
|
176
|
+
Choose a tag: type v0.1.3, click "Create new tag: v0.1.3 on publish".
|
|
177
|
+
Title: v0.1.3. Description: brief notes on what changed.
|
|
178
|
+
Click Publish release.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "digital-trigger"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "Simple class for simplified pySerial interface for use in TTL event marking using e.g. PsychoPy."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.8"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import serial
|
|
2
|
+
import atexit
|
|
2
3
|
|
|
3
4
|
class Trigger:
|
|
4
5
|
def __init__(self, port='COM3', baudrate=115200, timeout=0, names=None, simulate=False):
|
|
@@ -9,6 +10,7 @@ class Trigger:
|
|
|
9
10
|
self.port = serial.Serial(port, baudrate, timeout=timeout)
|
|
10
11
|
self.reset()
|
|
11
12
|
self.write()
|
|
13
|
+
atexit.register(self.stop)
|
|
12
14
|
|
|
13
15
|
# -- line number handling ------------------------------------------
|
|
14
16
|
|
|
@@ -70,13 +72,23 @@ class Trigger:
|
|
|
70
72
|
# self.open_lines()
|
|
71
73
|
|
|
72
74
|
def stop(self):
|
|
75
|
+
if self.simulate or not hasattr(self, 'port') or not self.port.is_open:
|
|
76
|
+
return # already stopped, or never opened
|
|
73
77
|
print('Shutting down port')
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
print('Port is closed: ', not self.port.is_open)
|
|
78
|
+
self.reset()
|
|
79
|
+
self.port.close()
|
|
80
|
+
print('Port is closed: ', not self.port.is_open)
|
|
78
81
|
|
|
79
82
|
# -- OPTIONAL EXTRAS -------------------------------------------------
|
|
83
|
+
def sync_to_component(self, line, component, win):
|
|
84
|
+
# TODO: this only really works with a single line due to is_closed() etc, so consider a rewrite there
|
|
85
|
+
# see https://github.com/psychopy/psychopy/blob/dev/psychopy/constants.py
|
|
86
|
+
# consider lazy import of `from psychopy.constants import STARTED, FINISHED` instead of ints
|
|
87
|
+
if component.status == 1 and self.is_closed(line):
|
|
88
|
+
win.callOnFlip(self.open, line)
|
|
89
|
+
elif component.status == -1 and self.is_open(line):
|
|
90
|
+
win.callOnFlip(self.close, line)
|
|
91
|
+
|
|
80
92
|
# -- display -------------------------------------------------
|
|
81
93
|
|
|
82
94
|
def is_open(self, lines):
|
|
@@ -119,8 +131,17 @@ class Trigger:
|
|
|
119
131
|
line_names.append('unnamed')
|
|
120
132
|
return line_names
|
|
121
133
|
|
|
134
|
+
def hex(self):
|
|
135
|
+
return f"{self.bitmask:02X}"
|
|
136
|
+
|
|
137
|
+
def binary(self):
|
|
138
|
+
return f"{self.bitmask:08b}"
|
|
139
|
+
|
|
122
140
|
# -- context manager support ----------------------------------------
|
|
123
141
|
|
|
142
|
+
def __repr__(self):
|
|
143
|
+
return f"Trigger(bitmask={self.binary()}, open_lines={self.open_lines()})"
|
|
144
|
+
|
|
124
145
|
def __enter__(self):
|
|
125
146
|
return self
|
|
126
147
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: digital-trigger
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Simple class for simplified pySerial interface for use in TTL event marking using e.g. PsychoPy.
|
|
5
5
|
Author-email: Max Lovell <max_lovell@hotmail.co.uk>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -19,7 +19,9 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Classifier: Topic :: Scientific/Engineering
|
|
20
20
|
Requires-Python: >=3.8
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
22
23
|
Requires-Dist: pyserial>=3.0
|
|
24
|
+
Dynamic: license-file
|
|
23
25
|
|
|
24
26
|
# digital-trigger
|
|
25
27
|
|
|
@@ -36,14 +38,6 @@ Requires Python 3.8+ and [`pyserial`](https://pypi.org/project/pyserial/) (insta
|
|
|
36
38
|
In PsychoPy you can install packages in the Builder GUI by going to:
|
|
37
39
|
Tools > Plugins and packages manager > Packages > Open PIP terminal, and run `pip install digital-trigger`
|
|
38
40
|
|
|
39
|
-
To find COM port number:
|
|
40
|
-
- run the command `python -m serial.tools.list_ports -v`
|
|
41
|
-
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
42
|
-
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
43
|
-
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
44
|
-
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
45
|
-
|
|
46
|
-
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
47
41
|
|
|
48
42
|
## Usage
|
|
49
43
|
|
|
@@ -60,34 +54,21 @@ from digital_trigger import Trigger
|
|
|
60
54
|
port = Trigger('COM4', names=['cond_1', 'cond_2', 'stim_1', 'stim_2'])
|
|
61
55
|
```
|
|
62
56
|
|
|
63
|
-
Note you can only do this once per experiment.
|
|
64
|
-
|
|
65
|
-
Probably best to have a single code block jsut for this in your first routine even.
|
|
66
|
-
|
|
67
|
-
#### Begin Routine
|
|
68
|
-
```
|
|
69
|
-
trigger_opened = False
|
|
70
|
-
trigger_closed = False
|
|
71
|
-
```
|
|
57
|
+
Note you can only do this once per experiment or you will get an 'access/permission denied' error.
|
|
58
|
+
Watch out if you insert the same routine twice as a copy.
|
|
72
59
|
|
|
73
60
|
#### Each Frame
|
|
74
61
|
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if image.status == STARTED and not trigger_opened:
|
|
78
|
-
win.callOnFlip(port.open, 'stim_1')
|
|
79
|
-
trigger_opened = True
|
|
62
|
+
if image.status == STARTED and port.is_closed(condition):
|
|
63
|
+
win.callOnFlip(port.open, condition)
|
|
80
64
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
win.callOnFlip(port.close, 'stim_1')
|
|
84
|
-
trigger_closed = True
|
|
65
|
+
if image.status == FINISHED and port.is_open(condition):
|
|
66
|
+
win.callOnFlip(port.close, condition)
|
|
85
67
|
```
|
|
86
68
|
|
|
87
|
-
|
|
69
|
+
OR, more simply:
|
|
88
70
|
```
|
|
89
|
-
|
|
90
|
-
port.close('stim_1')
|
|
71
|
+
port.sync_to_component(condition, image, win)
|
|
91
72
|
```
|
|
92
73
|
|
|
93
74
|
#### End Experiment
|
|
@@ -119,7 +100,44 @@ with Trigger('COM4', names=['stim_1']) as port:
|
|
|
119
100
|
port.open('stim_1')
|
|
120
101
|
```
|
|
121
102
|
|
|
122
|
-
|
|
103
|
+
## Issues
|
|
104
|
+
|
|
105
|
+
### Finding COM port number
|
|
106
|
+
To find COM port number:
|
|
107
|
+
- run the command `python -m serial.tools.list_ports -v`
|
|
108
|
+
- On Windows, open Device Manager, expand "Ports (COM & LPT)", unplug and replug to see which is your device
|
|
109
|
+
- On Mac run `ls /dev/cu.*` in Terminal and look for something like /dev/cu.usbserial-XXXX or /dev/cu.usbmodemXXXX — use the cu.* name, not tty.*.
|
|
110
|
+
- On Linux, run ls `/dev/ttyUSB* /dev/ttyACM*` — USB-serial adapters are usually `ttyUSB0`
|
|
111
|
+
- Arduino-style boards `ttyACM0; dmesg | tail` right after plugging in shows the assigned name, and you may need to add yourself to the dialout group for permission.
|
|
112
|
+
|
|
113
|
+
Make sure your COM port is set up with a latency of 1ms (or lower) and Baudrate of 115200. This can be done under Device Manager > COM port > Advanced on Windows.
|
|
114
|
+
|
|
115
|
+
### Module not found on Mac
|
|
116
|
+
`ModuleNotFoundError: No module named 'digital_trigger'` error on Mac: PsychoPy 2025 issue with install path typo.
|
|
117
|
+
Confirm by running this inside a code component in psychopy:
|
|
118
|
+
```
|
|
119
|
+
import sys
|
|
120
|
+
print(sys.executable)
|
|
121
|
+
for p in sys.path:
|
|
122
|
+
print(" ", p)
|
|
123
|
+
```
|
|
124
|
+
see if package is installed to python3.1 instead of python3.10.
|
|
125
|
+
- also `show digital-trigger` in PsychoPy's pip terminal (after running `install digital-trigger`) should also state that the package is installed.
|
|
126
|
+
- try `find ~/.psychopy3 /Applications/PsychoPy.app -name "digital_trigger*" 2>/dev/null` in terminal
|
|
127
|
+
|
|
128
|
+
Either install directly using `/Applications/PsychoPy.app/Contents/MacOS/python -m pip install \
|
|
129
|
+
--target ~/.psychopy3/packages/lib/python/site-packages \
|
|
130
|
+
digital-trigger`
|
|
131
|
+
or move the directory by running this in a terminal:
|
|
132
|
+
```
|
|
133
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger \
|
|
134
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
135
|
+
|
|
136
|
+
mv /Applications/PsychoPy.app/Contents/Resources/lib/python3.10/site-packages/digital_trigger-0.1.2.dist-info \
|
|
137
|
+
~/.psychopy3/packages/lib/python/site-packages/
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Resources:
|
|
123
141
|
- https://www.blackboxtoolkit.com/support_usb_ttl_module.html
|
|
124
142
|
- https://www.blackboxtoolkit.com/docs/pdf/USBTTLv1r19.pdf
|
|
125
143
|
- https://psychopy.org/developers/pluginDevGuide.html#plugindevguide
|
|
@@ -139,9 +157,11 @@ re-run build:
|
|
|
139
157
|
rm -rf dist # clear old builds so nothing stale is uploaded
|
|
140
158
|
python3 -m build
|
|
141
159
|
ls dist # confirm the new version number is shown
|
|
142
|
-
twine upload --repository testpypi dist/*
|
|
143
160
|
```
|
|
144
161
|
|
|
162
|
+
Push to PyPi test with `twine upload --repository testpypi dist/*`
|
|
163
|
+
Push to PyPi with `twine upload dist/*`
|
|
164
|
+
|
|
145
165
|
#### test
|
|
146
166
|
|
|
147
167
|
```
|
|
@@ -172,5 +192,12 @@ print('ok', t.bitmask)
|
|
|
172
192
|
#### release
|
|
173
193
|
```
|
|
174
194
|
cd /path/to/project # back to the project folder
|
|
195
|
+
rm -rf dist
|
|
196
|
+
python -m build
|
|
175
197
|
twine upload dist/* # no --repository = real PyPI
|
|
176
198
|
```
|
|
199
|
+
OR github:
|
|
200
|
+
Releases > Draft a new release.
|
|
201
|
+
Choose a tag: type v0.1.3, click "Create new tag: v0.1.3 on publish".
|
|
202
|
+
Title: v0.1.3. Description: brief notes on what changed.
|
|
203
|
+
Click Publish release.
|
|
File without changes
|
|
File without changes
|
{digital_trigger-0.1.2 → digital_trigger-0.1.3}/src/digital_trigger.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|