Skip to content

Commit 82fe7af

Browse files
committed
hal: Add new types and API framework for the getter/setter change.
1 parent af6fb80 commit 82fe7af

6 files changed

Lines changed: 589 additions & 125 deletions

File tree

src/hal/hal.h

Lines changed: 245 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,11 @@ RTAPI_BEGIN_DECLS
134134
#include <signal.h>
135135
#endif
136136

137+
#include "rtapi_stdint.h"
138+
#include "rtapi_bool.h"
137139
#include "rtapi_errno.h"
138140

139-
#define HAL_NAME_LEN 47 /* length for pin, signal, etc, names */
141+
#define HAL_NAME_LEN 55 /* length for pin, signal, etc, names */
140142

141143
/** These locking codes define the state of HAL locking, are used by most functions */
142144
/** The functions locked will return a -EPERM error message **/
@@ -290,46 +292,78 @@ typedef enum {
290292
HAL_TYPE_MAX,
291293
} hal_type_t;
292294

293-
/** HAL pins have a direction attribute. A pin may be an input to
294-
the HAL component, an output, or it may be bidirectional.
295-
Any number of HAL_IN or HAL_IO pins may be connected to the same
296-
signal, but only one HAL_OUT pin is permitted. This is equivalent
297-
to connecting two output pins together in an electronic circuit.
298-
(HAL_IO pins can be thought of as tri-state outputs.)
299-
*/
300-
295+
#define HAL_BOOL HAL_BIT
296+
#define HAL_REAL HAL_FLOAT
297+
#define HAL_SINT HAL_S64
298+
#define HAL_UINT HAL_U64
299+
300+
//
301+
// hal_pdir_t - Unified HAL pin/param direction type. Specifies the direction
302+
// of the pins and params while simultaneously allowing us to deduce whether we
303+
// are dealing with a pin or a param.
304+
//
305+
// HAL pins have a direction attribute. A pin may be an input to the HAL
306+
// component, an output, or it may be bidirectional. Any number of HAL_IN or
307+
// HAL_IO pins may be connected to the same signal, but only one HAL_OUT pin is
308+
// permitted. This is equivalent to connecting two output pins together in an
309+
// electronic circuit. (HAL_IO pins can be thought of as tri-state outputs.)
310+
//
311+
// HAL parameters also have a direction attribute. For parameters, the
312+
// attribute determines whether the user can write the value of the parameter,
313+
// or simply read it. HAL_RO parameters are read-only, and HAL_RW ones are
314+
// writable with 'halcmd setp'.
315+
//
301316
typedef enum {
302317
HAL_DIR_UNSPECIFIED = -1,
303-
HAL_IN = 16,
304-
HAL_OUT = 32,
305-
HAL_IO = (HAL_IN | HAL_OUT),
306-
} hal_pin_dir_t;
307-
308-
/** HAL parameters also have a direction attribute. For parameters,
309-
the attribute determines whether the user can write the value
310-
of the parameter, or simply read it. HAL_RO parameters are
311-
read-only, and HAL_RW ones are writable with 'halcmd setp'.
312-
*/
318+
HAL_IN = (1 << 4),
319+
HAL_OUT = (1 << 5),
320+
HAL_IO = (HAL_IN | HAL_OUT),
321+
HAL_RO = (1 << 6),
322+
HAL_WO = (1 << 7), // Actually fake value not enforced
323+
HAL_RW = (HAL_RO | HAL_WO),
324+
} hal_pdir_t;
325+
326+
// Map both old direction types to the new combined type
327+
// FIXME: These should be retired at some point
328+
typedef hal_pdir_t hal_pin_dir_t;
329+
typedef hal_pdir_t hal_param_dir_t;
330+
331+
#define __HAL_ALWAYS_INLINE __attribute__((always_inline))
332+
333+
//
334+
// bool hal_pdir_is_pin(hal_pdir_t)
335+
// bool hal_pdir_is_param(hal_pdir_t)
336+
// bool hal_pdir_is_neither(hal_pdir_t)
337+
//
338+
// Determine whether an I/O direction is a pin, a param or neither.
339+
//
340+
static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_pin(hal_pdir_t v) {
341+
// No other bits than in HAL_IO may be set
342+
return (0 == (v & ~HAL_IO)) && (0 != (v & HAL_IO));
343+
}
344+
static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_param(hal_pdir_t v) {
345+
// No other bits than in HAL_RW may be set
346+
return (0 == (v & ~HAL_RW)) && (0 != (v & HAL_RW));
347+
}
348+
static inline __HAL_ALWAYS_INLINE bool hal_pdir_is_neither(hal_pdir_t v) {
349+
// Any other bits than in HAL_IO|HAL_RW set or none of the set's bits
350+
return (0 != (v & ~(HAL_IO|HAL_RW))) || (0 == (v & (HAL_IO|HAL_RW)));
351+
}
313352

314-
typedef enum {
315-
HAL_RO = 64,
316-
HAL_RW = HAL_RO | 128 /* HAL_WO */,
317-
} hal_param_dir_t;
353+
// FIXME: These alignment attributes should be removed.
354+
// HAL now allocates on an 8-byte boundary and the rest should be left to the
355+
// compiler.
356+
// ==> Remove when we get rid of old hal_*_t typedefs. <==
357+
typedef rtapi_real real_t;
358+
typedef rtapi_u64 ireal_t __attribute__((aligned(8))); // integral type as wide as real_t / hal_float_t
318359

319-
/* Use these for x86 machines, and anything else that can write to
320-
individual bytes in a machine word. */
321-
#include "rtapi_bool.h"
322-
#include "rtapi_stdint.h"
323360
typedef volatile bool hal_bit_t;
324361
typedef volatile rtapi_u32 hal_u32_t;
325362
typedef volatile rtapi_s32 hal_s32_t;
326363
typedef volatile rtapi_u64 hal_u64_t;
327364
typedef volatile rtapi_s64 hal_s64_t;
365+
typedef volatile real_t hal_float_t;
328366
typedef volatile int hal_port_t;
329-
typedef double real_t __attribute__((aligned(8)));
330-
typedef rtapi_u64 ireal_t __attribute__((aligned(8))); // integral type as wide as real_t / hal_float_t
331-
332-
#define hal_float_t volatile real_t
333367

334368
/** HAL "data union" structure
335369
** This structure may hold any type of hal data
@@ -344,6 +378,186 @@ typedef union {
344378
hal_u64_t lu;
345379
} hal_data_u;
346380

381+
// Fake forward declarations so we can make opaque pointers
382+
struct __hal_stype_bool_t;
383+
struct __hal_stype_sint_t;
384+
struct __hal_stype_uint_t;
385+
struct __hal_stype_real_t;
386+
struct __hal_stype_port_t;
387+
388+
typedef struct __hal_stype_bool_t *hal_bool_t;
389+
typedef struct __hal_stype_sint_t *hal_sint_t;
390+
typedef struct __hal_stype_uint_t *hal_uint_t;
391+
typedef struct __hal_stype_real_t *hal_real_t;
392+
//typedef struct __hal_stype_port_t *hal_port_t;
393+
394+
typedef union {
395+
hal_bool_t b;
396+
hal_sint_t s;
397+
hal_uint_t u;
398+
hal_real_t r;
399+
//hal_port_t p;
400+
} hal_refs_u;
401+
402+
// We rely on little-endian memory layout in the union where the smaller
403+
// types are overlapping the larger type's least significant part.
404+
#include "rtapi_byteorder.h"
405+
406+
// The 'defined()' clause is specifically added for cppcheck 2.13.0, used in
407+
// Ubuntu 24.04, which appears to fail somewhere in including rtapi_byteorder.h
408+
// and hits the #error directive.
409+
#if defined(RTAPI_LITTLE_ENDIAN) && !RTAPI_LITTLE_ENDIAN
410+
#error "HAL only supports little endian machines at this moment."
411+
#endif
412+
413+
// This is a define so we don't export it to other code.
414+
// It is undef'ed after we're done with it.
415+
// FIXME: Get rid of the 32-bit types when we have upgraded everything using
416+
// getter/setter access only so we have guaranteed content.
417+
#define __HAL_MAPPED_TYPE union __hal_mapped_type { \
418+
volatile rtapi_bool _b; \
419+
volatile rtapi_s32 _ss; \
420+
volatile rtapi_u32 _su; \
421+
volatile rtapi_sint _s; \
422+
volatile rtapi_uint _u; \
423+
volatile rtapi_real _r; \
424+
}
425+
426+
427+
#if 0
428+
// The port change must be done later
429+
// A 'hal_port_t' is a pin/param reference which content represents
430+
// the integer offset in the HAL shared memory segment to a
431+
// hal_port_shm_t structure.
432+
static inline __HAL_ALWAYS_INLINE rtapi_sint hal_get_port(hal_port_t ref) {
433+
__HAL_MAPPED_TYPE;
434+
// cppcheck-suppress dangerousTypeCast
435+
return ((union __hal_mapped_type *)ref)->_s;
436+
}
437+
static inline __HAL_ALWAYS_INLINE rtapi_sint hal_set_port(hal_port_t ref, rtapi_sint val) {
438+
__HAL_MAPPED_TYPE;
439+
// cppcheck-suppress dangerousTypeCast
440+
((union __hal_mapped_type *)ref)->_s = val; // Store in the larger type
441+
return val;
442+
}
443+
#endif
444+
//
445+
// The hal_{get,set}_si32() and hal_{get,set}_ui32() are only present for
446+
// compatibility. They may be removed when all the remaining code has been
447+
// updated properly. However, there is a case for letting them remain as
448+
// they will simply use implicit truncation.
449+
// The hal_get_{s,u}i32_clamped() functions will not truncate but clamp the
450+
// read value to the appropriate min/max of the 32-bit type.
451+
//
452+
static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_get_si32_clamped(const hal_sint_t ref) {
453+
__HAL_MAPPED_TYPE;
454+
// Down conversion from the larger type
455+
// cppcheck-suppress dangerousTypeCast
456+
rtapi_sint val = ((union __hal_mapped_type *)ref)->_s;
457+
if(val <= RTAPI_INT32_MIN) return RTAPI_INT32_MIN;
458+
if(val >= RTAPI_INT32_MAX) return RTAPI_INT32_MAX;
459+
return (rtapi_s32)val;
460+
}
461+
static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_get_si32(const hal_sint_t ref) {
462+
__HAL_MAPPED_TYPE;
463+
// Implicitly Truncated from the larger type
464+
// cppcheck-suppress dangerousTypeCast
465+
return ((union __hal_mapped_type *)ref)->_ss;
466+
}
467+
static inline __HAL_ALWAYS_INLINE rtapi_s32 hal_set_si32(hal_sint_t ref, rtapi_s32 val) {
468+
__HAL_MAPPED_TYPE;
469+
// cppcheck-suppress dangerousTypeCast
470+
((union __hal_mapped_type *)ref)->_s = val; // Store in the larger type
471+
return val;
472+
}
473+
static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_get_ui32_clamped(const hal_uint_t ref) {
474+
__HAL_MAPPED_TYPE;
475+
// Down conversion from the larger type
476+
// cppcheck-suppress dangerousTypeCast
477+
rtapi_uint val = ((union __hal_mapped_type *)ref)->_u;
478+
if(val >= RTAPI_UINT32_MAX) return RTAPI_UINT32_MAX;
479+
return (rtapi_u32)val;
480+
}
481+
static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_get_ui32(const hal_uint_t ref) {
482+
__HAL_MAPPED_TYPE;
483+
// Implicitly Truncated from the larger type
484+
// cppcheck-suppress dangerousTypeCast
485+
return ((union __hal_mapped_type *)ref)->_su;
486+
}
487+
static inline __HAL_ALWAYS_INLINE rtapi_u32 hal_set_ui32(hal_uint_t ref, rtapi_u32 val) {
488+
__HAL_MAPPED_TYPE;
489+
// cppcheck-suppress dangerousTypeCast
490+
((union __hal_mapped_type *)ref)->_u = val; // Store in the larger type
491+
return val;
492+
}
493+
static inline __HAL_ALWAYS_INLINE rtapi_sint hal_get_sint(const hal_sint_t ref) {
494+
__HAL_MAPPED_TYPE;
495+
// cppcheck-suppress dangerousTypeCast
496+
return ((union __hal_mapped_type *)ref)->_s;
497+
}
498+
static inline __HAL_ALWAYS_INLINE rtapi_sint hal_set_sint(hal_sint_t ref, rtapi_sint val) {
499+
__HAL_MAPPED_TYPE;
500+
// cppcheck-suppress dangerousTypeCast
501+
((union __hal_mapped_type *)ref)->_s = val;
502+
return val;
503+
}
504+
static inline __HAL_ALWAYS_INLINE rtapi_uint hal_get_uint(const hal_uint_t ref) {
505+
__HAL_MAPPED_TYPE;
506+
// cppcheck-suppress dangerousTypeCast
507+
return ((union __hal_mapped_type *)ref)->_u;
508+
}
509+
static inline __HAL_ALWAYS_INLINE rtapi_uint hal_set_uint(hal_uint_t ref, rtapi_uint val) {
510+
__HAL_MAPPED_TYPE;
511+
// cppcheck-suppress dangerousTypeCast
512+
((union __hal_mapped_type *)ref)->_u = val;
513+
return val;
514+
}
515+
static inline __HAL_ALWAYS_INLINE rtapi_real hal_get_real(const hal_real_t ref) {
516+
__HAL_MAPPED_TYPE;
517+
// cppcheck-suppress dangerousTypeCast
518+
return ((union __hal_mapped_type *)ref)->_r;
519+
}
520+
static inline __HAL_ALWAYS_INLINE rtapi_real hal_set_real(hal_real_t ref, rtapi_real val) {
521+
__HAL_MAPPED_TYPE;
522+
// cppcheck-suppress dangerousTypeCast
523+
((union __hal_mapped_type *)ref)->_r = val;
524+
return val;
525+
}
526+
static inline __HAL_ALWAYS_INLINE rtapi_bool hal_get_bool(const hal_bool_t ref) {
527+
__HAL_MAPPED_TYPE;
528+
// cppcheck-suppress dangerousTypeCast
529+
return ((union __hal_mapped_type *)ref)->_b;
530+
}
531+
static inline __HAL_ALWAYS_INLINE rtapi_bool hal_set_bool(hal_bool_t ref, rtapi_bool val) {
532+
__HAL_MAPPED_TYPE;
533+
// 'val' is declared bool and will therefore store a one (1)
534+
// or a zero (0) in the larger target. This still works if the
535+
// call is made using an integer type as original argument.
536+
// cppcheck-suppress dangerousTypeCast
537+
((union __hal_mapped_type *)ref)->_u = val;
538+
return val;
539+
}
540+
#undef __HAL_ALWAYS_INLINE
541+
#undef __HAL_MAPPED_TYPE
542+
543+
#define __HAL_PFMT(a,b) __attribute__((format(printf,a,b)))
544+
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);
545+
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);
546+
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);
547+
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);
548+
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);
549+
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);
550+
// Note: port has no initial default as it is an 'internal' reference
551+
//int hal_pin_new_port(int compid, hal_pin_dir_t dir, hal_port_t *ref, const char *fmt, ...) __HAL_PFMT(4,5);
552+
553+
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);
554+
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);
555+
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);
556+
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);
557+
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);
558+
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);
559+
#undef __HAL_PFMT
560+
347561
/***********************************************************************
348562
* "LOCKING" FUNCTIONS *
349563
************************************************************************/

0 commit comments

Comments
 (0)