Commit 50f62ff2 authored by Nicolas Docquier's avatar Nicolas Docquier
Browse files

Merge branch 'RWC_RWT_modifications' into 'dev'

Handeling C-Structure from Python

See merge request robotran/mbsysc!407
parents 19bfba3d ca18b0b4
......@@ -253,6 +253,9 @@ void mbs_print_user_models(MbsInfos* mbs_infos, char *fileoutC, char *fileoutH)
fprintf(fidC, " um->%s.%s = get_ivec_1(%d);\n", mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->n_value);
fprintf(fidC, " um->%s.%s[0] = %d;\n", mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->n_value);
break;
case 6:
fprintf(fidC, " um->%s.%s = NULL;\n", mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name);
break;
case 7: //integer
fprintf(fidC, " um->%s.%s = 0;\n", mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name);
}
......@@ -403,9 +406,11 @@ void mbs_print_user_models(MbsInfos* mbs_infos, char *fileoutC, char *fileoutH)
case 3:
case 4:
case 5:
case 6:
fprintf(fidC, " mbs_infos->user_models->user_model_list[%d]->parameter_list[%d]->val_ptr = um->%s.%s;\n", i, j, mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name);
break;
case 6:
fprintf(fidC, " mbs_infos->user_models->user_model_list[%d]->parameter_list[%d]->val_ptr = &um->%s.%s;\n", i, j, mbs_infos->user_models->user_model_list[i]->name, mbs_infos->user_models->user_model_list[i]->parameter_list[j]->name);
break;
}
}
fprintf(fidC, " \n");
......
......@@ -275,6 +275,7 @@ typedef struct MbsInfoParameter
//!< but pointing the memory in MbsData.user_model
//!< - 1D LUT: points the MbsLut1D structure in MbsData.user_model.
//!< - 2D LUT: points the MbsLut2D structure in MbsData.user_model.
//!< - structure: points to NULL as loading user model does not allocate them.
//!< - structure: points the structure in MbsData.user_model.
/* probably members only used in the past for optimization purpose */
......
......@@ -180,6 +180,6 @@ MbsInfoParameter_c._fields_ = [
("type", ctypes.c_int),
("n_value", ctypes.c_int),
("value_list", ctypes.POINTER(ctypes.c_double)),
("val_ptr", ctypes.POINTER(ctypes.c_double))
("val_ptr", ctypes.c_void_p)
#remaining fields not implemented
]
\ No newline at end of file
]
......@@ -294,12 +294,13 @@ class MbsData(object):
Examples
--------
Here are some basic usages.
>>> mbs_data = MBsysPy.MbsData("../dataR/ExampleProject.mbs")
>>> mbs_data.user_model["MyUserModel"]["MyScalar"] = 3.0
>>> mbs_msg(mbs_data.user_model["MyUserModel"]["MyScalar"])
3.0
>>> #get a copy of the scalar
>>> # Get a copy of the scalar
>>> a = mbs_data.user_model["MyUserModel"]["MyScalar"]
>>> a = 2
>>> mbs_msg(mbs_data.user_model["MyUserModel"]["MyScalar"])
......@@ -317,6 +318,32 @@ class MbsData(object):
>>> print(mbs_data.user_model["MyUserModel"]["MyVector"])
array([1.0, 10.0])
The usage of C-structures is a bit more complex. This is mainly used in the
case of using a external C-library doing computation on the structure.
Such structures must be allocated by the user, either in the c function
user_load_post() (requires 'prj_functions_c="SU"') or in python script.
it is assumed that the user model ['um']['struct'] is dedicated to structure
named 'my_struc'.
>>> import ctypes
>>> class MyStruct(ctypes.Structure):
... _fields_ = [("x", ctypes.c_int),
... ("y", ctypes.c_int)]
...
>>> my_struct_ptr = ctypes.pointer(MyStruct(10, 20))
>>> mbs_data.user_model['um']['struct'] = my_struct_ptr
... # If using C library for user function, the structure is ready to use.
... # To retrieve the structure object (and not the pointer to it) and contents
... # for further modifications see next lines.
>>> my_struct = MyStruct.from_address(mbs_data.user_model['um']['struct'])
>>> my_struct.x = 127
In this example, a pointer to MyStruct instance was created.
However the python object of the structure is retrieved, allowing easy fields
access.
"""
def __init__(self, name, user_path=None, symbolic_path=None,
......@@ -2204,8 +2231,8 @@ class MbsData(object):
# And parameter name
name2 = bytes_to_str(parameter_list.name)
# Retrieve pointer to values, as ctypes.POINTER(ctypes.c_double)
val_ptr = parameter_list.val_ptr # Currently set in memory
# Retrieve pointer to values, as ctypes.c_void_p
val_adr = parameter_list.val_ptr # Currently set in memory
# Retrieve number of value in the parameter
size = parameter_list.n_value
......@@ -2215,31 +2242,66 @@ class MbsData(object):
um_type = parameter_list.type # shortcut for comparison
if um_type == 1: # scalar
self.user_model[name][name2] = np.ctypeslib.as_array(val_ptr, (1, 1))
# Convert the adress to an pointer to a double.
ptr_to_val = ctypes.pointer(ctypes.c_double.from_address(val_adr))
# Wrap the pointer to a double into a numpy array of 1 element.
self.user_model[name][name2] = np.ctypeslib.as_array(ptr_to_val, (1, 1))
elif um_type == 2: # vector, using index starting at 1.
self.user_model[name][name2] = np.ctypeslib.as_array(val_ptr, (1, size + 1))
# Convert the adress to an pointer to doubles.
ptr_to_val = ctypes.pointer(ctypes.c_double.from_address(val_adr))
# Wrap the pointer to doubles into a numpy array of correct size.
self.user_model[name][name2] = np.ctypeslib.as_array(ptr_to_val, (1, size + 1))
elif um_type == 5: # user state
if UmPy:
# The pointer is set to the initial value of the user states.
# The initial value has been loaded in MbsData.ux.
# The indices of the user state must be created.
# The indices are shared between all user states.
state = np.array([np.arange(next_user_state - 1, size + next_user_state)])
state[0][0] = size
next_user_state += size
else:
# The indices of the user state have been created by the c UserModel.
state = np.ctypeslib.as_array(ctypes.cast(val_ptr, ctypes.POINTER(ctypes.c_int)), (1, size + 1))
# Convert the adress to an pointer to a integer as the
# indices have been created by the c UserModel as int*.
ptr_to_val = ctypes.pointer(ctypes.c_int.from_address(val_adr))
# Wrap the pointer to ints into a numpy array of correct size.
state = np.ctypeslib.as_array(ptr_to_val, (1, size + 1))
# Preventing the user to modify the user state ids.
state.flags["WRITEABLE"] = False
self.user_model[name][name2] = state
elif um_type == 6:
if UmPy:
# As UserModel structure does not exists, there is no memory
# allocated to store the pointer to the pointer of the c-structure.
# An empty pointer is created.
ptr_to_val = ctypes.pointer(ctypes.c_void_p(None))
self.user_model[name][name2] = ptr_to_val
else:
# This is the pointer to the memory containing the pointer to
# the C-structure.
# Currently, the strutures are not yet allocated, the pointer
# is set to NULL ('None' for python) by the C-loading
# As the structure type is not know, a generic void* is used.
ptr_to_val = ctypes.pointer(ctypes.c_void_p.from_address(val_adr))
self.user_model[name][name2] = ptr_to_val
elif um_type == 7:
if UmPy:
# The values loaded from files are stored as double. The conversion
# to integer will be done for the user when asking for the parameter.
self.user_model[name][name2] = np.ctypeslib.as_array(val_ptr, (1, 1))
# Convert the adress to an pointer to doubles.
ptr_to_val = ctypes.pointer(ctypes.c_double.from_address(val_adr))
# Wrap the pointer into a numpy array of 1 element.
self.user_model[name][name2] = np.ctypeslib.as_array(ptr_to_val, (1, 1))
else:
# At UserModel creation the val_ptr is redirected toward an int.
# Casting the pointer to a pointer to int is required
self.user_model[name][name2] = np.ctypeslib.as_array(ctypes.cast(val_ptr, ctypes.POINTER(ctypes.c_int)), (1, 1))
# At UserModel creation the val_ptr is redirected toward a pointer of ints*.
# Convert the adress to an pointer to a integer.
ptr_to_val = ctypes.pointer(ctypes.c_int.from_address(val_adr))
# Wrap the pointer into a numpy array of 1 element.
self.user_model[name][name2] = np.ctypeslib.as_array(ptr_to_val, (1, 1))
else:
# Other parameter types are either non accessible or unknown.
type_convertor = ['Invalid Value', 'a scalar', 'a vector',
......@@ -3170,8 +3232,10 @@ class _UserModelDict(dict):
"The id of a user state cannot be changed."
.format(self._parent_key, key))
elif self._type[key] == 6:
mbs_error("User model['{:}']['{:}'] is a C structure and cannot be set from Python."
.format(self._parent_key, key))
ptr_to_val = ctypes.cast(ctypes.pointer(value)[0], ctypes.c_void_p)
cur_ptr = dict.__getitem__(self, key)
cur_ptr[0] = ptr_to_val
print("User model['{:}']['{:}'] is a pointer to a C-structure located at : {:}".format(self._parent_key, key, dict.__getitem__(self, key)))
elif self._type[key] == 7:
tab = self.__getarray__(key)
......@@ -3206,7 +3270,9 @@ class _UserModelDict(dict):
Get the item in the array in the dict.
If the value is a scalar, a scalar is returned.
if the value is a vector, a vector is returned.
If the value is a vector, a vector is returned.
If the value us a pointer, a LP_c_void_p is returned (pointer to pointer
of type void).
"""
if self._type is None:
return dict.__getitem__(self, key)
......@@ -3214,6 +3280,8 @@ class _UserModelDict(dict):
if key in self.keys():
if self._type[key] == 1:
return float(dict.__getitem__(self, key)[0][0])
elif self._type[key] == 6:
return dict.__getitem__(self, key)[0]
elif self._type[key] == 7:
return int(dict.__getitem__(self, key)[0][0])
else:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment