Skip to content

Commit 451d1ad

Browse files
committed
Merge remote-tracking branch 'cpp-lln-lab/master'
2 parents ed66c73 + dc6d344 commit 451d1ad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1335
-263
lines changed

.github/workflows/moxunit.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
branches: '*'
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v2
15+
with:
16+
submodules: true
17+
fetch-depth: 1
18+
- name: MOxUnit Action
19+
uses: joergbrech/[email protected]
20+
with:
21+
tests: tests
22+
src: src
23+
with_coverage: true
24+
cover_xml_file: coverage.xml
25+
- name: Code coverage
26+
uses: codecov/codecov-action@v1
27+
with:
28+
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
29+
file: coverage.xml # optional
30+
flags: unittests # optional
31+
name: codecov-umbrella # optional
32+
fail_ci_if_error: true # optional (default = false)

.travis.yml

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,27 +5,10 @@ dist: bionic
55
cache:
66
apt: true # only works with Pro version
77

8-
env:
9-
global:
10-
- OCTFLAGS="--no-gui --no-window-system --silent"
11-
128
before_install:
13-
- travis_retry sudo apt-get -y -qq update
14-
- travis_retry sudo apt-get -y install octave
15-
- travis_retry sudo apt-get -y install liboctave-dev
169
- cd .. && git clone https://github.com/florianschanda/miss_hit.git && export PATH=$PATH:`pwd`/miss_hit && cd CPP_PTB
1710

18-
install:
19-
- octave $OCTFLAGS --eval "addpath (pwd); savepath ();"
20-
21-
before_script:
22-
# Change current directory
23-
- cd tests
24-
2511
jobs:
2612
include:
27-
- stage: "Tests and linter"
28-
name: "Unit Tests" # names the first job
29-
script: octave $OCTFLAGS --eval "results = runTests; assert(all(~[results.Failed]))"
30-
- script: cd .. && mh_style `pwd`
13+
- script: mh_style `pwd`
3114
name: "miss_hit linter" # names the second job

README.md

Lines changed: 156 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -35,43 +35,96 @@ We use the [MISS_HIT linter](https://florianschanda.github.io/miss_hit/style_che
3535

3636
## How to install
3737

38-
### Use the matlab package manager
38+
### Download with git
39+
40+
``` bash
41+
cd fullpath_to_directory_where_to_install
42+
# use git to download the code
43+
git clone https://github.com/cpp-lln-lab/CPP_PTB.git
44+
# move into the folder you have just created
45+
cd CPP_PTB
46+
# add the src folder to the matlab path and save the path
47+
matlab -nojvm -nosplash -r "addpath(fullfile(pwd)); savepath ();"
48+
```
3949

40-
This repository can be added as a dependencies by listing it in a [mpm-requirements.txt file](.mpm-requirements.txt)
41-
as follows:
50+
Then get the latest commit:
51+
```bash
52+
# from the directory where you downloaded the code
53+
git pull origin master
54+
```
4255

43-
CPP_PTB -u https://github.com/cpp-lln-lab/CPP_PTB.git
56+
To work with a specific version, create a branch at a specific version tag number
57+
```bash
58+
# creating and checking out a branch that will be calle version1 at the version tag v0.0.1
59+
git checkout -b version1 v0.0.1
60+
```
4461

45-
You can then use the [matlab package manager](https://github.com/mobeets/mpm), to simply download the appropriate version of those dependencies and add them to your path by running a `getDependencies` function like the one below where you just need to replace `YOUR_EXPERIMENT_NAME` by the name of your experiment.
62+
### Add as a submodule
4663

47-
```matlab
48-
function getDependencies(action)
49-
% Will install on your computer the matlab dependencies specified in the mpm-requirements.txt
50-
% and add them to the matlab path. The path is never saved so you need to run getDependencies() when
51-
% you start matlab.
52-
%
53-
% getDependencies('update') will force the update and overwrite previous version of the dependencies.
54-
%
55-
% getDependencies() If you only already have the appropriate version but just want to add them to the matlab path.
56-
57-
experimentName = YOUR_EXPERIMENT_NAME;
58-
59-
if nargin<1
60-
action = '';
61-
end
62-
63-
switch action
64-
case 'update'
65-
% install dependencies
66-
mpm install -i mpm-requirements.txt -f -c YOUR_EXPERIMENT_NAME
67-
end
68-
69-
% adds them to the path
70-
mpm_folder = fileparts(which('mpm'));
71-
addpath(genpath(fullfile(mpm_folder, 'mpm-packages', 'mpm-collections', experimentName)));
72-
73-
end
64+
Add it as a submodule in the repo you are working on.
65+
66+
``` bash
67+
cd fullpath_to_directory_where_to_install
68+
# use git to download the code
69+
git submodule add https://github.com/cpp-lln-lab/CPP_PTB.git
70+
# move into the folder you have just created
71+
cd CPP_PTB
72+
# add the src folder to the matlab path and save the path
73+
matlab -nojvm -nosplash -r "addpath(fullfile(pwd))"
74+
```
75+
76+
To get the latest commit you then need to update the submodule with the information
77+
on its remote repository and then merge those locally.
78+
```bash
79+
git submodule update --remote --merge
80+
```
81+
82+
Remember that updates to submodules need to be committed as well.
83+
84+
#### Example for submodule usage
85+
86+
So say you want to clone a repo that has some nested submodules, then you would type this to get the content of all the submodules at once (here with my experiment repo):
87+
``` bash
88+
git clone --recurse-submodules https://github.com/user_name/yourExperiment.git
89+
```
90+
This would be the way to do it "by hand"
91+
92+
```bash
93+
# clone the repo
94+
git clone https://github.com/user_name/yourExperiment.git
95+
96+
# go into the directory
97+
cd yourExperiment
98+
99+
# initialize and get the content of the first level of submodules (CPP_PTB and CPP_BIDS)
100+
git submodule init
101+
git submodule update
102+
103+
# get the nested submodules JSONio and BIDS-matlab for CPP_BIDS
104+
git submodule foreach --recursive 'git submodule init'
105+
git submodule foreach --recursive 'git submodule update'
74106
```
107+
**TO DO**
108+
<!-- Submodules
109+
pros: in principle, downloading the experiment you have the whole package plus the benefit to stay updated and use version control of this dependency. Can probably handle a use case in which one uses different version on different projects (e.g. older and newer projects).
110+
cons: for pro users and not super clear how to use it at the moment. -->
111+
112+
### Direct download
113+
114+
Download the code. Unzip. And add to the matlab path.
115+
116+
Pick a specific version:
117+
118+
https://github.com/cpp-lln-lab/CPP_PTB/releases
119+
120+
Or take the latest commit (NOT RECOMMENDED):
121+
122+
https://github.com/cpp-lln-lab/CPP_PTB/archive/master.zip
123+
124+
**TO DO**
125+
<!-- Download a specific version and c/p it in a subfun folder
126+
pros: the easiest solution to share the code and 'installing' it on the stimulation computer (usually not the one used to develop the code).
127+
cons: extreme solution useful only at the very latest stage (i.e. one minute before acquiring your data); prone to be customized/modified (is it what we want?) -->
75128

76129
## Setting up keyboards
77130

@@ -98,9 +151,66 @@ press the keys necessary to start or abort the experiment.
98151

99152
Using empty vectors (ie `[]`) or a negative value for those means that you will let PTB find and use the default device.
100153

101-
## Structure and function details
154+
## Structure
155+
156+
```matlab
157+
158+
cfg.testingDevice = 'pc';
159+
160+
% cfg.color
161+
cfg.keyboard.keyboard = [];
162+
cfg.keyboard.responseBox = [];
163+
cfg.keyboard.responseKey = {};
164+
cfg.keyboard.escapeKey = 'ESCAPE';
165+
166+
% cfg.debug
167+
cfg.debug.do = true;
168+
cfg.debug.transpWin = true;
169+
cfg.debug.smallWin = true;
170+
171+
% cfg.text
172+
cfg.text.font
173+
cfg.text.size
174+
cfg.text.style
175+
176+
% cfg.color
177+
cfg.color.background
178+
179+
% cfg.screen
180+
cfg.screen.monitorWidth
181+
cfg.screen.monitorDistance
182+
cfg.screen.idx
183+
cfg.screen.win
184+
cfg.screen.winRect
185+
cfg.screen.winWidth
186+
cfg.screen.winHeight
187+
cfg.screen.center
188+
cfg.screen.FOV
189+
cfg.screen.ppd
190+
cfg.screen.ifi
191+
cfg.screen.monRefresh
192+
193+
% cfg.audio
194+
cfg.audio.do
195+
cfg.audio.pahandle
196+
cfg.audio.devIdx
197+
cfg.audio.playbackMode
198+
cfg.audio.requestedLatency
199+
cfg.audio.fs
200+
cfg.audio.channels
201+
cfg.audio.initVolume
202+
cfg.audio.pushSize
203+
cfg.audio.requestOffsetTime
204+
cfg.audio.reqsSampleOffset
205+
206+
% cfg.mri
207+
cfg.mri.repetitionTime
208+
cfg.mri.triggerNb
209+
cfg.mri.triggerKey
210+
```
211+
212+
## function details
102213

103-
<!-- ### setParameters -->
104214

105215
### initPTB
106216

@@ -129,12 +239,12 @@ and give access back to the keyboards.
129239

130240
### getResponse
131241

132-
It is wrapper function to use `KbQueue` which is definitely what you should used to collect responses.
242+
It is wrapper function to use `KbQueue` which is definitely what you should use to collect responses.
133243

134244
You can easily collect responses while running some other code at the same time.
135245

136-
It will only take responses from one device which can simply be the "main keyboard"
137-
(the default device that PTB will find) or another keyboard connected to the computer
246+
It will only take responses from one device which can simply be the "main keyboard"
247+
(the default device that PTB will find) or another keyboard connected to the computer
138248
or the response box that the participant is using.
139249

140250
You can use it in a way so that it only takes responses from certain keys and ignore others (like
@@ -146,7 +256,7 @@ In brief, there are several actions you can execute with this function.
146256

147257
- init: initialize the buffer for key presses on a given device (you can also specify the keys of interest that should be listened to).
148258
- start: start listening to the key presses (carefully insert into your script - where do you want to start buffering the responses).
149-
- check: till that point, it will check the buffer for all key presses.
259+
- check: till that point, it will check the buffer for all key presses.
150260
- It only reports presses on the keys of interest mentioned at initialization.
151261
- It **can** also check for presses on the escape key and abort if the escape key is part of the keys of interest.
152262
- flush: Empties the buffer of key presses in case you want to discard any previous key presses.
@@ -173,11 +283,18 @@ This will handle the Eye Tracker (EyeLink set up) and can be called to initializ
173283

174284
Use that to stop your script and only restart when the space bar is pressed.
175285

286+
287+
### waitForTrigger
288+
289+
Counts a certain number of triggers coming from the mri/scanner before returning.
290+
Requires number of triggers to wait for.
291+
292+
176293
## Annexes
177294

178295
### Experiment template [ WIP ]
179296

180-
### `devSandobox.m` stand-alone
297+
### devSandbox (stand-alone)
181298

182299
This script is a stand-alone function that can be useful as a sandbox to develop the PTB audio/visual stimulation of your experiment. No input/output required.
183300

checkAbort.m

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
function checkAbort(cfg, deviceNumber)
2+
% checkAbort(cfg, deviceNumber)
3+
%
24
% Check for experiment abortion from operator
35
% When no deviceNumber is set then it will check the default device
46
% When an abort key s detected this will set a global variable and throw a

checkPtbVersion.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
function checkPtbVersion()
22
% Checks that the right dependencies are installed.
33

4-
printCredits();
4+
printCreditsCppPtb();
55

66
PTB.major = 3;
77
PTB.minor = 0;

cleanUp.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
function cleanUp
1+
function cleanUp()
2+
% cleanUp()
3+
%
24
% A wrapper function to close all windows, ports, show mouse cursor, close keyboard queues
35
% and give access back to the keyboards.
46

collectAndSaveResponses.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function responseEvents = collectAndSaveResponses(cfg, logFile, experimentStart)
2+
3+
responseEvents = getResponse('check', cfg.keyboard.responseBox, cfg);
4+
5+
if isfield(responseEvents(1), 'onset') && ~isempty(responseEvents(1).onset)
6+
7+
for iResp = 1:size(responseEvents, 1)
8+
responseEvents(iResp).onset = ...
9+
responseEvents(iResp).onset - experimentStart;
10+
end
11+
12+
responseEvents.fileID = logFile.fileID;
13+
responseEvents.extraColumns = logFile.extraColumns;
14+
saveEventsFile('save', cfg, responseEvents);
15+
16+
end
17+
end

computeFOV.m

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function FOV = computeFOV(cfg)
2+
% FOV = computeFOV(cfg)
3+
%
4+
% computes the number of degrees of visual angle in the whole field of view
5+
%
6+
% δ = 2 arctan ( d / 2D )
7+
%
8+
% δ is the angular diameter, and d is the actual diameter of the object,
9+
% and D is the distance to the object.
10+
% The result obtained is in radians.
11+
%
12+
13+
FOV = ...
14+
180 / pi * ...
15+
2 * atan(cfg.screen.monitorWidth / (2 * cfg.screen.monitorDistance));
16+
17+
end

degToPix.m

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
function structure = degToPix(fieldName, structure, cfg)
2+
% structure = degToPix(fieldName, structure, cfg)
3+
%
24
% For a given field value in degrees of visual angle in the structure,
35
% this computes its value in pixel using the pixel per degree value of the cfg structure
46
% and returns a structure with an additional field with Pix suffix holding that new value.
57

68
deg = getfield(structure, fieldName); %#ok<GFLD>
79

810
structure = setfield(structure, [fieldName 'Pix'], ...
9-
floor(cfg.ppd * deg)) ; %#ok<SFLD>
11+
floor(deg * cfg.screen.ppd)) ; %#ok<SFLD>
1012

1113
end

demos/CPP_waitForTriggerDemo.m

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
cd ..;
22

3-
cfg.device = 'Scanner';
3+
cfg.testingDevice = 'mri';
44

5-
cfg.numTriggers = 4;
5+
cfg.mri.triggerNb = 4;
66

7-
cfg.triggerKey = 'space';
7+
cfg.mri.triggerKey = 'space';
88

99
KbName('UnifyKeyNames');
1010

0 commit comments

Comments
 (0)