diff --git a/src/hal/Submakefile b/src/hal/Submakefile index 99cb0370bfb..1827d7e10c8 100644 --- a/src/hal/Submakefile +++ b/src/hal/Submakefile @@ -20,7 +20,7 @@ $(HALLIB).0: $(call TOOBJS, $(HALLIBSRCS)) @rm -f $@ $(Q)$(CC) $(LDFLAGS) -Wl,-soname,$(notdir $@) -shared -o $@ $^ $(HALLIB_LIBS) $(ULAPI_LDFLAGS) -HALMODULESRCS := hal/halmodule.cc +HALMODULESRCS := hal/halmodule.cc hal/utils/setps_util.c PYSRCS += $(HALMODULESRCS) HALMODULE := ../lib/python/_hal.so diff --git a/src/hal/hal.h b/src/hal/hal.h index 729481bf514..17372ccd3d1 100644 --- a/src/hal/hal.h +++ b/src/hal/hal.h @@ -590,6 +590,9 @@ int hal_pin_new_uint(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_uint def int hal_pin_new_real(int compid, hal_pdir_t dir, hal_real_t *ref, rtapi_real def, const char *fmt, ...) __HAL_PFMT(5,6); // Note: port has no initial default as it is an 'internal' reference //int hal_pin_new_port(int compid, hal_pin_dir_t dir, hal_port_t *ref, const char *fmt, ...) __HAL_PFMT(4,5); +// FIXME: This needs to change into hal_port_t argument when we break the API +// It is here so we may add halmodule without too much trouble until then. +int hal_pin_new_port(int compid, hal_pin_dir_t dir, hal_sint_t *ref, const char *fmt, ...) __HAL_PFMT(4,5); int hal_param_new_bool(int compid, hal_pdir_t dir, hal_bool_t *ref, rtapi_bool def, const char *fmt, ...) __HAL_PFMT(5,6); int hal_param_new_si32(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s32 def, const char *fmt, ...) __HAL_PFMT(5,6); diff --git a/src/hal/hal_lib.c b/src/hal/hal_lib.c index 826bc7d46a7..9dffdc59c53 100644 --- a/src/hal/hal_lib.c +++ b/src/hal/hal_lib.c @@ -1046,10 +1046,11 @@ int hal_pin_new_real(int compid, hal_pdir_t dir, hal_real_t *ref, rtapi_real def return 0; } -#if 0 -// Must wait until switch // Note: port has no initial default as it is an 'internal' reference -int hal_pin_new_port(int compid, hal_pdir_t dir, hal_port_t *ref, const char *fmt, ...) +//int hal_pin_new_port(int compid, hal_pdir_t dir, hal_port_t *ref, const char *fmt, ...) +// FIXME: This needs to change into hal_port_t argument when we break the API +// It is here so we may add halmodule without too much trouble until then. +int hal_pin_new_port(int compid, hal_pdir_t dir, hal_sint_t *ref, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -1057,7 +1058,6 @@ int hal_pin_new_port(int compid, hal_pdir_t dir, hal_port_t *ref, const char *fm va_end(ap); return ret; } -#endif /* this is a generic function that does the majority of the work. */ @@ -5173,7 +5173,7 @@ EXPORT_SYMBOL(hal_pin_new_ui32); EXPORT_SYMBOL(hal_pin_new_sint); EXPORT_SYMBOL(hal_pin_new_uint); EXPORT_SYMBOL(hal_pin_new_real); -//EXPORT_SYMBOL(hal_pin_new_port); +EXPORT_SYMBOL(hal_pin_new_port); EXPORT_SYMBOL(hal_pin_bit_new); EXPORT_SYMBOL(hal_pin_float_new); diff --git a/src/hal/halmodule.cc b/src/hal/halmodule.cc index 2c508a85857..4fe9f7165e0 100644 --- a/src/hal/halmodule.cc +++ b/src/hal/halmodule.cc @@ -25,8 +25,8 @@ #include #include -#include "hal.h" -#include "hal_priv.h" +#include +#include "utils/setps_util.h" #define EXCEPTION_IF_NOT_LIVE(retval) do { \ if(self->hal_id <= 0) { \ @@ -35,13 +35,6 @@ } \ } while(0) -#define TEST_HAL_SHMEM_BASE(fname) do { \ - if(!hal_shmem_base) { \ - PyErr_Format(PyExc_RuntimeError, "%s: Cannot call before creating component", fname); \ - return NULL; \ - } \ - } while(0) - // Use stdint interfaces when we have them #if PY_VERSION_HEX >= 0x030e00f0 // 3.14 #define PyLong_FromRtapiS32 PyLong_FromInt32 @@ -85,23 +78,6 @@ struct scoped_lc_numeric_c { locale_t newlc; }; -// -// Acquire the HAL mutex for operations. -// ***** -// NOTE: the HAL mutex is _not_ recursive safe! -// ***** -// The mutex is automatically released when the instance is destructed. -// -struct scoped_hal_mutex { - scoped_hal_mutex() { - halpr_mutex_acquire(); - } - ~scoped_hal_mutex() { - halpr_mutex_release(); - } -}; - - PyObject *to_python(bool b) { return PyBool_FromLong(b); } @@ -114,15 +90,15 @@ PyObject *to_python(rtapi_s32 i) { return PyLong_FromRtapiS32(i); } -PyObject *to_python(rtapi_u64 u) { +PyObject *to_python(rtapi_uint u) { return PyLong_FromRtapiU64(u); } -PyObject *to_python(rtapi_s64 i) { +PyObject *to_python(rtapi_sint i) { return PyLong_FromRtapiS64(i); } -PyObject *to_python(double d) { +PyObject *to_python(rtapi_real d) { return PyFloat_FromDouble(d); } @@ -193,7 +169,7 @@ bool from_python(PyObject *o, bool *b) return false; } -bool from_python(PyObject *o, double *d) { +bool from_python(PyObject *o, rtapi_real *d) { if(PyFloat_Check(o)) { *d = PyFloat_AsDouble(o); return true; @@ -258,7 +234,7 @@ bool from_python(PyObject *o, rtapi_s32 *i) { return false; } -bool from_python(PyObject *o, rtapi_u64 *u) { +bool from_python(PyObject *o, rtapi_uint *u) { PyObject *tmp = NULL; unsigned long long l; tmp = PyLong_Check(o) ? o : PyNumber_Long(o); @@ -276,7 +252,7 @@ bool from_python(PyObject *o, rtapi_u64 *u) { return false; } -bool from_python(PyObject *o, rtapi_s64 *i) { +bool from_python(PyObject *o, rtapi_sint *i) { PyObject *tmp = NULL; long long l; tmp = PyLong_Check(o) ? o : PyNumber_Long(o); @@ -294,41 +270,11 @@ bool from_python(PyObject *o, rtapi_s64 *i) { return false; } -union paramunion { - hal_bit_t b; - hal_u32_t u32; - hal_s32_t s32; - hal_u64_t u64; - hal_s64_t s64; - hal_float_t f; -}; - -union pinunion { - void *v; - hal_bit_t *b; - hal_u32_t *u32; - hal_s32_t *s32; - hal_u64_t *u64; - hal_s64_t *s64; - hal_float_t *f; - hal_port_t *p; -}; - -union halunion { - union pinunion pin; - union paramunion param; -}; - -union haldirunion { - hal_pin_dir_t pindir; - hal_param_dir_t paramdir; -}; - struct halitem { bool is_pin; hal_type_t type; - union haldirunion dir; - union halunion *u; + hal_pdir_t dir; + hal_refs_u *u; }; struct pyhalitem { @@ -342,7 +288,7 @@ static PyObject * pyhal_pin_new(halitem * pin, const char *name); typedef std::map itemmap; typedef struct halobject { - PyObject_HEAD + PyObject_HEAD int hal_id; char *name; char *prefix; @@ -415,117 +361,65 @@ static void pyhal_delete(PyObject *_self) { static int pyhal_write_common(halitem *pin, PyObject *value) { if(!pin) return -1; - if(pin->is_pin) { - switch(pin->type) { - case HAL_BIT: { - bool tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.b = tmp; - break; - } - case HAL_FLOAT: { - double tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.f = tmp; - break; - } - case HAL_U32: { - rtapi_u32 tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.u32 = tmp; - break; - } - case HAL_S32: { - rtapi_s32 tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.s32 = tmp; - break; - } - case HAL_U64: { - rtapi_u64 tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.u64 = tmp; - break; - } - case HAL_S64: { - rtapi_s64 tmp; - if(!from_python(value, &tmp)) return -1; - *pin->u->pin.s64 = tmp; - break; - } - default: - PyErr_Format(pyhal_error_type, "Invalid pin type %d", pin->type); - } - } else { - switch(pin->type) { - case HAL_BIT: { - bool tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.b = tmp; - break; - } - case HAL_FLOAT: { - double tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.f = tmp; - break; - } - case HAL_U32: { - rtapi_u32 tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.u32 = tmp; - break; - } - case HAL_S32: - rtapi_s32 tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.s32 = tmp; - break; - case HAL_U64: { - rtapi_u64 tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.u64 = tmp; - break; - } - case HAL_S64: { - rtapi_s64 tmp; - if(!from_python(value, &tmp)) return -1; - pin->u->param.s64 = tmp; - break; - } - default: - PyErr_Format(pyhal_error_type, "Invalid pin type %d", pin->type); - } + switch(pin->type) { + case HAL_BOOL: { + bool tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_bool(pin->u->b, tmp); + break; + } + case HAL_REAL: { + rtapi_real tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_real(pin->u->r, tmp); + break; + } + case HAL_U32: { + rtapi_u32 tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_ui32(pin->u->u, tmp); + break; + } + case HAL_S32: { + rtapi_s32 tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_si32(pin->u->s, tmp); + break; + } + case HAL_UINT: { + rtapi_uint tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_uint(pin->u->u, tmp); + break; + } + case HAL_SINT: { + rtapi_sint tmp; + if(!from_python(value, &tmp)) return -1; + hal_set_sint(pin->u->s, tmp); + break; + } + default: + PyErr_Format(pyhal_error_type, "Invalid pin type %d", pin->type); } return 0; } static PyObject *pyhal_read_common(halitem *item) { if(!item) return NULL; - if(item->is_pin) { - switch(item->type) { - case HAL_BIT: return to_python(*(item->u->pin.b)); - case HAL_U32: return to_python(*(item->u->pin.u32)); - case HAL_S32: return to_python(*(item->u->pin.s32)); - case HAL_U64: return to_python(*(item->u->pin.u64)); - case HAL_S64: return to_python(*(item->u->pin.s64)); - case HAL_FLOAT: return to_python(*(item->u->pin.f)); - case HAL_PORT: return to_python(hal_port_buffer_size(item->u->pin.p)); - default: - break; - } - } else { - switch(item->type) { - case HAL_BIT: return to_python(item->u->param.b); - case HAL_U32: return to_python(item->u->param.u32); - case HAL_S32: return to_python(item->u->param.s32); - case HAL_U64: return to_python(item->u->param.u64); - case HAL_S64: return to_python(item->u->param.s64); - case HAL_FLOAT: return to_python(item->u->param.f); - case HAL_PORT: return to_python((unsigned)0); // HAL_PORT cannot be a parameter - default: - break; - } + switch(item->type) { + case HAL_BOOL: return to_python(hal_get_bool(item->u->b)); + case HAL_U32: return to_python(hal_get_ui32(item->u->u)); + case HAL_S32: return to_python(hal_get_si32(item->u->s)); + case HAL_UINT: return to_python(hal_get_uint(item->u->u)); + case HAL_SINT: return to_python(hal_get_sint(item->u->s)); + case HAL_REAL: return to_python(hal_get_real(item->u->r)); + case HAL_PORT: + if(item->is_pin) + return to_python(hal_port_buffer_size(reinterpret_cast(item->u->u))); + else + return to_python((unsigned)0); // HAL_PORT cannot be a parameter + default: + break; } PyErr_Format(pyhal_error_type, "Invalid item type %d", item->type); return NULL; @@ -544,29 +438,50 @@ static halitem *find_item(halobject *self, const char *name) { return &(i->second); } +static bool is_valid_hal_type(hal_type_t t, bool allowport) +{ + switch(t) { + case HAL_BOOL: + case HAL_S32: + case HAL_U32: + case HAL_SINT: + case HAL_UINT: + case HAL_REAL: + return true; + case HAL_PORT: + return allowport; + default: + return false; + } +} + static PyObject * pyhal_create_param(halobject *self, const char *name, hal_type_t type, hal_param_dir_t dir) { - char param_name[HAL_NAME_LEN+1]; int res; halitem param; param.is_pin = 0; - /* FIXME consider type < HAL_TYPE_UNSPECIFIED || HAL_TYPE_MAX <= type */ - if(type < HAL_BIT || type > HAL_U64) { + if(!is_valid_hal_type(type, false)) { PyErr_Format(pyhal_error_type, "Invalid param type %d", type); return NULL; } param.type = type; - param.dir.paramdir = dir; - param.u = (halunion*)hal_malloc(sizeof(halunion)); + param.dir = dir; + param.u = (hal_refs_u *)hal_malloc(sizeof(*param.u)); if(!param.u) { PyErr_SetString(PyExc_MemoryError, "hal_malloc failed"); return NULL; } - res = snprintf(param_name, sizeof(param_name), "%s.%s", self->prefix, name); - if(res > HAL_NAME_LEN || res < 0) { return pyhal_error(-EINVAL); } - res = hal_param_new(param_name, type, dir, (void*)param.u, self->hal_id); + switch(type) { + case HAL_BOOL: res = hal_param_new_bool(self->hal_id, dir, ¶m.u->b, 0, "%s.%s", self->prefix, name); break; + case HAL_S32: res = hal_param_new_si32(self->hal_id, dir, ¶m.u->s, 0, "%s.%s", self->prefix, name); break; + case HAL_U32: res = hal_param_new_ui32(self->hal_id, dir, ¶m.u->u, 0, "%s.%s", self->prefix, name); break; + case HAL_SINT: res = hal_param_new_sint(self->hal_id, dir, ¶m.u->s, 0, "%s.%s", self->prefix, name); break; + case HAL_UINT: res = hal_param_new_uint(self->hal_id, dir, ¶m.u->u, 0, "%s.%s", self->prefix, name); break; + case HAL_REAL: res = hal_param_new_real(self->hal_id, dir, ¶m.u->r, 0.0, "%s.%s", self->prefix, name); break; + default: res = -EINVAL; break; + } if(res) return pyhal_error(res); (*self->items)[name] = param; @@ -581,14 +496,14 @@ static PyObject * pyhal_create_pin(halobject *self, const char *name, hal_type_t halitem pin; pin.is_pin = 1; - if(type < HAL_BIT || type > HAL_U64) { + if(!is_valid_hal_type(type, true)) { PyErr_Format(pyhal_error_type, "Invalid pin type %d", type); return NULL; } pin.type = type; - pin.dir.pindir = dir; - pin.u = (halunion*)hal_malloc(sizeof(halunion)); + pin.dir = dir; + pin.u = (hal_refs_u *)hal_malloc(sizeof(*pin.u)); if(!pin.u) { PyErr_SetString(PyExc_MemoryError, "hal_malloc failed"); return NULL; @@ -601,7 +516,17 @@ static PyObject * pyhal_create_pin(halobject *self, const char *name, hal_type_t self->prefix, name, HAL_NAME_LEN); return NULL; } - res = hal_pin_new(pin_name, type, dir, (void**)pin.u, self->hal_id); + switch(type) { + case HAL_BOOL: res = hal_pin_new_bool(self->hal_id, dir, &pin.u->b, 0, "%s.%s", self->prefix, name); break; + case HAL_S32: res = hal_pin_new_si32(self->hal_id, dir, &pin.u->s, 0, "%s.%s", self->prefix, name); break; + case HAL_U32: res = hal_pin_new_ui32(self->hal_id, dir, &pin.u->u, 0, "%s.%s", self->prefix, name); break; + case HAL_SINT: res = hal_pin_new_sint(self->hal_id, dir, &pin.u->s, 0, "%s.%s", self->prefix, name); break; + case HAL_UINT: res = hal_pin_new_uint(self->hal_id, dir, &pin.u->u, 0, "%s.%s", self->prefix, name); break; + case HAL_REAL: res = hal_pin_new_real(self->hal_id, dir, &pin.u->r, 0.0, "%s.%s", self->prefix, name); break; + // FIXME: This needs to change when we break the API. + case HAL_PORT: res = hal_pin_new_port(self->hal_id, dir, &pin.u->s, "%s.%s", self->prefix, name); break; + default: res = -EINVAL; break; + } if(res) return pyhal_error(res); (*self->items)[name] = pin; @@ -686,7 +611,20 @@ static PyObject *pyhal_get_pins(PyObject *_self, PyObject * /*o*/) { PyObject *d = PyDict_New(); for(itemmap::iterator i = self->items->begin(); i != self->items->end(); ++i) { halitem * pin = &(i->second); - PyDict_SetItem(d, PyUnicode_FromString(i->first.c_str()), pyhal_read_common(pin)); + PyObject *key = PyUnicode_FromString(i->first.c_str()); + if(!key) { + Py_DECREF(d); + return NULL; + } + PyObject *val = pyhal_read_common(pin); + if(!val) { + Py_DECREF(key); + Py_DECREF(d); + return NULL; + } + PyDict_SetItem(d, key, val); + Py_DECREF(val); + Py_DECREF(key); } return d; } @@ -882,28 +820,22 @@ PyTypeObject halobject_type = { static const char * pin_type2name(hal_type_t type) { switch (type) { - case HAL_BIT: return "BIT"; - case HAL_S32: return "S32"; - case HAL_U32: return "U32"; - case HAL_S64: return "S64"; - case HAL_U64: return "U64"; - case HAL_FLOAT: return "FLOAT"; - case HAL_PORT: return "PORT"; + case HAL_BOOL: return "BIT"; + case HAL_S32: return "S32"; + case HAL_U32: return "U32"; + case HAL_SINT: return "S64"; + case HAL_UINT: return "U64"; + case HAL_REAL: return "FLOAT"; + case HAL_PORT: return "PORT"; default: return "unknown"; } } -static const char * pin_dir2name(hal_pin_dir_t type) { +static const char * pin_dir2name(hal_pdir_t type) { switch (type) { case HAL_IN: return "IN"; case HAL_IO: return "IO"; case HAL_OUT: return "OUT"; - default: return "unknown"; - } -} - -static const char * param_dir2name(hal_param_dir_t type) { - switch (type) { case HAL_RO: return "RO"; case HAL_RW: return "RW"; default: return "unknown"; @@ -917,11 +849,9 @@ static PyObject *pyhalpin_repr(PyObject *_self) { const char * name = "(null)"; if (pyself->name) name = pyself->name; - if (!self->is_pin) - return PyUnicode_FromFormat("", name, - pin_type2name(self->type), param_dir2name(self->dir.paramdir)); - return PyUnicode_FromFormat("", name, - pin_type2name(self->type), pin_dir2name(self->dir.pindir)); + const char *pp = self->is_pin ? "pin" : "param"; + return PyUnicode_FromFormat("", pp, name, + pin_type2name(self->type), pin_dir2name(self->dir)); } static int pyhalpin_init(PyObject * /*_self*/, PyObject *, PyObject *) { @@ -957,10 +887,7 @@ static PyObject * pyhal_pin_get_type(PyObject * _self, PyObject *) { static PyObject * pyhal_pin_get_dir(PyObject * _self, PyObject *) { pyhalitem * self = reinterpret_cast(_self); - if (self->pin.is_pin) - return PyLong_FromLong(self->pin.dir.pindir); - else - return PyLong_FromLong(self->pin.dir.paramdir); + return PyLong_FromLong(self->pin.dir); } static PyObject * pyhal_pin_is_pin(PyObject * _self, PyObject *) { @@ -997,7 +924,7 @@ static PyObject *pyhal_port_write(PyObject *self, PyObject *o) pyhalitem *item = reinterpret_cast(self); if(!check_port(item, "write")) return NULL; - if(item->pin.dir.pindir != HAL_OUT) { + if(item->pin.dir != HAL_OUT) { PyErr_Format(PyExc_RuntimeError, "write: %s: Pin not output", item->name); return NULL; } @@ -1022,12 +949,12 @@ static PyObject *pyhal_port_write(PyObject *self, PyObject *o) Py_INCREF(Py_False); return Py_False; } - if(len > (Py_ssize_t)hal_port_writable(item->pin.u->pin.p)) { + if(len > (Py_ssize_t)hal_port_writable((hal_port_t *)item->pin.u->u)) { Py_INCREF(Py_False); return Py_False; } - return PyBool_FromLong(hal_port_write(item->pin.u->pin.p, cptr, (unsigned)len)); + return PyBool_FromLong(hal_port_write((hal_port_t *)item->pin.u->u, cptr, (unsigned)len)); } static PyObject *pyhal_port_read_peek(pyhalitem *item, PyObject *o, bool isread) @@ -1035,7 +962,7 @@ static PyObject *pyhal_port_read_peek(pyhalitem *item, PyObject *o, bool isread) const char *pfx = isread ? "read" : "peek"; if(!check_port(item, pfx)) return NULL; - if(item->pin.dir.pindir != HAL_IN) { + if(item->pin.dir != HAL_IN) { PyErr_Format(PyExc_RuntimeError, "%s: %s: Pin not input", pfx, item->name); return NULL; } @@ -1051,7 +978,7 @@ static PyObject *pyhal_port_read_peek(pyhalitem *item, PyObject *o, bool isread) Py_INCREF(Py_False); return Py_False; } - if(l > (unsigned long)hal_port_readable(item->pin.u->pin.p)) { + if(l > (unsigned long)hal_port_readable((hal_port_t *)item->pin.u->u)) { Py_INCREF(Py_False); return Py_False; } @@ -1063,9 +990,9 @@ static PyObject *pyhal_port_read_peek(pyhalitem *item, PyObject *o, bool isread) } bool b; if(isread) - b = hal_port_read(item->pin.u->pin.p, PyBytes_AsString(bts), (unsigned)l); + b = hal_port_read((hal_port_t *)item->pin.u->u, PyBytes_AsString(bts), (unsigned)l); else - b = hal_port_peek(item->pin.u->pin.p, PyBytes_AsString(bts), (unsigned)l); + b = hal_port_peek((hal_port_t *)item->pin.u->u, PyBytes_AsString(bts), (unsigned)l); if(b) { Py_DECREF(bts); Py_INCREF(Py_False); @@ -1103,7 +1030,7 @@ static PyObject *pyhal_port_peek_commit(PyObject *self, PyObject *o) Py_INCREF(Py_False); return Py_False; } - return PyBool_FromLong(hal_port_peek_commit(item->pin.u->pin.p, (unsigned)l)); + return PyBool_FromLong(hal_port_peek_commit((hal_port_t *)item->pin.u->u, (unsigned)l)); } static PyObject *pyhal_port_writable(PyObject *self, PyObject *) @@ -1111,11 +1038,11 @@ static PyObject *pyhal_port_writable(PyObject *self, PyObject *) pyhalitem *item = reinterpret_cast(self); if(!check_port(item, "writable")) return NULL; - if(item->pin.dir.pindir != HAL_OUT) { + if(item->pin.dir != HAL_OUT) { PyErr_Format(PyExc_RuntimeError, "writable: %s: Pin not output", item->name); return NULL; } - return PyLong_FromUnsignedLong(hal_port_writable(item->pin.u->pin.p)); + return PyLong_FromUnsignedLong(hal_port_writable((hal_port_t *)item->pin.u->u)); } static PyObject *pyhal_port_readable(PyObject *self, PyObject *) @@ -1123,11 +1050,11 @@ static PyObject *pyhal_port_readable(PyObject *self, PyObject *) pyhalitem *item = reinterpret_cast(self); if(!check_port(item, "readable")) return NULL; - if(item->pin.dir.pindir != HAL_IN) { + if(item->pin.dir != HAL_IN) { PyErr_Format(PyExc_RuntimeError, "readable: %s: Pin not input", item->name); return NULL; } - return PyLong_FromUnsignedLong(hal_port_readable(item->pin.u->pin.p)); + return PyLong_FromUnsignedLong(hal_port_readable((hal_port_t *)item->pin.u->u)); } static PyObject *pyhal_port_clear(PyObject *self, PyObject *) @@ -1135,7 +1062,7 @@ static PyObject *pyhal_port_clear(PyObject *self, PyObject *) pyhalitem *item = reinterpret_cast(self); if(!check_port(item, "clear")) return NULL; - hal_port_clear(item->pin.u->pin.p); + hal_port_clear((hal_port_t *)item->pin.u->u); Py_INCREF(Py_None); return Py_None; } @@ -1145,7 +1072,7 @@ static PyObject *pyhal_port_size(PyObject *self, PyObject *) pyhalitem *item = reinterpret_cast(self); if(!check_port(item, "size")) return NULL; - return PyLong_FromUnsignedLong(hal_port_buffer_size(item->pin.u->pin.p)); + return PyLong_FromUnsignedLong(hal_port_buffer_size((hal_port_t *)item->pin.u->u)); } static PyMethodDef halpin_methods[] = { @@ -1245,24 +1172,32 @@ static PyObject * pyhal_pin_new(halitem * pin, const char * name) { } PyObject *pin_has_writer(PyObject * /*self*/, PyObject *args) { - const char *name; - if(!PyArg_ParseTuple(args, "s", &name)) return NULL; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; // get mutex before accessing shared data - hal_pin_t *pin = halpr_find_pin_by_name(name); - if(!pin) { - PyErr_Format(PyExc_NameError, "Pin `%s' does not exist", name); + hal_query_t q = {}; + if(!PyArg_ParseTuple(args, "s", &q.name)) return NULL; + + q.qtype = HAL_QTYPE_PIN; // Only query a pin + int rv = hal_get_p(&q, NULL, NULL); + if(0 == rv) { + // Success reading. See if it has a driver. + if(!q.pp.signal) { + // No signal, no writer + Py_INCREF(Py_False); + return Py_False; + } + hal_query_t qs = {}; + qs.name = q.pp.signal; + if(0 != (rv = hal_getref_s(&qs))) { + PyErr_Format(PyExc_NameError, "Signal '%s' of pin '%s' gave unexpected error=%d", q.pp.signal, q.name, rv); + return NULL; + } + return PyBool_FromLong(qs.sig.writers > 0); + } else if(-ENOENT == rv) { + // Pin not found + PyErr_Format(PyExc_NameError, "Pin `%s' does not exist", q.name); return NULL; } - - if(pin->signal) { - hal_sig_t *signal = (hal_sig_t*)SHMPTR(pin->signal); - return PyBool_FromLong(signal->writers > 0); - } - Py_INCREF(Py_False); - return Py_False; + PyErr_Format(PyExc_RuntimeError, "pin_has_writer: %s: returned error: %s", q.name, hal_strerror(rv)); + return NULL; } @@ -1270,21 +1205,25 @@ PyObject *component_exists(PyObject * /*self*/, PyObject *args) { const char *name; if(!PyArg_ParseTuple(args, "s", &name)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; // get mutex before accessing shared data - return PyBool_FromLong(halpr_find_comp_by_name(name) != NULL); + int rv = hal_comp_by_name(name, NULL); + if(0 == rv) { + Py_INCREF(Py_True); + return Py_True; + } else if(-ENOENT == rv) { + Py_INCREF(Py_False); + return Py_False; + } + PyErr_Format(PyExc_RuntimeError, "component_exists: hal_comp_by_name '%s' returned %d", name, rv); + return NULL; } PyObject *component_is_ready(PyObject * /*self*/, PyObject *args) { const char *name; if(!PyArg_ParseTuple(args, "s", &name)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; // get mutex before accessing shared data - hal_comp_t *thecomp = halpr_find_comp_by_name(name); - return PyBool_FromLong((thecomp) && (thecomp->ready != 0)); + hal_query_t q = {}; + int rv = hal_comp_by_name(name, &q); + return PyBool_FromLong(0 == rv && q.comp.ready); } PyObject *new_sig(PyObject * /*self*/, PyObject *args) { @@ -1292,16 +1231,14 @@ PyObject *new_sig(PyObject * /*self*/, PyObject *args) { int type,retval; if(!PyArg_ParseTuple(args, "si", &name,&type)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); - //printf("INFO HALMODULE -- make signal -> %s type %d\n",name,(hal_type_t) type); switch (type) { - case HAL_BIT: + case HAL_BOOL: case HAL_S32: case HAL_U32: - case HAL_S64: - case HAL_U64: - case HAL_FLOAT: + case HAL_SINT: + case HAL_UINT: + case HAL_REAL: case HAL_PORT: retval = hal_signal_new(name, (hal_type_t)type); break; @@ -1317,8 +1254,6 @@ PyObject *connect(PyObject * /*self*/, PyObject *args) { const char *signame,*pinname; if(!PyArg_ParseTuple(args, "ss", &pinname,&signame)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); - //printf("INFO HALMODULE -- link sig %s to pin %s\n",signame,pinname); return PyBool_FromLong(hal_link(pinname, signame) != 0); } @@ -1327,522 +1262,359 @@ PyObject *disconnect(PyObject * /*self*/, PyObject *args) { const char *pinname; if(!PyArg_ParseTuple(args, "s", &pinname)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); - //printf("INFO HALMODULE -- unlink pin %s\n",pinname); return PyBool_FromLong(hal_unlink(pinname) != 0); } -static int set_common(hal_type_t type, hal_data_u *d_ptr, PyObject *obj) +static int set_common_cb(hal_query_t *q, void *arg) { - // This function assumes that the mutex is held + PyObject *obj = static_cast(arg); + hal_type_t type = HAL_QTYPE_SIGNAL == q->qtype ? q->sig.type : q->pp.type; + hal_query_value_u *qvp = HAL_QTYPE_SIGNAL == q->qtype ? &q->sig.value : &q->pp.value; switch(type) { - case HAL_BIT: { + case HAL_BOOL: { bool tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->b = tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->b = tmp; break; } - case HAL_FLOAT: { - double tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->f = tmp; + case HAL_REAL: { + rtapi_real tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->r = tmp; break; } case HAL_S32: { rtapi_s32 tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->s = tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->s = tmp; break; } case HAL_U32: { rtapi_u32 tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->u = tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->u = tmp; break; } - case HAL_S64: { - rtapi_s64 tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->ls = tmp; + case HAL_SINT: { + rtapi_sint tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->s = tmp; break; } - case HAL_U64: { - rtapi_u64 tmp; - if(!from_python(obj, &tmp)) return -1; - d_ptr->lu = tmp; + case HAL_UINT: { + rtapi_uint tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->u = tmp; break; } - case HAL_PORT: - if((d_ptr->p != 0) && (hal_port_buffer_size(&d_ptr->p) > 0)) { - // port is already allocated - PyErr_Format(PyExc_RuntimeError, "port has already memory allocated"); - return -1; - } else { - unsigned tmp; - if(!from_python(obj, &tmp)) - return -1; - int err = hal_port_alloc(tmp, &d_ptr->p); - if(err < 0) { - PyErr_Format(PyExc_RuntimeError, "port memory allocation failed"); - } - } + case HAL_PORT: { + unsigned tmp; + if(!from_python(obj, &tmp)) return -EINVAL; + qvp->u = tmp; break; + } default: // Shouldn't get here, but just in case... - return -1; + return -EBADF; } return 0; } PyObject *set_p(PyObject * /*self*/, PyObject *args) { - const char *name; + hal_query_t q = {}; PyObject *obj; - int retval; - hal_type_t type; - hal_data_u *d_ptr; - - if(!PyArg_ParseTuple(args, "sO", &name, &obj)) return NULL; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - scoped_hal_mutex _hallock; // get mutex before accessing shared data + if(!PyArg_ParseTuple(args, "sO", &q.name, &obj)) return NULL; - // Search pin and then param - // We are more likely to set a pin than a param - hal_pin_t *pin = halpr_find_pin_by_name(name); - if(pin == NULL) { - hal_param_t *param = halpr_find_param_by_name(name); - if (param == NULL) { - // Found neither pin nor param - PyErr_Format(PyExc_RuntimeError, "pin or param not found"); - return NULL; - } - // Found a param - type = param->type; - /* is it read only? */ - if (param->dir == HAL_RO) { - PyErr_Format(PyExc_RuntimeError, "param not writable"); - return NULL; - } - d_ptr = reinterpret_cast(SHMPTR(param->data_ptr)); - } else { - // Found a pin - type = pin->type; - if(pin->dir == HAL_OUT) { - PyErr_Format(PyExc_RuntimeError, "pin not writable"); - return NULL; - } - if(pin->type == HAL_PORT) { - PyErr_Format(PyExc_RuntimeError, "ports are not writable"); - return NULL; - } - if(pin->signal != 0) { - PyErr_Format(PyExc_RuntimeError, "pin connected to signal"); - return NULL; - } - d_ptr = &pin->dummysig; + int rv = hal_set_p(&q, set_common_cb, obj); + if(rv < 0) { + PyErr_Format(PyExc_RuntimeError, "set_p: %s: %s", q.name, hal_strerror(rv)); + return NULL; } - - retval = set_common(type, d_ptr, obj); - if(retval != 0) - return NULL; // set_common has set an exception return PyBool_FromLong(1); } PyObject *set_s(PyObject * /*self*/, PyObject *args) { - const char *name; + hal_query_t q = {}; PyObject *obj; - int retval; - hal_sig_t *sig; - hal_type_t type; - hal_data_u *d_ptr; - - if(!PyArg_ParseTuple(args, "sO", &name, &obj)) return NULL; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - scoped_hal_mutex _hallock; // get mutex before accessing shared data + if(!PyArg_ParseTuple(args, "sO", &q.name, &obj)) return NULL; - sig = halpr_find_sig_by_name(name); - if (sig == NULL) { - PyErr_Format(PyExc_RuntimeError, - "signal not found"); + int rv = hal_set_s(&q, set_common_cb, obj); + if(rv < 0) { + PyErr_Format(PyExc_RuntimeError, "set_s: %s: %s", q.name, hal_strerror(rv)); return NULL; - } else { - if ((sig->type != HAL_PORT) && (sig->writers > 0)) { - PyErr_Format(PyExc_RuntimeError, - "signal '%s' already has writer(s)\n", name); - return NULL; - } - /* no writer, so we can safely set it */ - type = sig->type; - d_ptr = reinterpret_cast(SHMPTR(sig->data_ptr)); - retval = set_common(type, d_ptr, obj); - if(retval != 0) - return NULL; // set_common has set an exception - return PyBool_FromLong(1); } + return PyBool_FromLong(1); } /*######################################*/ /* Get a Pin, Param or signal value */ /* Search order: pin, param, signal */ -static PyObject *halref_to_object(hal_data_u *d_ptr, hal_type_t type) +static PyObject *halref_to_object(hal_type_t type, const hal_query_value_u *v) { switch(type) { - case HAL_BIT: return to_python(d_ptr->b); - case HAL_U32: return to_python(d_ptr->u); - case HAL_S32: return to_python(d_ptr->s); - case HAL_U64: return to_python(d_ptr->lu); - case HAL_S64: return to_python(d_ptr->ls); - case HAL_FLOAT: return to_python(d_ptr->f); - case HAL_PORT: return to_python(d_ptr->p); + case HAL_BOOL: return to_python(v->b); + case HAL_U32: return to_python((rtapi_u32)v->u); + case HAL_S32: return to_python((rtapi_s32)v->s); + case HAL_UINT: return to_python(v->u); + case HAL_SINT: return to_python(v->s); + case HAL_REAL: return to_python(v->r); + case HAL_PORT: return to_python(v->s); default: PyErr_Format(PyExc_RuntimeError, "halref_to_object: unknown hal type '%d'", (int)type); return NULL; } } -PyObject *get_value(PyObject * /*self*/, PyObject *args) { - const char *name; +// +// get_p() tries to get the value of a named pin or parameter. +// +PyObject *get_p(PyObject * /*self*/, PyObject *args) +{ + hal_query_t q = {}; - if(!PyArg_ParseTuple(args, "s", &name)) return NULL; + if(!PyArg_ParseTuple(args, "s", &q.name)) return NULL; - TEST_HAL_SHMEM_BASE(__FUNCTION__); + // A connected pin will return the signal's value + int rv = hal_get_p(&q, NULL, NULL); + if(0 == rv) + return halref_to_object(q.pp.type, &q.pp.value); + // Get here: most likely no pin/param with that name + PyErr_Format(PyExc_RuntimeError, "get_p: %s: %s", q.name, hal_strerror(rv)); + return NULL; +} + +// +// get_s() tries to get the value of a named signal. +// +PyObject *get_s(PyObject * /*self*/, PyObject *args) +{ + hal_query_t q = {}; - scoped_hal_mutex _hallock; /* get mutex before accessing shared data */ + if(!PyArg_ParseTuple(args, "s", &q.name)) return NULL; - /* search pin list for name */ - hal_pin_t *pin = halpr_find_pin_by_name(name); - if(pin) { - hal_data_u *d_ptr; - if (pin->signal != 0) { - hal_sig_t *sig = (hal_sig_t*)SHMPTR(pin->signal); - d_ptr = reinterpret_cast(SHMPTR(sig->data_ptr)); - } else { - d_ptr = &(pin->dummysig); - } - return halref_to_object(d_ptr, pin->type); /* convert to python value */ - } - /* search param list for name */ - hal_param_t *param = halpr_find_param_by_name(name); - if (param) { - hal_data_u *d_ptr = reinterpret_cast(SHMPTR(param->data_ptr)); - return halref_to_object(d_ptr, param->type); /* convert to python value */ - } - /* search signal list for name */ - hal_sig_t *sig = halpr_find_sig_by_name(name); - if (sig) { - hal_data_u *d_ptr = reinterpret_cast(SHMPTR(sig->data_ptr)); - return halref_to_object(d_ptr, sig->type); /* convert to python value */ - } - /* error if here */ - PyErr_Format(PyExc_RuntimeError, "Can't get value: pin / param %s not found", name); + int rv = hal_get_s(&q, NULL, NULL); + if(0 == rv) + return halref_to_object(q.sig.type, &q.sig.value); + // Get here: most likely no signal with that name + PyErr_Format(PyExc_RuntimeError, "get_s: %s: %s", q.name, hal_strerror(rv)); return NULL; +} +// +// get_value() first tries pins/params and then signals if no pin/param with +// that name. +// +PyObject *get_value(PyObject * /*self*/, PyObject *args) +{ + hal_query_t q = {}; + + if(!PyArg_ParseTuple(args, "s", &q.name)) return NULL; + + // Try a pin/param + // A connected pin will return the signal's value + int rv = hal_get_p(&q, NULL, NULL); + if(0 == rv) + return halref_to_object(q.pp.type, &q.pp.value); + // No pin/param with that name, try a signal + if(-ENOENT == rv) { + rv = hal_get_s(&q, NULL, NULL); + if(0 == rv) + return halref_to_object(q.sig.type, &q.sig.value); + } + PyErr_Format(PyExc_RuntimeError, "get_value: %s: %s", q.name, hal_strerror(rv)); + return NULL; } /*######################################*/ /* Get a dict of pin info for all pins in system */ -PyObject *get_info_pins(PyObject * /*self*/, PyObject * /*args*/) { - SHMFIELD(hal_pin_t) next; - int type; +static int pinparaminfo_cb(hal_query_t *q, void *arg) +{ + PyObject *lst = static_cast(arg); + PyObject *obj; static const char str_n[] = "NAME"; static const char str_v[] = "VALUE"; static const char str_t[] = "TYPE"; static const char str_d[] = "DIRECTION"; - hal_data_u *d_ptr; - hal_pin_t *pin; - hal_sig_t *sig; + switch(q->pp.type) { + case HAL_BOOL: + obj = Py_BuildValue("{s:s,s:N,s:N,s:N}", + str_n, q->name, str_v, PyBool_FromLong(hal_get_bool(q->pp.ref.b)), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_BOOL)); + break; + case HAL_U32: + obj = Py_BuildValue("{s:s,s:k,s:N,s:N}", + str_n, q->name, str_v, hal_get_ui32(q->pp.ref.u), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_U32)); + break; + case HAL_S32: + obj = Py_BuildValue("{s:s,s:l,s:N,s:N}", + str_n, q->name, str_v, hal_get_si32(q->pp.ref.s), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_S32)); + break; + case HAL_UINT: + obj = Py_BuildValue("{s:s,s:K,s:N,s:N}", + str_n, q->name, str_v, hal_get_uint(q->pp.ref.u), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_UINT)); + break; + case HAL_SINT: + obj = Py_BuildValue("{s:s,s:L,s:N,s:N}", + str_n, q->name, str_v, hal_get_sint(q->pp.ref.s), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_SINT)); + break; + case HAL_REAL: + obj = Py_BuildValue("{s:s,s:d,s:N,s:N}", + str_n, q->name, str_v, hal_get_real(q->pp.ref.r), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_REAL)); + break; + case HAL_PORT: + obj = Py_BuildValue("{s:s,s:l,s:N,s:N}", + str_n, q->name, str_v, hal_get_sint(q->pp.ref.s), + str_d, PyLong_FromLong(q->pp.dir), str_t, PyLong_FromLong(HAL_PORT)); + break; + default: + obj = Py_BuildValue("{s:s,s:s,s:N,s:s}", + str_n, q->name, str_v, NULL, + str_d, PyLong_FromLong(q->pp.dir), str_t, NULL); + break; + } + PyList_Append(lst, obj); + Py_DECREF(obj); + return 0; +} +PyObject *get_info_pins(PyObject * /*self*/, PyObject * /*args*/) +{ PyObject* python_list = PyList_New(0); - PyObject *obj; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; /* get mutex before accessing shared data */ - - next = hal_data->pin_list_ptr; - while (next != 0) { - pin = SHMPTR(next); - type = pin->type; - if (pin->signal != 0) { - sig = (hal_sig_t*)SHMPTR(pin->signal); - d_ptr = reinterpret_cast(SHMPTR(sig->data_ptr)); - } else { - sig = NULL; - d_ptr = &(pin->dummysig); - } - - /* convert to dict of python values */ - switch(type) { - case HAL_BIT: - obj = Py_BuildValue("{s:s,s:N,s:N,s:N}", - str_n, pin->name, - str_v, PyBool_FromLong((long)d_ptr->b), - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_BIT)); - break; - case HAL_U32: - obj = Py_BuildValue("{s:s,s:k,s:N,s:N}", - str_n, pin->name, - str_v, (unsigned long)d_ptr->u, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_U32)); - break; - case HAL_S32: - obj = Py_BuildValue("{s:s,s:l,s:N,s:N}", - str_n, pin->name, - str_v, (long)d_ptr->s, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_S32)); - break; - case HAL_U64: - obj = Py_BuildValue("{s:s,s:K,s:N,s:N}", - str_n, pin->name, - str_v, (unsigned long long)d_ptr->lu, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_S64)); - break; - case HAL_S64: - obj = Py_BuildValue("{s:s,s:L,s:N,s:N}", - str_n, pin->name, - str_v, (long long)d_ptr->ls, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_S64)); - break; - case HAL_FLOAT: - obj = Py_BuildValue("{s:s,s:d,s:N,s:N}", - str_n, pin->name, - str_v, (double)d_ptr->f, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_FLOAT)); - break; - case HAL_PORT: - obj = Py_BuildValue("{s:s,s:l,s:N,s:N}", - str_n, pin->name, - str_v, (long)d_ptr->p, - str_d, PyLong_FromLong(pin->dir), - str_t, PyLong_FromLong(HAL_PORT)); - break; - case HAL_TYPE_UNSPECIFIED: /* fallthrough */ ; - case HAL_TYPE_UNINITIALIZED: /* fallthrough */ ; - default: - obj = Py_BuildValue("{s:s,s:s,s:N,s:s}", - str_n, pin->name, - str_v, NULL, - str_d, PyLong_FromLong(pin->dir), - str_t, NULL); - break; - } - - // add to list - PyList_Append( python_list, obj); - next = pin->next_ptr; + hal_query_t q = {}; + q.qtype = HAL_QTYPE_PIN; // Only handle pins + int rv = hal_list_p(&q, pinparaminfo_cb, python_list); + if(0 != rv) { + Py_DECREF(python_list); + PyErr_Format(PyExc_RuntimeError, "hal_list_p: returned '%s' (%d)", hal_strerror(rv), rv); + return NULL; } - return python_list; } /*######################################*/ /* Get a dict of signal info for all signals in system */ -PyObject *get_info_signals(PyObject * /*self*/, PyObject * /*args*/) { - SHMFIELD(hal_sig_t) next; - int type; + +static int siginfo_writer_cb(hal_query_t *q, void *arg) +{ + if(HAL_OUT == q->pp.dir) { + // Found the writer, record and quit the loop + *((const char **)arg) = q->name; + return 1; + } + return 0; +} + +static int siginfo_cb(hal_query_t *q, void *arg) +{ + PyObject *lst = static_cast(arg); + PyObject *obj; static const char str_n[] = "NAME"; static const char str_v[] = "VALUE"; static const char str_t[] = "TYPE"; static const char str_d[] = "DRIVER"; - hal_data_u *d_ptr; - hal_sig_t *sig; - hal_pin_t *pin; - PyObject* python_list = PyList_New(0); - PyObject *obj; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; /* get mutex before accessing shared data */ - next = hal_data->sig_list_ptr; - while (next != 0) { - sig = SHMPTR(next); - type = sig->type; - d_ptr = reinterpret_cast(SHMPTR(sig->data_ptr)); - - /* it have a writer? */ - pin = halpr_find_pin_by_sig(sig, NULL); - while (pin != NULL) { - if (pin->dir == HAL_OUT){break;} - pin = halpr_find_pin_by_sig(sig, pin); - } - /* convert to dict of python values */ - switch(type) { - case HAL_BIT: - obj = Py_BuildValue("{s:s,s:N,s:s,s:N}", - str_n, sig->name, - str_v, PyBool_FromLong((long)d_ptr->b), - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_BIT)); - break; - case HAL_U32: - obj = Py_BuildValue("{s:s,s:k,s:s,s:N}", - str_n, sig->name, - str_v, (unsigned long)d_ptr->u, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_U32)); - break; - case HAL_S32: - obj = Py_BuildValue("{s:s,s:l,s:s,s:N}", - str_n, sig->name, - str_v, (long)d_ptr->s, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_S32)); - break; - case HAL_U64: - obj = Py_BuildValue("{s:s,s:K,s:s,s:N}", - str_n, sig->name, - str_v, (unsigned long long)d_ptr->lu, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_U64)); - break; - case HAL_S64: - obj = Py_BuildValue("{s:s,s:L,s:s,s:N}", - str_n, sig->name, - str_v, (long long)d_ptr->ls, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_S64)); - break; - case HAL_FLOAT: - obj = Py_BuildValue("{s:s,s:d,s:s,s:N}", - str_n, sig->name, - str_v, (double)d_ptr->f, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_FLOAT)); - break; - case HAL_PORT: - obj = Py_BuildValue("{s:s,s:l,s:s,s:N}", - str_n, sig->name, - str_v, (long)d_ptr->p, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, PyLong_FromLong(HAL_PORT)); - break; - case HAL_TYPE_UNSPECIFIED: /* fallthrough */ ; - case HAL_TYPE_UNINITIALIZED: /* fallthrough */ ; - default: - obj = Py_BuildValue("{s:s,s:s,s:s,s:s}", - str_n, sig->name, - str_v, NULL, - str_d, (pin != NULL) ? pin->name : NULL, - str_t, NULL); - break; - } + const char *writer = NULL; + if(q->sig.writers > 0) { + // Retrieve the writer pin name + hal_query_t qd = {}; + qd.name = q->name; + hal_list_p_s(&qd, siginfo_writer_cb, (void *)&writer); + } - PyList_Append( python_list, obj); - next = sig->next_ptr; + switch(q->sig.type) { + case HAL_BOOL: + obj = Py_BuildValue("{s:s,s:N,s:s,s:N}", + str_n, q->name, str_v, PyBool_FromLong(hal_get_bool(q->sig.ref.b)), + str_d, writer, str_t, PyLong_FromLong(HAL_BOOL)); + break; + case HAL_U32: + obj = Py_BuildValue("{s:s,s:k,s:s,s:N}", + str_n, q->name, str_v, hal_get_ui32(q->sig.ref.u), + str_d, writer, str_t, PyLong_FromLong(HAL_U32)); + break; + case HAL_S32: + obj = Py_BuildValue("{s:s,s:l,s:s,s:N}", + str_n, q->name, str_v, hal_get_si32(q->sig.ref.s), + str_d, writer, str_t, PyLong_FromLong(HAL_S32)); + break; + case HAL_UINT: + obj = Py_BuildValue("{s:s,s:K,s:s,s:N}", + str_n, q->name, str_v, hal_get_uint(q->sig.ref.u), + str_d, writer, str_t, PyLong_FromLong(HAL_UINT)); + break; + case HAL_SINT: + obj = Py_BuildValue("{s:s,s:L,s:s,s:N}", + str_n, q->name, str_v, hal_get_sint(q->sig.ref.s), + str_d, writer, str_t, PyLong_FromLong(HAL_SINT)); + break; + case HAL_REAL: + obj = Py_BuildValue("{s:s,s:d,s:s,s:N}", + str_n, q->name, str_v, hal_get_real(q->sig.ref.r), + str_d, writer, str_t, PyLong_FromLong(HAL_REAL)); + break; + case HAL_PORT: + obj = Py_BuildValue("{s:s,s:l,s:s,s:N}", + str_n, q->name, str_v, hal_get_sint(q->sig.ref.s), + str_d, writer, str_t, PyLong_FromLong(HAL_PORT)); + break; + default: + obj = Py_BuildValue("{s:s,s:s,s:s,s:s}", + str_n, q->name, str_v, NULL, + str_d, writer, str_t, NULL); + break; } + PyList_Append(lst, obj); + Py_DECREF(obj); + return 0; +} +PyObject *get_info_signals(PyObject * /*self*/, PyObject * /*args*/) +{ + PyObject* python_list = PyList_New(0); + hal_query_t q = {}; + int rv = hal_list_s(&q, siginfo_cb, python_list); + if(0 != rv) { + Py_DECREF(python_list); + PyErr_Format(PyExc_RuntimeError, "hal_list_s: returned '%s' (%d)", hal_strerror(rv), rv); + return NULL; + } return python_list; } /*######################################*/ /* Get a dict of parameter info for all parameters in system */ -PyObject *get_info_params(PyObject * /*self*/, PyObject * /*args*/) { - SHMFIELD(hal_param_t) next; - int type; - static const char str_n[] = "NAME"; - static const char str_v[] = "VALUE"; - static const char str_t[] = "TYPE"; - static const char str_d[] = "DIRECTION"; - hal_data_u *d_ptr; - hal_param_t *param; +PyObject *get_info_params(PyObject * /*self*/, PyObject * /*args*/) +{ PyObject* python_list = PyList_New(0); - PyObject *obj; - - TEST_HAL_SHMEM_BASE(__FUNCTION__); - - scoped_hal_mutex _hallock; /* get mutex before accessing shared data */ - - next = hal_data->param_list_ptr; - while (next != 0) { - param = SHMPTR(next); - type = param->type; - d_ptr = reinterpret_cast(SHMPTR(param->data_ptr)); - - /* convert to dict of python values */ - switch(type) { - case HAL_BIT: - obj = Py_BuildValue("{s:s,s:N,s:N,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, PyBool_FromLong((long)d_ptr->b), - str_t, PyLong_FromLong(HAL_BIT)); - break; - case HAL_U32: - obj = Py_BuildValue("{s:s,s:N,s:k,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, (unsigned long)d_ptr->u, - str_t, PyLong_FromLong(HAL_U32)); - break; - case HAL_S32: - obj = Py_BuildValue("{s:s,s:N,s:l,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, (long)d_ptr->s, - str_t, PyLong_FromLong(HAL_S32)); - break; - case HAL_U64: - obj = Py_BuildValue("{s:s,s:N,s:K,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, (unsigned long long)d_ptr->lu, - str_t, PyLong_FromLong(HAL_U64)); - break; - case HAL_S64: - obj = Py_BuildValue("{s:s,s:N,s:L,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, (long long)d_ptr->ls, - str_t, PyLong_FromLong(HAL_S64)); - break; - case HAL_FLOAT: - obj = Py_BuildValue("{s:s,s:N,s:d,s:N}", - str_n, param->name, - str_d, PyLong_FromLong(param->dir), - str_v, (double)d_ptr->f, - str_t, PyLong_FromLong(HAL_FLOAT)); - break; - case HAL_PORT: // HAL_PORT cannot be a parameter - case HAL_TYPE_UNSPECIFIED: /* fallthrough */ ; - case HAL_TYPE_UNINITIALIZED: /* fallthrough */ ; - default: - obj = Py_BuildValue("{s:s,s:s,s:s,s:s}", - str_n, param->name, - str_d, NULL, - str_v, NULL, - str_t, NULL); - break; - } - - PyList_Append( python_list, obj); - next = param->next_ptr; + hal_query_t q = {}; + q.qtype = HAL_QTYPE_PARAM; // Only handle parameters + int rv = hal_list_p(&q, pinparaminfo_cb, python_list); + if(0 != rv) { + Py_DECREF(python_list); + PyErr_Format(PyExc_RuntimeError, "hal_list_p: returned '%s' (%d)", hal_strerror(rv), rv); + return NULL; } - return python_list; } static PyObject *pyhal_get_realtime_type(PyObject * /*self*/, PyObject * /*o*/) { - TEST_HAL_SHMEM_BASE(__FUNCTION__); int res = hal_get_realtime_type(); return PyLong_FromLong(res); } static PyObject *pyhal_is_initialized(PyObject * /*self*/, PyObject * /*o*/) { - return PyBool_FromLong(hal_shmem_base != NULL); + return PyBool_FromLong(hal_is_init()); } struct shmobject { @@ -2061,12 +1833,12 @@ static int pystream_init(PyObject *_self, PyObject *args, PyObject * /*kw*/) { for(int i=0; istream, i)) { - case HAL_BIT: tbuf[i] = 'b'; break; - case HAL_FLOAT: tbuf[i] = 'f'; break; - case HAL_S32: tbuf[i] = 's'; break; - case HAL_U32: tbuf[i] = 'u'; break; - case HAL_S64: tbuf[i] = 'l'; break; - case HAL_U64: tbuf[i] = 'k'; break; + case HAL_BOOL: tbuf[i] = 'b'; break; + case HAL_REAL: tbuf[i] = 'f'; break; + case HAL_S32: tbuf[i] = 's'; break; + case HAL_U32: tbuf[i] = 'u'; break; + case HAL_SINT: tbuf[i] = 'l'; break; + case HAL_UINT: tbuf[i] = 'k'; break; default: tbuf[i] = '?'; break; } } @@ -2312,6 +2084,11 @@ static PyMethodDef module_methods[] = { ".set_p('name', 'value'): Set the pin or param value"}, {"set_s", set_s, METH_VARARGS, ".set_s('name', 'value'): Set the signal value"}, + {"get_p", get_p, METH_VARARGS, + ".get_p('name', 'value'): Get the pin or param value. Will return the signal value if it is a pin and connected"}, + {"get_s", get_s, METH_VARARGS, + ".get_s('name', 'value'): Get the signal value"}, + {"get_value", get_value, METH_VARARGS, ".get_value('name'): Gets the pin, param or signal value"}, @@ -2370,6 +2147,17 @@ PyMODINIT_FUNC PyInit__hal(void); PyMODINIT_FUNC PyInit__hal(void) { PyObject *m = PyModule_Create(&hal_moduledef); + if(!m) + return NULL; + + int rv; + if(0 != (rv = hal_lib_init())) { + PyErr_Format(PyExc_ImportError, "Initializing hal_lib returned error=%d", rv); + Py_DECREF(m); + return NULL; + } + + Py_AtExit(hal_lib_exit); pyhal_error_type = PyErr_NewException("hal.error", NULL, NULL); PyModule_AddObject(m, "error", pyhal_error_type); @@ -2390,6 +2178,10 @@ PyMODINIT_FUNC PyInit__hal(void) PyModule_AddIntConstant(m, "MSG_DBG", RTAPI_MSG_DBG); PyModule_AddIntConstant(m, "MSG_ALL", RTAPI_MSG_ALL); + PyModule_AddIntConstant(m, "HAL_BOOL", HAL_BOOL); + PyModule_AddIntConstant(m, "HAL_REAL", HAL_REAL); + PyModule_AddIntConstant(m, "HAL_SINT", HAL_SINT); + PyModule_AddIntConstant(m, "HAL_UINT", HAL_UINT); PyModule_AddIntConstant(m, "HAL_BIT", HAL_BIT); PyModule_AddIntConstant(m, "HAL_FLOAT", HAL_FLOAT); PyModule_AddIntConstant(m, "HAL_S32", HAL_S32); diff --git a/tests/halmodule.2/expected b/tests/halmodule.2/expected new file mode 100644 index 00000000000..aa4b59a081c --- /dev/null +++ b/tests/halmodule.2/expected @@ -0,0 +1,10 @@ +- [0, 0, 0, 0, 0, 0, 0] +0 [0, 0, 0, 0, 0, 0, 0] +1 [1, 0, 0, 1, 0, 1, 1] +2 [0, 1, 0, 1, 0, 1, 1] +3 [1, 1, 1, 1, 1, 1, 0] +- [1, 0, 0, 1, 0, 1, 1] +0 [1, 0, 0, 1, 0, 1, 1] +1 [0, 1, 0, 1, 0, 1, 1] +2 [1, 1, 1, 1, 1, 1, 0] +3 [0, 0, 0, 0, 0, 0, 0] diff --git a/tests/halmodule.2/halmodtest.py b/tests/halmodule.2/halmodtest.py new file mode 100755 index 00000000000..dfd0def306a --- /dev/null +++ b/tests/halmodule.2/halmodtest.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 + +# +# This shows HAL with Python without creating a component. All functions that +# only require a mapped HAL shared memory segment will function fine without a +# component. +# That means hal.* functions will generally function as expected immediately +# after the HAL module is imported. +# + +import time +import hal + +# Wait for at least one thread cycle +def cycleWait(): + oldtime = time.time() + newval = oldval = hal.get_value("testthread.threadbeat") + while newval <= oldval: + if time.time() - oldtime >= 10.0: + sys.exit("error: cycleWait(): Timeout") + time.sleep(0.001) + newval = hal.get_value("testthread.threadbeat") + +# We need to make sure that the servo-thread ran at least +# once for the input to be copied to the output +cycleWait() + +sigs = [ "net-input-a", "net-input-b", + "and2.0.out", "or2.0.out", + "xor2.0.in0", "xor2.0.in1", + "net-output" ] + +def values(pfx): + out = [] + for s in sigs: + out.append(int(hal.get_value(s))) + print(f"{pfx} {out}") + +values("-") + +v = hal.get_s("net-input-a") +v += hal.get_s("net-input-b") * 2 + +for i in range(4): + hal.set_s("net-input-a", 0 != (i+v) & 1) + hal.set_s("net-input-b", 0 != (i+v) & 2) + # Output is set in the thread cycle, need at least + # one cycle after input change + cycleWait() + values(str(i)) + diff --git a/tests/halmodule.2/test.hal b/tests/halmodule.2/test.hal new file mode 100644 index 00000000000..b9e4ef9dedf --- /dev/null +++ b/tests/halmodule.2/test.hal @@ -0,0 +1,32 @@ +# The goal of this test is to run the 'halmodtest.py' script that will read the +# pins *without* creating a component. We only need a mapped HAL shared memory +# segment for that. +# It is rather unimportant what is loaded. We just need to ensure we have a +# working HAL system and some pins we can look at. +loadrt threads name1=testthread period1=1000000 + +loadrt and2 count=1 +loadrt or2 count=1 +loadrt xor2 count=1 + +addf and2.0 testthread +addf or2.0 testthread +addf xor2.0 testthread + +net net-input-a and2.0.in0 or2.0.in0 +net net-input-b and2.0.in1 or2.0.in1 +net net-xor-a and2.0.out xor2.0.in0 +net net-xor-b or2.0.out xor2.0.in1 +net net-output xor2.0.out + +start + +# Show the initial state +loadusr -w ./halmodtest.py + +# Force some value change +sets net-input-a 1 +sets net-input-b 0 + +# This should show the changed state +loadusr -w ./halmodtest.py