diff options
Diffstat (limited to 'pcilib/views.c')
-rw-r--r-- | pcilib/views.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/pcilib/views.c b/pcilib/views.c new file mode 100644 index 0000000..38ce102 --- /dev/null +++ b/pcilib/views.c @@ -0,0 +1,331 @@ +#include <string.h> +#include "pci.h" +#include "pcilib.h" +#include <Python.h> +#include "views.h" +#include "error.h" +#include <strings.h> +#include <stdlib.h> + +/** + * + * replace a substring within a string by another + * @param[in] txt - the string to be modified + *@param[in] before - the substring in the string that will be replaced + *@param[in] after - the new value of before substring + *@return the modified txt string + */ +static char* +pcilib_view_formula_replace (const char *txt, const char *before, const char *after) +{ + const char *pos; + char *return_txt; + size_t pos_return_txt; + size_t len; + size_t allocated_size; + + /*get the first occurence of before. then we need one time to be out of the loop to correctly set the diverses varaibles (malloc instead of realloc notably)*/ + pos = strstr (txt, before); + + if (pos == NULL) + { + pcilib_warning("problem with a formula"); + } + + /* get the position of this occurence*/ + len = (size_t)pos - (size_t)txt; + allocated_size = len + strlen (after) + 1; + return_txt = malloc (allocated_size); + pos_return_txt = 0; + + /* we copy there the in a newly allocated string the start of txt before the "before" occurence, and then we copy after instead*/ + strncpy (return_txt + pos_return_txt, txt, len); + pos_return_txt += len; + txt = pos + strlen (before); + + len = strlen (after); + strncpy (return_txt + pos_return_txt, after, len); + pos_return_txt += len; + + /* we then iterate with the same principle to all occurences of before*/ + pos = strstr (txt, before); + while (pos != NULL) + { + len = (size_t)pos - (size_t)txt; + allocated_size += len + strlen (after); + return_txt = (char *)realloc (return_txt, allocated_size); + + strncpy (return_txt + pos_return_txt, txt, len); + pos_return_txt += len; + + txt = pos + strlen (before); + + len = strlen (after); + strncpy (return_txt + pos_return_txt, after, len); + pos_return_txt += len; + pos = strstr (txt, before); + } + /* put the rest of txt string at the end*/ + len = strlen (txt) + 1; + allocated_size += len; + return_txt = realloc (return_txt, allocated_size); + strncpy (return_txt + pos_return_txt, txt, len); + + return return_txt; +} + +/** + * function used to get the substring of a string s, from the starting and ending indexes + * @param[in] s string containing the substring we want to extract. + * @param[in] start the start index of the substring. + * @param[in] end the ending index of the substring. + * @return the extracted substring. + */ +static char* +pcilib_view_str_sub (const char *s, unsigned int start, unsigned int end) +{ + char *new_s = NULL; + + if (s != NULL && start < end) + { + new_s = malloc (sizeof (*new_s) * (end - start + 2)); + if (new_s != NULL) + { + int i; + + for (i = start; i <= end; i++) + { + new_s[i-start] = s[i]; + } + new_s[i-start] = '\0'; + } + else + { + pcilib_error("insufficient memory for string manipulation\n"); + return NULL; + } + } + return new_s; +} + +/** + * get the bank name associated with a register name + */ +static const char* +pcilib_view_get_bank_from_reg_name(pcilib_t* ctx,char* reg_name){ + int k; + for(k=0;ctx->registers[k].bits;k++){ + if(!(strcasecmp(reg_name,ctx->registers[k].name))){ + return ctx->banks[pcilib_find_register_bank_by_addr(ctx,ctx->registers[k].bank)].name; + } + } + return NULL; +} + +/** + * replace plain registers name in a formula by their value + */ +static char* +pcilib_view_compute_plain_registers(pcilib_t* ctx, char* formula){ + int j,k; + char *substr, *substr2; + char temp[66]; + pcilib_register_value_t value; + + /*we get recursively all registers of string , and if they are not equel to '@reg', then we get their value and put it in formula*/ + for(j=0;j<strlen((char*)formula);j++){ + if(formula[j]=='@'){ + k=j+1; + while((formula[k]!=' ' && formula[k]!=')' && formula[k]!='/' && formula[k]!='+' && formula[k]!='-' && formula[k]!='*' && formula[k]!='=') && (k<strlen((char*)formula))){ + k++; + } + substr2=pcilib_view_str_sub((char*)formula,j,k-1); /**< we get the name of the register+@*/ + substr=pcilib_view_str_sub(substr2,1,k-j/*length of substr2*/); /**< we get the name of the register*/ + + if((strcasecmp(substr,"reg"))){ + /* we get the bank name associated to the register, and read its value*/ + pcilib_read_register(ctx, pcilib_view_get_bank_from_reg_name(ctx, substr),substr,&value); + /* we put the value in formula*/ + sprintf(temp,"%i",value); + formula = pcilib_view_formula_replace(formula,substr2,temp); + } + + } + } + return formula; +} + +/** + * this function calls the python script and the function "evaluate" in it to evaluate the given formula + *@param[in] the formula to be evaluated + *@return the integer value of the evaluated formula (maybe go to float instead) + */ +static pcilib_register_value_t +pcilib_view_eval_formula(char* formula){ + setenv("PYTHONPATH",".",1); + PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult=NULL; + char* pythonfile; + + /* path to the python file, we may need a way to set it, maybe with a variable like PCILIB_PYTHON_PATH*/ + pythonfile="pythonscripts.py"; + + /* initialization of python interpreter*/ + Py_Initialize(); + + pName = PyUnicode_FromString(pythonfile); + pModule = PyImport_Import(pName); /* get the python file*/ + if(!pModule) { + pcilib_error("no python file found for python evaluation of formulas\n"); + PyErr_Print(); + return -1; + } + pDict = PyModule_GetDict(pModule); /*useless but needed*/ + + pFunc = PyDict_GetItemString(pDict, (char*)"evaluate"); /*getting of the function "evaluate" in the script*/ + /* if the function is ok, then call it*/ + if (PyCallable_Check(pFunc)) + { + /* execution of the function*/ + pValue=Py_BuildValue("(z)",formula); + PyErr_Print(); + presult=PyObject_CallObject(pFunc,pValue); + PyErr_Print(); + } else + { + PyErr_Print(); + } + /* remove memory*/ + Py_DECREF(pModule); + Py_DECREF(pName); + + /* close interpreter*/ + Py_Finalize(); + + return (pcilib_register_value_t)PyLong_AsUnsignedLong(presult); /*this function is due to python 3.3, as PyLong_AsInt was there in python 2.7 and is no more there, resulting in using cast futhermore*/ +} + + +static void +pcilib_view_apply_formula(pcilib_t* ctx, char* formula, pcilib_register_value_t reg_value, pcilib_register_value_t* out_value) +{ + /* when applying a formula, we need to: + 1) compute the values of all registers present in plain name in the formulas and replace their name with their value : for example, if we have the formula" ((1./4)*(@reg - 1200)) if @freq==0 else ((3./10)*(@reg - 1000)) " we need to get the value of the register "freq" + 2) compute the "@reg" component, corresponding to the raw value of the register + 3) pass the formula to python interpreter for evaluation + 4) return the final evaluation + + remark: it might be worth to use python regular expression interpreter (the following return all words following @ in formula : + >>> import re + >>> m = re.search('(?<=@)\w+', formula) + >>> m.group(0) + */ + + char reg_value_string[66]; /* to register reg_value as a string, need to check the length*/ + sprintf(reg_value_string,"%u",reg_value); + + /*computation of plain registers in the formula*/ + formula=pcilib_view_compute_plain_registers(ctx,formula); + /* computation of @reg with register value*/ + formula=pcilib_view_formula_replace(formula,"@reg",reg_value_string); + + /* evaluation of the formula*/ + *out_value= pcilib_view_eval_formula(formula); + +} + +int pcilib_read_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view/*, const char *unit*/, size_t value_size, void *value) +{ + int i,j,err=0; + pcilib_register_value_t temp_value; + char* formula; + + /* we get the index of the register to find the corresponding register context*/ + if((i=pcilib_find_register(ctx,bank,regname))==PCILIB_REGISTER_INVALID){ + pcilib_error("can't get the index of the register %s", regname); + return PCILIB_ERROR_INVALID_REQUEST; + } + + /* we get the value of the register, as we will apply the view on it*/ + if((err==pcilib_read_register_by_id(ctx,i,&temp_value))>0){ + pcilib_error("can't read the register %s value before applying views",regname); + } + /*in the case we don't ask for a view's name, we know it will be for views of type enum. Especially, it's faster to search directly on the values of those views instead of a given name. + we iterate so through the views of type enum to verify if the value we have corresponds to an enum command*/ + if(!(view)){ + for(j=0; ctx->register_ctx[i].enums[j].value;j++){ + if((temp_value >= ctx->register_ctx[i].enums[j].min) && (temp_value <= ctx->register_ctx[i].enums[j].max)){ + value_size=strlen(ctx->register_ctx[i].enums[j].name)*sizeof(char); + value=malloc(sizeof(value_size)); + if(!(value)){ + pcilib_error("can't allocate memory for the returning value of the view %s",view); + return PCILIB_ERROR_MEMORY; + } + /* in the case the value of register is between min and max, then we return the correponding enum command*/ + strncpy((char*)value,ctx->register_ctx[i].enums[j].name, strlen(ctx->register_ctx[i].enums[j].name)); + return 0; + } + } + pcilib_warning("the value of the register asked do not correspond to any enum views"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + /** in the other case we ask for a view of type formula. Indeed, wa can't directly ask for a formula, so we have to provide a name for those views*/ + j=0; + while((ctx->register_ctx[i].formulas[j].name)){ + if(!(strcasecmp(ctx->register_ctx[i].formulas[j].name,view))){ + /* when we have found the correct view of type formula, we apply the formula, that get the good value for return*/ + formula=malloc(sizeof(char)*strlen(ctx->register_ctx[i].formulas[j].read_formula)); + strncpy(formula,ctx->register_ctx[i].formulas[j].read_formula,strlen(ctx->register_ctx[i].formulas[j].read_formula)); + // pcilib_view_apply_formula(ctx, ctx->register_ctx[i].formulas[j].read_formula,temp_value,value); + pcilib_view_apply_formula(ctx, formula,temp_value,value); + value_size=sizeof(int); + return 0; + } + j++; + } + + pcilib_warning("the view asked and the register do not correspond"); + return PCILIB_ERROR_NOTAVAILABLE; +} + + +/** + * function to write to a register using a view + */ +int pcilib_write_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, size_t value_size,void* value/*, const char *unit*/){ + int i,j; + pcilib_register_value_t temp_value; + char *formula; + + /* we get the index of the register to find the corresponding register context*/ + if((i=pcilib_find_register(ctx,bank,regname))==PCILIB_REGISTER_INVALID){ + pcilib_error("can't get the index of the register %s", regname); + return PCILIB_ERROR_INVALID_REQUEST; + } + + /*here, in the case of views of type enum, view will correspond to the enum command. + we iterate so through the views of type enum to get the value corresponding to the enum command*/ + for(j=0; ctx->register_ctx[i].enums[j].value;j++){ + if(!(strcasecmp(ctx->register_ctx[i].enums[j].name,view))){ + pcilib_write_register(ctx,bank,regname,ctx->register_ctx[i].enums[j].value); + return 0; + } + } + + /** in the other case we ask for a view of type formula. Indeed, wa can't directly ask for a formula, so we have to provide a name for those views in view, and the value we want to write in value*/ + j=0; + while((ctx->register_ctx[i].formulas[j].name)){ + if(!(strcasecmp(ctx->register_ctx[i].formulas[j].name,view))){ + /* when we have found the correct view of type formula, we apply the formula, that get the good value for return*/ + formula=malloc(sizeof(char)*strlen(ctx->register_ctx[i].formulas[j].write_formula)); + strncpy(formula,ctx->register_ctx[i].formulas[j].write_formula,strlen(ctx->register_ctx[i].formulas[j].write_formula)); + // pcilib_view_apply_formula(ctx, ctx->register_ctx[i].formulas[j].write_formula,(pcilib_register_value_t*)value,temp_value); + pcilib_view_apply_formula(ctx,formula,*(pcilib_register_value_t*)value,&temp_value); + pcilib_write_register(ctx,bank,regname,temp_value); + return 0; + } + j++; + } + pcilib_warning("the view asked and the register do not correspond"); + return PCILIB_ERROR_NOTAVAILABLE; + } |