-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathleverThread_Py.cpp
More file actions
314 lines (282 loc) · 14.8 KB
/
leverThread_Py.cpp
File metadata and controls
314 lines (282 loc) · 14.8 KB
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#include <Python.h>
#include <stdlib.h>
#include <iostream>
#include "leverThread.h"
/* ****************** Function called automatically when PyCapsule object is deleted in Python *****************************************
Last Modified:
* 2018/03/12 by Jamie Boyd - initial version */
void py_Lever_del(PyObject * PyPtr){
delete static_cast<leverThread*> (PyCapsule_GetPointer (PyPtr, "pulsedThread"));
}
/* ****************** Makes a leverThread object and returns a PyCapsule reference *****************************************
Last Modified:
* 2019/06/10 by Jamie Boyd - added new paramaters for motor direction pin and motor force mapping reversal
* 2018/03/12 by Jamie Boyd - initial version */
static PyObject* py_LeverThread_New (PyObject *self, PyObject *args) {
PyObject * bufferObj;
int isCued;
unsigned int nCircularOrToGoal;
int isReversed;
int goalCuerPin;
float cuerFreq;
int startCuerPin;
float startCuerFreq;
float startCueTime;
float timeBetweenTrials;
int motorDirPin;
int motorIsReversed;
if (!PyArg_ParseTuple(args,"OiIiifiiifff", &bufferObj, &isCued,&nCircularOrToGoal, &isReversed, &goalCuerPin, &cuerFreq, &motorDirPin, &motorIsReversed, &startCuerPin, &startCuerFreq, &startCueTime, &timeBetweenTrials)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for lever position buffer, isCued, number for circular buffer or goal pos, isReversed, goal cuer pin, cuer frequency, motorDirPin and motorIsReversed.");
return NULL;
}
// check that buffer is valid and that it is writable 16 bit int buffer
if (PyObject_CheckBuffer (bufferObj) == 0){
PyErr_SetString (PyExc_RuntimeError, "Error getting bufferObj from Python array.");
return NULL;
}
Py_buffer buffer;
if (PyObject_GetBuffer (bufferObj, &buffer, PyBUF_FORMAT)==-1){
PyErr_SetString (PyExc_RuntimeError,"Error getting C array from bufferObj from Python array");
return NULL;
}
if (strcmp (buffer.format, "h") != 0){
PyErr_SetString (PyExc_RuntimeError, "Error for bufferObj: data type of Python array is not signed short");
return NULL;
}
// make a leverThread object
leverThread * leverThreadPtr = leverThread::leverThreadMaker (static_cast <int16_t *>(buffer.buf), (unsigned int) (buffer.len/buffer.itemsize), isCued,nCircularOrToGoal, isReversed, goalCuerPin,cuerFreq, motorDirPin, motorIsReversed, startCuerPin, startCuerFreq, startCueTime, timeBetweenTrials);
if (leverThreadPtr == nullptr){
PyErr_SetString (PyExc_RuntimeError, "leverThreadMaker was not able to make a leverThread object");
return NULL;
}else{
return PyCapsule_New (static_cast <void *>(leverThreadPtr), "pulsedThread", py_Lever_del);
}
}
/* *************************************** Sets value of the constant force that is stored in the lever thread ************************************
* Last Modified:
* 2019/06/10 by Jamie Boyd -changed force from int to float where force is mapped from 0 to 1*/
static PyObject* py_leverThread_setConstForce (PyObject *self, PyObject *args){
PyObject *PyPtr;
float newForce;
if (!PyArg_ParseTuple(args,"Of", &PyPtr, &newForce)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and constant force");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setConstForce (newForce);
Py_RETURN_NONE;
}
/* *************************************** returns value of the constant force that is stored in the lever thread ************************************
* Last Modified:
* 2019/06/10 by Jamie Boyd -changed force from int to float where force is mapped from 0 to 1*/
static PyObject* py_leverThread_getConstForce (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
return Py_BuildValue("f", leverThreadPtr->getConstForce());
}
/* ********************************** applies an arbitrary force on the lever, scaled from 0 to 1, in specified direction *******************************
* Last Modified:
* 2019/06/10 by Jamie Boyd -changed force from int to float where force is mapped from 0 to 1, and added direction */
static PyObject* py_leverThread_applyForce (PyObject *self, PyObject *args){
PyObject *PyPtr;
float newForce;
int direction;
if (!PyArg_ParseTuple(args,"Ofi", &PyPtr, &newForce, &direction)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object, force, and direction");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->applyForce (newForce, direction);
Py_RETURN_NONE;
}
/* ********************************** applies an arbitrary force on the lever, scaled from 0 to 1, in specified direction *******************************
* Last Modified:
* 2019/06/10 by Jamie Boyd -changed force from int to float where force is mapped from 0 to 1, and added direction */
static PyObject* py_leverThread_applyConstForce (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->applyConstForce();
Py_RETURN_NONE;
}
/* ********************************** moves lever to 0 position, if zeroMode is set, rezeroes the decoder *******************************
* returns value of decoder before a rezeroing
* Last Modified:
* 2019/06/10 by Jamie Boyd -changed force from int to float where force is mapped from 0 to 1, and added direction */
static PyObject* py_leverThread_zeroLever (PyObject *self, PyObject *args){
PyObject *PyPtr;
int zeroMode; // 0 for move lever back against post, 1 for move lever back against post and rezero the encoder
int isLocking;
if (!PyArg_ParseTuple(args,"Oii", &PyPtr, &zeroMode, &isLocking)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object, zero Mode and isLocking");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
return Py_BuildValue("i", leverThreadPtr-> zeroLever (zeroMode, isLocking));
}
/* ************************* sets force, from -constForce to maxForce - constForce, that will be added to const force during perturbation ***********
* Last Modified:
* 2019/06/10 by Jamie Boyd - made force into float, scaled from 0 to 1 */
static PyObject* py_leverThread_setPerturbForce (PyObject *self, PyObject *args){
PyObject *PyPtr;
float perturbForce;
if (!PyArg_ParseTuple(args,"Of", &PyPtr, &perturbForce)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and perturbForce");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setPerturbForce (perturbForce);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_setPerturbLength (PyObject *self, PyObject *args){
PyObject *PyPtr;
unsigned int perturbLength;
if (!PyArg_ParseTuple(args,"OI", &PyPtr, &perturbLength)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and perturb length");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setPerturbLength (perturbLength);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_getPerturbLength (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
return Py_BuildValue("h", leverThreadPtr->getPerturbLength());
}
static PyObject* py_leverThread_setPerturbOff (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setPerturbOff ();
Py_RETURN_NONE;
}
static PyObject* py_leverThread_setPerturbStartPos (PyObject *self, PyObject *args){
PyObject *PyPtr;
unsigned int perturbStartPos;
if (!PyArg_ParseTuple(args,"OI", &PyPtr, &perturbStartPos)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and perturb start position");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setPerturbStartPos (perturbStartPos);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_setTicksToGoal (PyObject *self, PyObject *args){
PyObject *PyPtr;
unsigned int ticksToGoal;
if (!PyArg_ParseTuple(args,"OI", &PyPtr, &ticksToGoal)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and ticks to goal position");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setTicksToGoal (ticksToGoal);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_startTrial (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->startTrial();
Py_RETURN_NONE;
}
static PyObject* py_leverThread_checkTrial (PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
int trialCode;
unsigned int goalEntryPos;
bool isDone=leverThreadPtr->checkTrial(trialCode, goalEntryPos);
PyObject *returnTuple;
if (isDone){
returnTuple = Py_BuildValue("(OiI)", Py_True, trialCode,goalEntryPos );
Py_INCREF (Py_True);
}else{
returnTuple = Py_BuildValue("(OiI)", Py_False, trialCode, goalEntryPos);
Py_INCREF (Py_False);
}
return returnTuple;
}
static PyObject* py_leverThread_doGoalCue (PyObject *self, PyObject *args){
PyObject *PyPtr;
int offOn;
if (!PyArg_ParseTuple(args,"Oi", &PyPtr, &offOn)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and offOn");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->doGoalCue (offOn);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_setHoldParams (PyObject *self, PyObject *args){
PyObject *PyPtr;
int16_t goalBottom;
int16_t goalTop;
unsigned int nHoldTicks;
if (!PyArg_ParseTuple(args,"OhhI", &PyPtr, &goalBottom, &goalTop, &nHoldTicks)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object, goalBottom, goalTop, and holdTicks");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->setHoldParams (goalBottom, goalTop, nHoldTicks);
Py_RETURN_NONE;
}
static PyObject* py_leverThread_getLeverPos(PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
return Py_BuildValue("h", leverThreadPtr->getLeverPos());
}
static PyObject* py_leverThread_abortUncuedTrial(PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
leverThreadPtr->abortUncuedTrial();
Py_RETURN_NONE;
}
static PyObject* py_leverThread_isCued(PyObject *self, PyObject *PyPtr) {
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
if (leverThreadPtr->isCued ()){
Py_RETURN_TRUE;
}else{
Py_RETURN_FALSE;
}
}
static PyObject* py_leverThread_setCued (PyObject *self, PyObject *args){
PyObject *PyPtr;
int isCued;
if (!PyArg_ParseTuple(args,"Oi", &PyPtr, &isCued)) {
PyErr_SetString (PyExc_RuntimeError, "Could not parse input for thread object and isCued");
return NULL;
}
leverThread * leverThreadPtr = static_cast<leverThread * > (PyCapsule_GetPointer(PyPtr, "pulsedThread"));
if (isCued ==0){
leverThreadPtr->setCue (false);
}else{
leverThreadPtr->setCue (true);
}
Py_RETURN_NONE;
}
/* Module method table */
static PyMethodDef leverThreadMethods[] = {
{"newLever", py_LeverThread_New, METH_VARARGS, "(lever position buffer, circular buffer num, isReversed, goal cuer pin, cuer frequency, motorPin, motorIsReversed) Creates a new instance of leverThread"},
{"setConstForce", py_leverThread_setConstForce, METH_VARARGS, "(PyPtr, newForce) Sets constant force to be used for leverThread"},
{"getConstForce", py_leverThread_getConstForce, METH_O, "(PyPtr) Returns constant force used for leverThread"},
{"applyForce", py_leverThread_applyForce, METH_VARARGS, "(PyPtr, force) Sets physical force on lever for leverThread"},
{"applyConstForce", py_leverThread_applyConstForce, METH_O, "(PyPtr) applies the constant force as set for leverThread"},
{"zeroLever", py_leverThread_zeroLever, METH_VARARGS, "(PyPtr, zeroMode, isLocking) Returns lever to front rail, optionally zeroing encoder"},
{"setPerturbLength", py_leverThread_setPerturbLength, METH_VARARGS, "(PyPtr, perturbLength) sets number of points used to generate perturb force ramp"},
{"setPerturbOff", py_leverThread_setPerturbOff, METH_O, "(PyPtr) turns off perturbation for upcoming lever trials"},
{"getPerturbLength", py_leverThread_getPerturbLength, METH_O, "(PyPtr) returns number of points used to generate perturb force ramp"},
{"setPerturbForce", py_leverThread_setPerturbForce, METH_VARARGS, "(PyPtr, perturbForce) Fills perturbation force array with sigmoid ramp"},
{"setPerturbStartPos", py_leverThread_setPerturbStartPos, METH_VARARGS, " (PyPtr, perturbPos) sets start position of perturb force"},
{"startTrial", py_leverThread_startTrial, METH_O, "(PyPtr) starts a trial as currently confgured"},
{"checkTrial", py_leverThread_checkTrial, METH_O, "(PyPtr) returns a three tuple of a boolean for trial completion and integers for trial result and goal position"},
{"doGoalCue", py_leverThread_doGoalCue, METH_VARARGS, "(PyPtr, OffOn) turns In-Goal Cue on or off"},
{"setHoldParams", py_leverThread_setHoldParams, METH_VARARGS, "(PyPtr, goalBottom, goalTop, nHoldTicks) sets lever hold params for next trial."},
{"getLeverPos",py_leverThread_getLeverPos, METH_O, "(PyPtr) returns the current lever position"},
{"abortUncuedTrial", py_leverThread_abortUncuedTrial, METH_O, "(PyPtr) aborts an uncued trial."},
{"isCued", py_leverThread_isCued, METH_O, "(PyPtr) returns truth that trials are cued, not un-cued."},
{"setCued", py_leverThread_setCued, METH_VARARGS, "(PyPtr, isCued) sets trials to be cued, or un-cued."},
{"setTicksToGoal", py_leverThread_setTicksToGoal, METH_VARARGS, "(PyPtr, ticksToGoal) sets ticks given for lever to get into goal position"},
{ NULL, NULL, 0, NULL}
};
/* Module structure */
static struct PyModuleDef leverThreadmodule = {
PyModuleDef_HEAD_INIT,
"ptLeverThread", /* name of module */
"Controls a leverThread for Auto Head Fix", /* Doc string (may be NULL) */
-1, /* Size of per-interpreter state or -1 */
leverThreadMethods /* Method table */
};
/* Module initialization function */
PyMODINIT_FUNC
PyInit_ptLeverThread (void) {
return PyModule_Create(&leverThreadmodule);
}