/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool
309 by Suren A. Chilingaryan
Base functions for views
1
#include <Python.h>
2
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <string.h>
6
#include <strings.h>
7
8
#include "pci.h"
314 by Suren A. Chilingaryan
Support writting register views
9
#include "debug.h"
309 by Suren A. Chilingaryan
Base functions for views
10
#include "pcilib.h"
11
#include "py.h"
12
#include "error.h"
13
14
struct pcilib_py_s {
15
    PyObject *main_module;
16
    PyObject *global_dict;
17
};
18
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
19
struct pcilib_script_s {
20
    PyObject *py_script_module;	/**< PyModule object, contains script enviroment */
21
	PyObject *dict;
22
	char* script_name;
23
};
24
309 by Suren A. Chilingaryan
Base functions for views
25
int pcilib_init_py(pcilib_t *ctx) {
26
    ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
27
    if (!ctx->py) return PCILIB_ERROR_MEMORY;
28
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
29
    if(!Py_IsInitialized())
30
        Py_Initialize();
309 by Suren A. Chilingaryan
Base functions for views
31
32
    ctx->py->main_module = PyImport_AddModule("__parser__");
33
    if (!ctx->py->main_module)
34
        return PCILIB_ERROR_FAILED;
35
36
    ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
37
    if (!ctx->py->global_dict)
38
        return PCILIB_ERROR_FAILED;
39
40
    return 0;
41
}
42
43
void pcilib_free_py(pcilib_t *ctx) {
44
    if (ctx->py) {
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
45
        // Dict and module references are borrowed
309 by Suren A. Chilingaryan
Base functions for views
46
        free(ctx->py);
47
        ctx->py = NULL;
48
    }
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
49
    //Py_Finalize();
309 by Suren A. Chilingaryan
Base functions for views
50
}
51
52
/*
53
static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) {
54
    char *ptr;
55
    size_t cur = *size;
56
    
57
    if ((required + 1) > cur) {
58
        while (cur < required) cur *= 2;
59
        ptr = (char*)realloc(*str, cur);
60
        if (!ptr) return PCILIB_ERROR_MEMORY;
61
        *size = cur;
62
        *str = ptr;
63
    }
64
    ]
65
    return 0;
66
}
67
*/
68
69
static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
70
    int i;
71
    int err = 0;
312 by Suren A. Chilingaryan
Support transform views
72
    pcilib_value_t val = {0};
309 by Suren A. Chilingaryan
Base functions for views
73
    pcilib_register_value_t regval;
74
75
    char save;
76
    char *reg, *cur;
77
    size_t offset = 0;
78
79
    size_t size;
80
    char *src;
81
    char *dst;
82
83
    size_t max_repl = 2 + 2 * sizeof(pcilib_value_t);                               // the text representation of largest integer
84
85
    if (value) {
86
        err = pcilib_copy_value(ctx, &val, value);
87
        if (err) return NULL;
88
89
        err = pcilib_convert_value_type(ctx, &val, PCILIB_TYPE_STRING);
90
        if (err) return NULL;
91
92
        if (strlen(val.sval) > max_repl)
93
            max_repl = strlen(val.sval);
94
    }
95
96
    size = ((max_repl + 1) / 3 + 1) * strlen(codestr);                          // minimum register length is 3 symbols ($a + delimiter space), it is replaces with (max_repl+1) symbols
97
98
    src = strdup(codestr);
99
    dst = (char*)malloc(size);                                                  // allocating maximum required space
100
101
    if ((!src)||(!dst)) {
102
        if (src) free(src);
103
        if (dst) free(dst);
104
        pcilib_error("Failed to allocate memory for string formulas");
105
        return NULL;
106
    }
107
108
    cur = src;
109
    reg = strchr(src, '$');
110
    while (reg) {
111
        strcpy(dst + offset, cur);
112
        offset += reg - cur;
113
114
            // find the end of the register name
115
        reg++;
317 by Suren A. Chilingaryan
Support properties in transform formulas
116
        if (*reg == '{') {
117
            reg++;
118
            for (i = 0; (reg[i])&&(reg[i] != '}'); i++);
119
            if (!reg[i]) {
120
                pcilib_error("Python formula (%s) contains unterminated variable reference", codestr);
121
                err = PCILIB_ERROR_INVALID_DATA;
122
                break;
123
            }
124
        } else {
125
            for (i = 0; isalnum(reg[i])||(reg[i] == '_'); i++);
126
        }
309 by Suren A. Chilingaryan
Base functions for views
127
        save = reg[i];
128
        reg[i] = 0;
129
130
            // determine replacement value
131
        if (!strcasecmp(reg, "value")) {
132
            if (!value) {
133
                pcilib_error("Python formula (%s) relies on the value of register, but it is not provided", codestr);
134
                err = PCILIB_ERROR_INVALID_REQUEST;
135
                break;
136
            }
137
138
            strcpy(dst + offset, val.sval);
139
        } else {
317 by Suren A. Chilingaryan
Support properties in transform formulas
140
            if (*reg == '/') {
141
                pcilib_value_t val = {0};
142
                err = pcilib_get_property(ctx, reg, &val);
143
                if (err) break;
144
                err = pcilib_convert_value_type(ctx, &val, PCILIB_TYPE_STRING);
145
                if (err) break;
146
                sprintf(dst + offset, "%s", val.sval);
147
            } else {
148
                err = pcilib_read_register(ctx, NULL, reg, &regval);
149
                if (err) break;
330 by Suren A. Chilingaryan
Support for 64-bit registes
150
                sprintf(dst + offset, "0x%lx", regval);
317 by Suren A. Chilingaryan
Support properties in transform formulas
151
            }
309 by Suren A. Chilingaryan
Base functions for views
152
        }
153
154
        offset += strlen(dst + offset);
317 by Suren A. Chilingaryan
Support properties in transform formulas
155
        if (save == '}') i++;
156
        else reg[i] = save;
309 by Suren A. Chilingaryan
Base functions for views
157
158
            // Advance to the next register if any
159
        cur = reg + i;
160
        reg = strchr(cur, '$');
161
    }
162
163
    strcpy(dst + offset, cur);
164
165
    free(src);
166
167
    if (err) {
168
        free(dst);
169
        return NULL;
170
    }
171
172
    return dst;
173
}
174
175
int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
176
    PyGILState_STATE gstate;
177
    char *code;
178
    PyObject* obj;
179
180
    code = pcilib_py_parse_string(ctx, codestr, value);
181
    if (!code) {
182
        pcilib_error("Failed to parse registers in the code: %s", codestr);
183
        return PCILIB_ERROR_FAILED;
184
    }
185
186
    gstate = PyGILState_Ensure();
187
    obj = PyRun_String(code, Py_eval_input, ctx->py->global_dict, ctx->py->global_dict);
188
    PyGILState_Release(gstate);
189
190
    if (!obj) {
191
        pcilib_error("Failed to run the Python code: %s", code);
192
        return PCILIB_ERROR_FAILED;
193
    }
194
314 by Suren A. Chilingaryan
Support writting register views
195
    pcilib_debug(VIEWS, "Evaluating a Python string \'%s\' to %lf=\'%s\'", codestr, PyFloat_AsDouble(obj), code);
309 by Suren A. Chilingaryan
Base functions for views
196
    return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj));
197
}
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
198
346.1.7 by Vasilii Chernov
Change error logging method in Python wrap. Move functions, that converts values between PyObject and pcilib_value_t to py.c
199
void* pcilib_convert_val_to_pyobject(pcilib_t* ctx, pcilib_value_t *val)
200
{
201
	int err;
202
	
203
	switch(val->type)
204
	{
205
		case PCILIB_TYPE_INVALID:
206
                pcilib_error("Invalid register output type (PCILIB_TYPE_INVALID)");
207
			return NULL;
208
			
209
		case PCILIB_TYPE_STRING:
210
                pcilib_error("Invalid register output type (PCILIB_TYPE_STRING)");
211
			return NULL;
212
		
213
		case PCILIB_TYPE_LONG:
214
		{
215
			long ret;
216
			ret = pcilib_get_value_as_int(ctx, val, &err);
217
			
218
			if(err)
219
			{
220
                    pcilib_error("Failed: pcilib_get_value_as_int (%i)", err);
221
				return NULL;
222
			}
223
			return (PyObject*)PyInt_FromLong((long) ret);
224
		}
225
		
226
		case PCILIB_TYPE_DOUBLE:
227
		{
228
			double ret;
229
			ret = pcilib_get_value_as_float(ctx, val, &err);
230
			
231
			if(err)
232
			{
233
                    pcilib_error("Failed: pcilib_get_value_as_int (%i)", err);
234
				return NULL;
235
			}
236
			return (PyObject*)PyFloat_FromDouble((double) ret);
237
		}
238
		
239
		default:
240
                pcilib_error("Invalid register output type (unknown)");
241
			return NULL;
242
	}
243
}
244
245
int pcilib_convert_pyobject_to_val(pcilib_t* ctx, void* pyObjVal, pcilib_value_t *val)
246
{
247
	PyObject* pyVal = pyObjVal;
248
	int err;
249
	
250
    if(PyInt_Check(pyVal))
251
    {
252
        err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyVal));
253
    }
254
    else
255
        if(PyFloat_Check(pyVal))
256
            err = pcilib_set_value_from_float(ctx, val, PyFloat_AsDouble(pyVal));
257
        else
258
            if(PyString_Check(pyVal))
259
                err = pcilib_set_value_from_static_string(ctx, val, PyString_AsString(pyVal));
260
                else
261
                {
262
                    pcilib_error("Invalid input. Input type should be int, float or string.");
263
                    return PCILIB_ERROR_NOTSUPPORTED;
264
                }
265
    if(err)
266
        return err;
267
        
268
    return 0;
269
}
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
270
271
int pcilib_init_py_script(pcilib_t *ctx, char* module_name, pcilib_script_t **module, pcilib_access_mode_t *mode)
346.1.8 by Vasilii Chernov
Solve errors in serialing register_info function. Clear unused code
272
{	
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
273
	//Initialize python script, if it has not initialized already.
274
	if(!module_name)
275
	{
276
		pcilib_error("Invalid script name specified in XML property (NULL)");
277
		return PCILIB_ERROR_INVALID_DATA;
278
	}
279
	
280
	//create path string to scripts
281
	char* model_dir = getenv("PCILIB_MODEL_DIR");
282
	char* model_path = malloc(strlen(model_dir) + strlen(ctx->model) + 2);
283
	if (!model_path) return PCILIB_ERROR_MEMORY;
284
	sprintf(model_path, "%s/%s", model_dir, ctx->model);
285
	
286
	//set model path to python
287
	PySys_SetPath(model_path);
288
	free(model_path);
289
	model_path = NULL;
290
	
291
	//create path string to pcipywrap library
292
	char* app_dir = getenv("APP_PATH");
293
	char* pcipywrap_path;
294
	if(app_dir)
295
	{
346.1.9 by Vasilii Chernov
Change no_set_check parameter name. Move Python wrap to separate directory.
296
		pcipywrap_path = malloc(strlen(app_dir) + strlen("/pywrap"));
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
297
		if (!pcipywrap_path) return PCILIB_ERROR_MEMORY;
346.1.9 by Vasilii Chernov
Change no_set_check parameter name. Move Python wrap to separate directory.
298
		sprintf(pcipywrap_path, "%s/%s", "/pywrap", ctx->model);
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
299
	}
300
	else
301
	{
346.1.9 by Vasilii Chernov
Change no_set_check parameter name. Move Python wrap to separate directory.
302
		pcipywrap_path = malloc(strlen("./pywrap"));
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
303
		if (!pcipywrap_path) return PCILIB_ERROR_MEMORY;
346.1.9 by Vasilii Chernov
Change no_set_check parameter name. Move Python wrap to separate directory.
304
		sprintf(pcipywrap_path, "%s", "./pywrap");
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
305
306
	}
307
	
308
	//set pcipywrap library path to python
309
	PyObject* path = PySys_GetObject("path");
310
	if(PyList_Append(path, PyString_FromString(pcipywrap_path)) == -1)
311
	{
312
		pcilib_error("Cant set pcipywrap library path to python.");
313
		return PCILIB_ERROR_FAILED;
314
	}
315
	free(pcipywrap_path);
316
	pcipywrap_path = NULL;
317
	
318
	
319
	//extract module name from script name
320
	char* py_module_name = strtok(module_name, ".");
321
	
322
	if(!py_module_name)
323
	{
324
		pcilib_error("Invalid script name specified in XML property (%s)."
325
					 " Seems like name doesnt contains extension", module_name);
326
		return PCILIB_ERROR_INVALID_DATA;
327
	}
328
	
329
	//import python script
330
	PyObject* py_script_module = PyImport_ImportModule(py_module_name);
331
	
332
	if(!py_script_module)
333
	{
334
		printf("Error in import python module: ");
335
		PyErr_Print();
336
		return PCILIB_ERROR_INVALID_DATA;
337
	}
338
339
340
	//Initializing pcipywrap module if script use it
341
	PyObject* dict = PyModule_GetDict(py_script_module);
342
	if(PyDict_Contains(dict, PyString_FromString("pcipywrap")))
343
	{
344
		PyObject* pcipywrap_module = PyDict_GetItemString(dict, "pcipywrap");
345
		if(!pcipywrap_module)
346
		{
347
			pcilib_error("Cant extract pcipywrap module from script dictionary");
348
			return PCILIB_ERROR_FAILED;
349
		}
350
	   
351
	   //setting pcilib_t instance                 
352
	   PyObject_CallMethodObjArgs(pcipywrap_module,
353
							   PyUnicode_FromString("setPcilib"),
354
							   PyByteArray_FromStringAndSize((const char*)&ctx, sizeof(pcilib_t*)),
355
							   NULL);
356
	}
357
	
358
	//Success. Create struct and initialize values
359
	module[0] = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
360
	module[0]->py_script_module = py_script_module;
361
	module[0]->script_name = module_name;
362
	module[0]->dict = dict;
363
	
364
	//Setting correct mode
365
	mode[0] = 0;
366
	if(PyDict_Contains(dict, PyString_FromString("read_from_register")))
367
		mode[0] |= PCILIB_ACCESS_R;	
368
	if(PyDict_Contains(dict, PyString_FromString("write_to_register")))
369
		mode[0] |= PCILIB_ACCESS_W;
370
	
371
	return 0;
372
}
373
374
int pcilib_free_py_script(pcilib_script_t *module)
375
{
376
	if(module)
377
	{
378
		if(module->script_name)
379
		{
380
			free(module->script_name);
381
			module->script_name = NULL;
382
		}
383
		
384
		if(module->py_script_module)
385
		{
386
			//PyObject_Free(module->py_script_module);
387
			module->py_script_module = NULL;
388
		}
389
	}
346.1.8 by Vasilii Chernov
Solve errors in serialing register_info function. Clear unused code
390
	
391
	return 0;
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
392
}
393
394
int pcilib_script_read(pcilib_t *ctx, pcilib_script_t *module, pcilib_value_t *val)
395
{
396
	
397
	int err;
398
	
399
	PyObject *ret = PyObject_CallMethod(module->py_script_module, "read_from_register", "()");
400
	if (!ret) 
401
	{
402
	   printf("Python script error: ");
403
	   PyErr_Print();
404
	   return PCILIB_ERROR_FAILED;
405
	}
406
	
407
	err = pcilib_convert_pyobject_to_val(ctx, ret, val);
408
	
409
	if(err)
410
	{
411
		pcilib_error("Failed to convert python script return value to internal type: %i", err);
412
		return err;
413
	}
414
    return 0;
415
}
416
417
int pcilib_script_write(pcilib_t *ctx, pcilib_script_t *module, pcilib_value_t *val)
346.1.8 by Vasilii Chernov
Solve errors in serialing register_info function. Clear unused code
418
{	
346.1.7 by Vasilii Chernov
Change error logging method in Python wrap. Move functions, that converts values between PyObject and pcilib_value_t to py.c
419
    PyObject *input = pcilib_convert_val_to_pyobject(ctx, val);
346.1.6 by Vasilii Chernov
Merge script and transform view. Add get register and properties info to python wrap.
420
	if(!input)
421
	{
422
	   printf("Failed to convert input value to Python object");
423
	   PyErr_Print();
424
	   return PCILIB_ERROR_FAILED;
425
	}
426
	
427
	PyObject *ret = PyObject_CallMethodObjArgs(module->py_script_module,
428
											   PyUnicode_FromString("write_to_register"),
429
											   input,
430
											   NULL);
431
	if (!ret) 
432
	{
433
	   printf("Python script error: ");
434
	   PyErr_Print();
435
	   return PCILIB_ERROR_FAILED;
436
	}
437
438
    return 0;
439
}