diff --git a/src/hal/hal.h b/src/hal/hal.h index fb67a33d3c1..e9311ed64a1 100644 --- a/src/hal/hal.h +++ b/src/hal/hal.h @@ -134,9 +134,11 @@ RTAPI_BEGIN_DECLS #include #endif +#include "rtapi_stdint.h" +#include "rtapi_bool.h" #include "rtapi_errno.h" -#define HAL_NAME_LEN 47 /* length for pin, signal, etc, names */ +#define HAL_NAME_LEN 55 /* length for pin, signal, etc, names */ /** These locking codes define the state of HAL locking, are used by most functions */ /** The functions locked will return a -EPERM error message **/ @@ -285,46 +287,78 @@ typedef enum { HAL_TYPE_MAX, } hal_type_t; -/** HAL pins have a direction attribute. A pin may be an input to - the HAL component, an output, or it may be bidirectional. - Any number of HAL_IN or HAL_IO pins may be connected to the same - signal, but only one HAL_OUT pin is permitted. This is equivalent - to connecting two output pins together in an electronic circuit. - (HAL_IO pins can be thought of as tri-state outputs.) -*/ - +#define HAL_BOOL HAL_BIT +#define HAL_REAL HAL_FLOAT +#define HAL_SINT HAL_S64 +#define HAL_UINT HAL_U64 + +// +// hal_pdir_t - Unified HAL pin/param direction type. Specifies the direction +// of the pins and params while simultaneously allowing us to deduce whether we +// are dealing with a pin or a param. +// +// HAL pins have a direction attribute. A pin may be an input to the HAL +// component, an output, or it may be bidirectional. Any number of HAL_IN or +// HAL_IO pins may be connected to the same signal, but only one HAL_OUT pin is +// permitted. This is equivalent to connecting two output pins together in an +// electronic circuit. (HAL_IO pins can be thought of as tri-state outputs.) +// +// HAL parameters also have a direction attribute. For parameters, the +// attribute determines whether the user can write the value of the parameter, +// or simply read it. HAL_RO parameters are read-only, and HAL_RW ones are +// writable with 'halcmd setp'. +// typedef enum { HAL_DIR_UNSPECIFIED = -1, - HAL_IN = 16, - HAL_OUT = 32, - HAL_IO = (HAL_IN | HAL_OUT), -} hal_pin_dir_t; - -/** HAL parameters also have a direction attribute. For parameters, - the attribute determines whether the user can write the value - of the parameter, or simply read it. HAL_RO parameters are - read-only, and HAL_RW ones are writable with 'halcmd setp'. -*/ + HAL_IN = (1 << 4), + HAL_OUT = (1 << 5), + HAL_IO = (HAL_IN | HAL_OUT), + HAL_RO = (1 << 6), + HAL_WO = (1 << 7), // Actually fake value not enforced + HAL_RW = (HAL_RO | HAL_WO), +} hal_pdir_t; + +// Map both old direction types to the new combined type +// FIXME: These should be retired at some point +typedef hal_pdir_t hal_pin_dir_t; +typedef hal_pdir_t hal_param_dir_t; + +#define __HAL_ALWAYS_INLINE __attribute__((always_inline)) + +// +// bool hal_pdir_is_pin(hal_pdir_t) +// bool hal_pdir_is_param(hal_pdir_t) +// bool hal_pdir_is_neither(hal_pdir_t) +// +// Determine whether an I/O direction is a pin, a param or neither. +// +static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_pin(hal_pdir_t v) { + // No other bits than in HAL_IO may be set + return (0 == (v & ~HAL_IO)) && (0 != (v & HAL_IO)); +} +static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_param(hal_pdir_t v) { + // No other bits than in HAL_RW may be set + return (0 == (v & ~HAL_RW)) && (0 != (v & HAL_RW)); +} +static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_neither(hal_pdir_t v) { + // Any other bits than in HAL_IO|HAL_RW set or none of the set's bits + return (0 != (v & ~(HAL_IO|HAL_RW))) || (0 == (v & (HAL_IO|HAL_RW))); +} -typedef enum { - HAL_RO = 64, - HAL_RW = HAL_RO | 128 /* HAL_WO */, -} hal_param_dir_t; +// FIXME: These alignment attributes should be removed. +// HAL now allocates on an 8-byte boundary and the rest should be left to the +// compiler. +// ==> Remove when we get rid of old hal_*_t typedefs. <== +typedef rtapi_real real_t; +typedef rtapi_u64 ireal_t __attribute__((aligned(8))); // integral type as wide as real_t / hal_float_t -/* Use these for x86 machines, and anything else that can write to - individual bytes in a machine word. */ -#include "rtapi_bool.h" -#include "rtapi_stdint.h" typedef volatile bool hal_bit_t; typedef volatile rtapi_u32 hal_u32_t; typedef volatile rtapi_s32 hal_s32_t; typedef volatile rtapi_u64 hal_u64_t; typedef volatile rtapi_s64 hal_s64_t; +typedef volatile real_t hal_float_t; typedef volatile int hal_port_t; -typedef double real_t __attribute__((aligned(8))); -typedef rtapi_u64 ireal_t __attribute__((aligned(8))); // integral type as wide as real_t / hal_float_t - -#define hal_float_t volatile real_t /** HAL "data union" structure ** This structure may hold any type of hal data @@ -339,6 +373,186 @@ typedef union { hal_u64_t lu; } hal_data_u; +// Fake forward declarations so we can make opaque pointers +struct __hal_stype_bool_t; +struct __hal_stype_sint_t; +struct __hal_stype_uint_t; +struct __hal_stype_real_t; +struct __hal_stype_port_t; + +typedef struct __hal_stype_bool_t *hal_bool_t; +typedef struct __hal_stype_sint_t *hal_sint_t; +typedef struct __hal_stype_uint_t *hal_uint_t; +typedef struct __hal_stype_real_t *hal_real_t; +//typedef struct __hal_stype_port_t *hal_port_t; + +typedef union { + hal_bool_t b; + hal_sint_t s; + hal_uint_t u; + hal_real_t r; + //hal_port_t p; +} hal_refs_u; + +// We rely on little-endian memory layout in the union where the smaller +// types are overlapping the larger type's least significant part. +#include "rtapi_byteorder.h" +#if !RTAPI_LITTLE_ENDIAN +// At least cppcheck 2.17 cannot properly evaluate preprocessor conditions and +// will always trigger this error. Version 2.19 has no problem. However, Debian +// trixie and Ubuntu are on 2.17.1 and it trips CI. +// cppcheck-suppress preprocessorErrorDirective +#error "HAL only supports little endian machines at this moment." +#endif + +// This is a define so we don't export it to other code. +// It is undef'ed after we're done with it. +// FIXME: Get rid of the 32-bit types when we have upgraded everything using +// getter/setter access only so we have guaranteed content. +#define __HAL_MAPPED_TYPE union __hal_mapped_type { \ + volatile rtapi_bool _b; \ + volatile rtapi_s32 _ss; \ + volatile rtapi_u32 _su; \ + volatile rtapi_sint _s; \ + volatile rtapi_uint _u; \ + volatile rtapi_real _r; \ + } + + +#if 0 +// The port change must be done later +// A 'hal_port_t' is a pin/param reference which content represents +// the integer offset in the HAL shared memory segment to a +// hal_port_shm_t structure. +static inline __HAL_ALWAYS_INLINE rtapi_sint hal_get_port(hal_port_t ref) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_s; +} +static inline __HAL_ALWAYS_INLINE rtapi_sint hal_set_port(hal_port_t ref, rtapi_sint val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_s = val; // Store in the larger type + return val; +} +#endif +// +// The hal_{get,set}_si32() and hal_{get,set}_ui32() are only present for +// compatibility. They may be removed when all the remaining code has been +// updated properly. However, there is a case for letting them remain as +// they will simply use implicit truncation. +// The hal_get_{s,u}i32_clamped() functions will not truncate but clamp the +// read value to the appropriate min/max of the 32-bit type. +// +static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_get_si32_clamped(const hal_sint_t ref) { + __HAL_MAPPED_TYPE; + // Down conversion from the larger type + // cppcheck-suppress dangerousTypeCast + rtapi_sint val = ((union __hal_mapped_type *)ref)->_s; + if(val <= RTAPI_INT32_MIN) return RTAPI_INT32_MIN; + if(val >= RTAPI_INT32_MAX) return RTAPI_INT32_MAX; + return (rtapi_s32)val; +} +static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_get_si32(const hal_sint_t ref) { + __HAL_MAPPED_TYPE; + // Implicitly Truncated from the larger type + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_ss; +} +static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_set_si32(hal_sint_t ref, rtapi_s32 val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_s = val; // Store in the larger type + return val; +} +static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_get_ui32_clamped(const hal_uint_t ref) { + __HAL_MAPPED_TYPE; + // Down conversion from the larger type + // cppcheck-suppress dangerousTypeCast + rtapi_uint val = ((union __hal_mapped_type *)ref)->_u; + if(val >= RTAPI_UINT32_MAX) return RTAPI_UINT32_MAX; + return (rtapi_u32)val; +} +static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_get_ui32(const hal_uint_t ref) { + __HAL_MAPPED_TYPE; + // Implicitly Truncated from the larger type + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_su; +} +static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_set_ui32(hal_uint_t ref, rtapi_u32 val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_u = val; // Store in the larger type + return val; +} +static inline __HAL_ALWAYS_INLINE rtapi_sint hal_get_sint(const hal_sint_t ref) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_s; +} +static inline __HAL_ALWAYS_INLINE rtapi_sint hal_set_sint(hal_sint_t ref, rtapi_sint val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_s = val; + return val; +} +static inline __HAL_ALWAYS_INLINE rtapi_uint hal_get_uint(const hal_uint_t ref) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_u; +} +static inline __HAL_ALWAYS_INLINE rtapi_uint hal_set_uint(hal_uint_t ref, rtapi_uint val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_u = val; + return val; +} +static inline __HAL_ALWAYS_INLINE rtapi_real hal_get_real(const hal_real_t ref) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_r; +} +static inline __HAL_ALWAYS_INLINE rtapi_real hal_set_real(hal_real_t ref, rtapi_real val) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_r = val; + return val; +} +static inline __HAL_ALWAYS_INLINE rtapi_bool hal_get_bool(const hal_bool_t ref) { + __HAL_MAPPED_TYPE; + // cppcheck-suppress dangerousTypeCast + return ((union __hal_mapped_type *)ref)->_b; +} +static inline __HAL_ALWAYS_INLINE rtapi_bool hal_set_bool(hal_bool_t ref, rtapi_bool val) { + __HAL_MAPPED_TYPE; + // 'val' is declared bool and will therefore store a one (1) + // or a zero (0) in the larger target. This still works if the + // call is made using an integer type as original argument. + // cppcheck-suppress dangerousTypeCast + ((union __hal_mapped_type *)ref)->_u = val; + return val; +} +#undef __HAL_ALWAYS_INLINE +#undef __HAL_MAPPED_TYPE + +#define __HAL_PFMT(a,b) __attribute__((format(printf,a,b))) +int hal_pin_new_bool(int compid, hal_pdir_t dir, hal_bool_t *ref, rtapi_bool def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_pin_new_si32(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s32 def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_pin_new_ui32(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u32 def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_pin_new_sint(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_sint def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_pin_new_uint(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_uint def, const char *fmt, ...) __HAL_PFMT(5,6); +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); + +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); +int hal_param_new_ui32(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u32 def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_param_new_sint(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_sint def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_param_new_uint(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_uint def, const char *fmt, ...) __HAL_PFMT(5,6); +int hal_param_new_real(int compid, hal_pdir_t dir, hal_real_t *ref, rtapi_real def, const char *fmt, ...) __HAL_PFMT(5,6); +#undef __HAL_PFMT + /*********************************************************************** * "LOCKING" FUNCTIONS * ************************************************************************/ diff --git a/src/hal/hal_lib.c b/src/hal/hal_lib.c index 944ceec10e2..372fa14e53a 100644 --- a/src/hal/hal_lib.c +++ b/src/hal/hal_lib.c @@ -709,6 +709,92 @@ int hal_pin_port_newf(hal_pin_dir_t dir, return ret; } +// *** New interface *** + +int hal_pin_new_bool(int compid, hal_pdir_t dir, hal_bool_t *ref, bool def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_BIT, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_bool(*ref, def); + return 0; +} + +int hal_pin_new_si32(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s32 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_S32, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_si32(*ref, def); + return 0; +} + +int hal_pin_new_ui32(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u32 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_U32, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_ui32(*ref, def); + return 0; +} + +int hal_pin_new_sint(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s64 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_S64, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_sint(*ref, def); + return 0; +} + +int hal_pin_new_uint(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u64 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_U64, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_uint(*ref, def); + return 0; +} + +int hal_pin_new_real(int compid, hal_pdir_t dir, hal_real_t *ref, real_t def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_FLOAT, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_real(*ref, 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, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_pin_newfv(HAL_PORT, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + return ret; +} +#endif /* this is a generic function that does the majority of the work. */ @@ -1016,16 +1102,11 @@ int hal_signal_new(const char *name, hal_type_t type) return -EINVAL; } /* allocate memory for the signal value */ -/* -because accesses will later be through pointer of type hal_data_u, -allocate something that big. Otherwise, gcc -fsanitize=undefined will -issue diagnostics like - hal/hal_lib.c:3203:35: runtime error: member access within misaligned address 0x7fcf3d11f10b for type 'union hal_data_u', which requires 8 byte alignment -on accesses through hal_data_u. - -This does increase memory usage somewhat, but is required for compliance -with the C standard. -*/ + /* It is always the size of the data union. This does increase memory usage + * somewhat, but is required for compliance with the C standard. It also + * fixes an old memory corruption bug. + * See: #421 and https://github.com/machinekit/machinekit/issues/524 + */ switch (type) { case HAL_BIT: case HAL_S32: @@ -1035,13 +1116,14 @@ with the C standard. case HAL_FLOAT: case HAL_PORT: data_addr = shmalloc_up(sizeof(hal_data_u)); - break; + // Initialize the signal value + memset(data_addr, 0, sizeof(hal_data_u)); + break; default: rtapi_mutex_give(&(hal_data->mutex)); rtapi_print_msg(RTAPI_MSG_ERR, "HAL: ERROR: illegal signal type %d'\n", type); return -EINVAL; - break; } /* allocate a new signal structure */ new = alloc_sig_struct(); @@ -1052,32 +1134,6 @@ with the C standard. "HAL: ERROR: insufficient memory for signal '%s'\n", name); return -ENOMEM; } - /* initialize the signal value */ - switch (type) { - case HAL_BIT: - *((hal_bit_t *) data_addr) = 0; - break; - case HAL_S32: - *((hal_s32_t *) data_addr) = 0; - break; - case HAL_U32: - *((hal_u32_t *) data_addr) = 0; - break; - case HAL_S64: - *((hal_s64_t *) data_addr) = 0; - break; - case HAL_U64: - *((hal_u64_t *) data_addr) = 0; - break; - case HAL_FLOAT: - *((hal_float_t *) data_addr) = 0.0; - break; - case HAL_PORT: - *((int *) data_addr) = 0; - break; - default: - break; - } /* initialize the structure */ new->data_ptr = SHMOFF(data_addr); new->type = type; @@ -1490,8 +1546,12 @@ int hal_param_s64_newf(hal_param_dir_t dir, hal_s64_t * data_addr, /* this is a generic function that does the majority of the work. */ -int hal_param_new(const char *name, hal_type_t type, hal_param_dir_t dir, void *data_addr, - int comp_id) +// The old API parameter style uses the 'data_addr' as the actual data storage +// location. +// The new API uses local data in the hal param structure and the data_addr is +// a reference to the data into the hal param structure (just like pins). +static int hal_param_new_anyapi(const char *name, hal_type_t type, hal_pdir_t dir, void *data_addr, + int comp_id, bool newapi) { rtapi_intptr_t *prev, next; int cmp; @@ -1578,7 +1638,14 @@ int hal_param_new(const char *name, hal_type_t type, hal_param_dir_t dir, void * } /* initialize the structure */ new->owner_ptr = SHMOFF(comp); - new->data_ptr = SHMOFF(data_addr); + if (newapi) { + // New API has the parameter value as part of the param structure + new->data_ptr = SHMOFF(&(new->data)); + *(void **)data_addr = (char *)comp->shmem_base + SHMOFF(&(new->data)); + } else { + // Old API has the parameter value as user supplied pointer + new->data_ptr = SHMOFF(data_addr); + } new->type = type; new->dir = dir; rtapi_snprintf(new->name, sizeof(new->name), "%s", name); @@ -1616,6 +1683,102 @@ int hal_param_new(const char *name, hal_type_t type, hal_param_dir_t dir, void * } } +// Old API interface +int hal_param_new(const char *name, hal_type_t type, hal_pdir_t dir, void *data_addr, + int comp_id) +{ + return hal_param_new_anyapi(name, type, dir, data_addr, comp_id, 0); +} + +// New API interface only used locally +static int hal_param_new_newapi(hal_type_t type, hal_pdir_t dir, void *data_addr, + int comp_id, const char *fmt, va_list ap) +{ + char name[HAL_NAME_LEN + 1]; + int sz = rtapi_vsnprintf(name, sizeof(name), fmt, ap); + if(sz == -1 || sz > HAL_NAME_LEN) { + rtapi_print_msg(RTAPI_MSG_ERR, + "hal_param_new_newapi: length %d too long for name starting '%s'\n", + sz, name); + return -ENOMEM; + } + return hal_param_new_anyapi(name, type, dir, data_addr, comp_id, 1); +} + +// *** New interface *** + +int hal_param_new_bool(int compid, hal_pdir_t dir, hal_bool_t *ref, bool def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_BIT, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_bool(*ref, def); + return 0; +} + +int hal_param_new_si32(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s32 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_S32, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_si32(*ref, def); + return 0; +} + +int hal_param_new_ui32(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u32 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_U32, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_ui32(*ref, def); + return 0; +} + +int hal_param_new_sint(int compid, hal_pdir_t dir, hal_sint_t *ref, rtapi_s64 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_S64, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_sint(*ref, def); + return 0; +} + +int hal_param_new_uint(int compid, hal_pdir_t dir, hal_uint_t *ref, rtapi_u64 def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_U64, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_uint(*ref, def); + return 0; +} + +int hal_param_new_real(int compid, hal_pdir_t dir, hal_real_t *ref, real_t def, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int ret = hal_param_new_newapi(HAL_FLOAT, dir, (void**)ref, compid, fmt, ap); + va_end(ap); + if(ret) + return ret; + hal_set_real(*ref, def); + return 0; +} + /* wrapper functs for typed params - these call the generic funct below */ int hal_param_bit_set(const char *name, int value) @@ -3294,21 +3457,22 @@ static void *shmalloc_up(long int size) return NULL; } + // We want to keep allocations on proper 64-bit alignment. The value + // allocations are already sizeof(hal_data_u) and this will just enforce + // the minimum size so we won't see any memory corruptions. + if (size < 8) + size = 8; + /* deal with alignment requirements */ tmp_bot = hal_data->shmem_bot; if (size >= 16) { /* align on 16 byte boundary */ tmp_bot = (tmp_bot + 15) & (~15); - } else if (size >= 8) { + } else { /* align on 8 byte boundary */ tmp_bot = (tmp_bot + 7) & (~7); - } else if (size >= 4) { - /* align on 4 byte boundary */ - tmp_bot = (tmp_bot + 3) & (~3); - } else if (size == 2) { - /* align on 2 byte boundary */ - tmp_bot = (tmp_bot + 1) & (~1); } + /* is there enough memory available? */ if ((hal_data->shmem_top - tmp_bot) < size) { /* no */ @@ -3332,22 +3496,23 @@ static void *shmalloc_dn(long int size) return NULL; } + // We want to keep allocations on proper 64-bit alignment. The value + // allocations are already sizeof(hal_data_u) and this will just enforce + // the minimum size so we won't see any memory corruptions. + if (size < 8) + size = 8; + /* tentatively allocate memory */ tmp_top = hal_data->shmem_top - size; /* deal with alignment requirements */ if (size >= 16) { /* align on 16 byte boundary */ tmp_top &= (~15); - } else if (size >= 8) { + } else { /* align on 8 byte boundary */ tmp_top &= (~7); - } else if (size >= 4) { - /* align on 4 byte boundary */ - tmp_top &= (~3); - } else if (size == 2) { - /* align on 2 byte boundary */ - tmp_top &= (~1); } + /* is there enough memory available? */ if (tmp_top < hal_data->shmem_bot) { /* no */ @@ -3724,10 +3889,12 @@ static void unlink_pin(hal_pin_t * pin) static void free_pin_struct(hal_pin_t * pin) { - unlink_pin(pin); /* clear contents of struct */ - if ( pin->oldname != 0 ) free_oldname_struct(SHMPTR(pin->oldname)); + if ( pin->oldname != 0 ) { + free_oldname_struct(SHMPTR(pin->oldname)); + pin->oldname = 0; + } pin->data_ptr_addr = 0; pin->owner_ptr = 0; pin->type = 0; @@ -3767,10 +3934,16 @@ static void free_sig_struct(hal_sig_t * sig) static void free_param_struct(hal_param_t * p) { /* clear contents of struct */ - if ( p->oldname != 0 ) free_oldname_struct(SHMPTR(p->oldname)); + if ( p->oldname != 0 ) { + free_oldname_struct(SHMPTR(p->oldname)); + p->oldname = 0; + } p->data_ptr = 0; p->owner_ptr = 0; p->type = 0; + p->dir = 0; + p->reserved = 0; + memset(&p->data, 0, sizeof(p->data)); p->name[0] = '\0'; /* add it to free list (params use the same struct as src vars) */ p->next_ptr = hal_data->param_free_ptr; @@ -4678,6 +4851,14 @@ EXPORT_SYMBOL(hal_exit); EXPORT_SYMBOL(hal_malloc); EXPORT_SYMBOL(hal_comp_name); +EXPORT_SYMBOL(hal_pin_new_bool); +EXPORT_SYMBOL(hal_pin_new_si32); +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_bit_new); EXPORT_SYMBOL(hal_pin_float_new); EXPORT_SYMBOL(hal_pin_u32_new); @@ -4716,6 +4897,13 @@ EXPORT_SYMBOL(hal_param_s32_newf); EXPORT_SYMBOL(hal_param_u64_newf); EXPORT_SYMBOL(hal_param_s64_newf); +EXPORT_SYMBOL(hal_param_new_bool); +EXPORT_SYMBOL(hal_param_new_si32); +EXPORT_SYMBOL(hal_param_new_ui32); +EXPORT_SYMBOL(hal_param_new_sint); +EXPORT_SYMBOL(hal_param_new_uint); +EXPORT_SYMBOL(hal_param_new_real); + EXPORT_SYMBOL(hal_param_bit_set); EXPORT_SYMBOL(hal_param_float_set); EXPORT_SYMBOL(hal_param_u32_set); diff --git a/src/hal/hal_priv.h b/src/hal/hal_priv.h index 33efadb303f..cad0a246293 100644 --- a/src/hal/hal_priv.h +++ b/src/hal/hal_priv.h @@ -118,8 +118,8 @@ */ #define HAL_KEY 0x48414C32 /* key used to open HAL shared memory */ -#define HAL_VER 0x00000010 /* version code */ -#define HAL_SIZE (256*4096) +#define HAL_VER 0x00000011 /* version code */ +#define HAL_SIZE (2*256*4096) #define HAL_PSEUDO_COMP_PREFIX "__" /* prefix to identify a pseudo component */ /* These pointers are set by hal_init() to point to the shmem block @@ -308,14 +308,16 @@ struct hal_comp_t { /** HAL 'pin' data structure. This structure contains information about a 'pin' object. + The structure layout is matched in the parameter layout. + FIXME: Merge with hal_param_t */ struct hal_pin_t { SHMFIELD(hal_pin_t) next_ptr; /* next pin in linked list */ SHMFIELD(void*) data_ptr_addr; /* address of pin data pointer */ SHMFIELD(hal_comp_t) owner_ptr; /* component that owns this pin */ - SHMFIELD(hal_sig_t) signal; /* signal to which pin is linked */ - hal_data_u dummysig; /* if unlinked, data_ptr points here */ SHMFIELD(hal_oldname_t) oldname; /* old name if aliased, else zero */ + hal_data_u dummysig; /* if unlinked, data_ptr points here */ + SHMFIELD(hal_sig_t) signal; /* signal to which pin is linked */ hal_type_t type; /* data type */ hal_pin_dir_t dir; /* pin direction */ char name[HAL_NAME_LEN + 1]; /* pin name */ @@ -336,12 +338,16 @@ struct hal_sig_t { /** HAL 'parameter' data structure. This structure contains information about a 'parameter' object. + The structure layout is matched in the pin layout. + FIXME: Merge with hal_pin_t */ struct hal_param_t { SHMFIELD(hal_param_t) next_ptr; /* next parameter in linked list */ SHMFIELD(void*) data_ptr; /* offset of parameter value */ SHMFIELD(hal_comp_t) owner_ptr; /* component that owns this signal */ SHMFIELD(hal_oldname_t) oldname; /* old name if aliased, else zero */ + hal_data_u data; /* new API parameter storage is here, data_ptr points here too */ + SHMFIELD(void*) reserved; /* reserved to match hal_pin_t layout */ hal_type_t type; /* data type */ hal_param_dir_t dir; /* data direction */ char name[HAL_NAME_LEN + 1]; /* parameter name */ @@ -373,7 +379,7 @@ struct hal_funct_t { void (*funct) (void *, long); /* ptr to function code */ hal_s32_t* runtime; /* (pin) duration of last run, in CPU cycles */ hal_s32_t maxtime; /* (param) duration of longest run, in CPU cycles */ - hal_bit_t maxtime_increased; /* on last call, maxtime increased */ + hal_bit_t maxtime_increased; /* (param) on last call, maxtime increased */ char name[HAL_NAME_LEN + 1]; /* function name */ }; diff --git a/src/hal/utils/halcompile.g b/src/hal/utils/halcompile.g index fcce8c63297..baffc17027a 100644 --- a/src/hal/utils/halcompile.g +++ b/src/hal/utils/halcompile.g @@ -24,7 +24,7 @@ parser Hal: token END: ";;" token PARAMDIRECTION: "rw|r" token PINDIRECTION: "in|out|io" - token TYPE: "float|bit|signed|unsigned|u32|s32|u64|s64|port" + token TYPE: "float|bit|signed|unsigned|u32|s32|u64|s64|port|bool|sint|uint|si32|ui32|real" token NAME: "[a-zA-Z_][a-zA-Z0-9_]*" token STARREDNAME: "[*]*[a-zA-Z_][a-zA-Z0-9_]*" token HALNAME: "[#a-zA-Z_][-#a-zA-Z0-9_.]*" @@ -153,6 +153,7 @@ dirmap = {'r': 'HAL_RO', 'rw': 'HAL_RW', 'in': 'HAL_IN', 'out': 'HAL_OUT', 'io': typemap = {'signed': 's32', 'unsigned': 'u32'} deprmap = {'s32': 'signed', 'u32': 'unsigned'} deprecated = ['s32', 'u32'] +newtypes = ['bool', 'sint', 'uint', 'si32', 'ui32', 'real'] def initialize(): global functions, params, pins, comp_name, names, docs, variables @@ -275,6 +276,10 @@ def to_c(name): name = re.sub("[-._]*#+", "", name) name = name.replace("#", "").replace(".", "_").replace("-", "_") return re.sub("_+", "_", name) +def to_t(t): + if "si32" == t: return "sint" + if "ui32" == t: return "uint" + return t def prologue(f): print("/* Autogenerated by %s on %s -- do not edit */" % ( @@ -345,19 +350,20 @@ static int comp_id; print(" int _personality;", file=f) for name, type_, array, dir_, value, personality in pins: + star = '' if type_ in newtypes else '*' if array: if isinstance(array, tuple): array = array[0] - print(" hal_%s_t *%s_p[%s];" % (type_, to_c(name), array), file=f) + print(" hal_%s_t %s%s_p[%s];" % (to_t(type_), star, to_c(name), array), file=f) else: - print(" hal_%s_t *%s_p;" % (type_, to_c(name)), file=f) + print(" hal_%s_t %s%s_p;" % (to_t(type_), star, to_c(name)), file=f) names[name] = 1 for name, type_, array, dir_, value, personality in params: if array: if isinstance(array, tuple): array = array[0] - print(" hal_%s_t %s_p[%s];" % (type_, to_c(name), array), file=f) + print(" hal_%s_t %s_p[%s];" % (to_t(type_), to_c(name), array), file=f) else: - print(" hal_%s_t %s_p;" % (type_, to_c(name)), file=f) + print(" hal_%s_t %s_p;" % (to_t(type_), to_c(name)), file=f) names[name] = 1 for type_, name, array, value in variables: @@ -431,6 +437,7 @@ static int comp_id; if has_personality: print(" personality = inst->_personality;", file=f) for name, type_, array, dir_, value, personality in pins: + isnewtype = type_ in newtypes if personality: print("if(%s) {" % personality, file=f) if array: @@ -444,24 +451,35 @@ static int comp_id; print(" }", file=f) else: cnt = array print(" for(j=0; j < (%s); j++) {" % cnt, file=f) - print(" r = hal_pin_%s_newf(%s, &(inst->%s_p[j]), comp_id," % ( - type_, dirmap[dir_], to_c(name)), file=f) + if isnewtype: + dflt = "%s" % value if value is not None else "0" + print(" r = hal_pin_new_%s(comp_id, %s, &(inst->%s_p[j]), %s," % ( + type_, dirmap[dir_], to_c(name), dflt), file=f) + else: + print(" r = hal_pin_%s_newf(%s, &(inst->%s_p[j]), comp_id," % ( + type_, dirmap[dir_], to_c(name)), file=f) print(" \"%%s%s\", prefix, j);" % to_hal("." + name), file=f) print(" if(r != 0) return r;", file=f) - if value is not None: + if not isnewtype and value is not None: print(" *(inst->%s_p[j]) = %s;" % (to_c(name), value), file=f) print(" }", file=f) else: - print(" r = hal_pin_%s_newf(%s, &(inst->%s_p), comp_id," % ( - type_, dirmap[dir_], to_c(name)), file=f) + if isnewtype: + dflt = "%s" % value if value is not None else "0" + print(" r = hal_pin_new_%s(comp_id, %s, &(inst->%s_p), %s," % ( + type_, dirmap[dir_], to_c(name), dflt), file=f) + else: + print(" r = hal_pin_%s_newf(%s, &(inst->%s_p), comp_id," % ( + type_, dirmap[dir_], to_c(name)), file=f) print(" \"%%s%s\", prefix);" % to_hal("." + name), file=f) print(" if(r != 0) return r;", file=f) - if value is not None: + if not isnewtype and value is not None: print(" *(inst->%s_p) = %s;" % (to_c(name), value), file=f) if personality: print("}", file=f) for name, type_, array, dir_, value, personality in params: + isnewtype = type_ in newtypes if personality: print("if(%s) {" % personality, file=f) if array: @@ -475,18 +493,28 @@ static int comp_id; print(" }", file=f) else: cnt = array print(" for(j=0; j < (%s); j++) {" % cnt, file=f) - print(" r = hal_param_%s_newf(%s, &(inst->%s_p[j]), comp_id," % ( - type_, dirmap[dir_], to_c(name)), file=f) + if isnewtype: + dflt = "%s" % value if value is not None else "0" + print(" r = hal_param_new_%s(comp_id, %s, &(inst->%s_p[j]), %s," % ( + type_, dirmap[dir_], to_c(name), dflt), file=f) + else: + print(" r = hal_param_%s_newf(%s, &(inst->%s_p[j]), comp_id," % ( + type_, dirmap[dir_], to_c(name)), file=f) print(" \"%%s%s\", prefix, j);" % to_hal("." + name), file=f) print(" if(r != 0) return r;", file=f) - if value is not None: + if not isnewtype and value is not None: print(" inst->%s_p[j] = %s;" % (to_c(name), value), file=f) print(" }", file=f) else: - print(" r = hal_param_%s_newf(%s, &(inst->%s_p), comp_id," % ( - type_, dirmap[dir_], to_c(name)), file=f) + if isnewtype: + dflt = "%s" % value if value is not None else "0" + print(" r = hal_param_new_%s(comp_id, %s, &(inst->%s_p), %s," % ( + type_, dirmap[dir_], to_c(name), dflt), file=f) + else: + print(" r = hal_param_%s_newf(%s, &(inst->%s_p), comp_id," % ( + type_, dirmap[dir_], to_c(name)), file=f) print(" \"%%s%s\", prefix);" % to_hal("." + name), file=f) - if value is not None: + if not isnewtype and value is not None: print(" inst->%s_p = %s;" % (to_c(name), value), file=f) print(" if(r != 0) return r;", file=f) if personality: @@ -752,26 +780,46 @@ int __comp_parse_names(int *argc, char **argv) { print("#undef fperiod", file=f) print("#define fperiod (period * 1e-9)", file=f) for name, type_, array, dir_, value, personality in pins: - print("#undef %s" % to_c(name), file=f) - print("#undef %s_ptr" % to_c(name), file=f) - if array: - print("#define %s_ptr(i) (__comp_inst->%s_p[i])" % (to_c(name), to_c(name)), file=f) - if dir_ == 'in': - print("#define %s(i) (0+*(__comp_inst->%s_p[i]))" % (to_c(name), to_c(name)), file=f) + if type_ in newtypes: + if array: + print("#define %s_ptr(i) (__comp_inst->%s_p[(i)])" % (to_c(name), to_c(name)), file=f) + if dir_ != 'in': # Only I/O and output pins can be 'set' + print("#define %s_set(i,v) (hal_set_%s(__comp_inst->%s_p[(i)],(v)))" % (to_c(name), type_, to_c(name)), file=f) + print("#define %s(i) (hal_get_%s(__comp_inst->%s_p[(i)]))" % (to_c(name), type_, to_c(name)), file=f) else: - print("#define %s(i) (*(__comp_inst->%s_p[i]))" % (to_c(name), to_c(name)), file=f) + print("#define %s_ptr (__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + if dir_ != 'in': # Only I/O and output pins can be 'set' + print("#define %s_set(v) (hal_set_%s(__comp_inst->%s_p,(v)))" % (to_c(name), type_, to_c(name)), file=f) + print("#define %s (hal_get_%s(__comp_inst->%s_p))" % (to_c(name), type_, to_c(name)), file=f) else: - print("#define %s_ptr (__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) - if dir_ == 'in': - print("#define %s (0+*__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + print("#undef %s" % to_c(name), file=f) + print("#undef %s_ptr" % to_c(name), file=f) + if array: + print("#define %s_ptr(i) (__comp_inst->%s_p[(i)])" % (to_c(name), to_c(name)), file=f) + if dir_ == 'in': + print("#define %s(i) (0+*(__comp_inst->%s_p[(i)]))" % (to_c(name), to_c(name)), file=f) + else: + print("#define %s(i) (*(__comp_inst->%s_p[(i)]))" % (to_c(name), to_c(name)), file=f) else: - print("#define %s (*__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + print("#define %s_ptr (__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + if dir_ == 'in': + print("#define %s (0+*__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + else: + print("#define %s (*__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) for name, type_, array, dir_, value, personality in params: - print("#undef %s" % to_c(name), file=f) - if array: - print("#define %s(i) (__comp_inst->%s_p[i])" % (to_c(name), to_c(name)), file=f) + if type_ in newtypes: + if array: + print("#define %s(i) (hal_get_%s(__comp_inst->%s_p[i]))" % (to_c(name), type_, to_c(name)), file=f) + print("#define %s_set(i,v) (hal_set_%s(__comp_inst->%s_p[i],(v)))" % (to_c(name), type_, to_c(name)), file=f) + else: + print("#define %s (hal_get_%s(__comp_inst->%s_p))" % (to_c(name), type_, to_c(name)), file=f) + print("#define %s_set(v) (hal_set_%s(__comp_inst->%s_p,(v)))" % (to_c(name), type_, to_c(name)), file=f) else: - print("#define %s (__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) + print("#undef %s" % to_c(name), file=f) + if array: + print("#define %s(i) (__comp_inst->%s_p[i])" % (to_c(name), to_c(name)), file=f) + else: + print("#define %s (__comp_inst->%s_p)" % (to_c(name), to_c(name)), file=f) for type_, name, array, value in variables: name = name.replace("*", "") diff --git a/src/rtapi/rtapi_bool.h b/src/rtapi/rtapi_bool.h index 2040fc72daa..0a9fcb36fac 100644 --- a/src/rtapi/rtapi_bool.h +++ b/src/rtapi/rtapi_bool.h @@ -22,4 +22,7 @@ #include #endif +// Abstracted for HAL +typedef bool rtapi_bool; + #endif diff --git a/src/rtapi/rtapi_stdint.h b/src/rtapi/rtapi_stdint.h index 4000e9473e7..06a4f6866a2 100644 --- a/src/rtapi/rtapi_stdint.h +++ b/src/rtapi/rtapi_stdint.h @@ -75,4 +75,9 @@ typedef uintptr_t rtapi_uintptr_t; #define RTAPI_UINT64_MAX UINT64_MAX #endif +// Abstracted for HAL +typedef double rtapi_real; +typedef rtapi_s64 rtapi_sint; +typedef rtapi_u64 rtapi_uint; + #endif