portable.h 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. #ifndef PORTABLE_H
  2. #define PORTABLE_H
  3. /*
  4. * Architecture portability layer.
  5. * Target: Raspberry Pi 5 (BCM2712, Cortex-A76, aarch64 LP64, 8GB RAM)
  6. * and x86_64 dev host. Both are little-endian; PS/RTP/ISUP wire
  7. * formats are BIG-ENDIAN, so every multi-byte field on the wire is
  8. * built via explicit shift writers (never by casting a char* to a
  9. * wider type, which is undefined on strict-alignment ABIs and
  10. * endian-wrong on any host).
  11. */
  12. #include <stdint.h>
  13. #include <stddef.h>
  14. #include <pthread.h>
  15. #include <unistd.h>
  16. #include <limits.h>
  17. #include <errno.h>
  18. /* char is UNSIGNED by default on the ARM AAPCS (aarch64). Never rely on
  19. * signedness of plain char for byte values: always use uint8_t or int. */
  20. /* Fixed-width, ABI-stable types. On LP64 'long' is 8 bytes while on ILP32
  21. * it is 4; we therefore avoid long/int for cross-arch fields. */
  22. typedef int32_t hk_i32;
  23. typedef uint32_t hk_u32;
  24. typedef int64_t hk_i64;
  25. typedef uint64_t hk_u64;
  26. /* Big-endian byte writers (wire order). Unaligned-safe via memcpy, correct
  27. * on x86_64 and aarch64 alike. */
  28. static inline void be_write16(uint8_t *p, uint16_t v){
  29. p[0]=(uint8_t)(v>>8); p[1]=(uint8_t)v;
  30. }
  31. static inline void be_write24(uint8_t *p, uint32_t v){
  32. p[0]=(uint8_t)(v>>16); p[1]=(uint8_t)(v>>8); p[2]=(uint8_t)v;
  33. }
  34. static inline void be_write32(uint8_t *p, uint32_t v){
  35. p[0]=(uint8_t)(v>>24); p[1]=(uint8_t)(v>>16); p[2]=(uint8_t)(v>>8); p[3]=(uint8_t)v;
  36. }
  37. static inline void be_write48(uint8_t *p, uint64_t v){
  38. for(int i=0;i<6;i++) p[i]=(uint8_t)(v>>((5-i)*8));
  39. }
  40. /* Big-endian readers */
  41. static inline uint16_t be_read16(const uint8_t *p){ return (uint16_t)((p[0]<<8)|p[1]); }
  42. static inline uint32_t be_read32(const uint8_t *p){
  43. return ((uint32_t)p[0]<<24)|((uint32_t)p[1]<<16)|((uint32_t)p[2]<<8)|(uint32_t)p[3];
  44. }
  45. /* Monotonic milliseconds (immune to wall-clock jumps / NTP on Pi). */
  46. int64_t portable_now_ms(void);
  47. /* Portable sleep (nanosleep; usleep is deprecated on newer glibc). */
  48. void portable_sleep_ms(int ms);
  49. /* Configure a thread with an explicit stack size (Pi5 default 8MB is fine,
  50. * but big PS buffers are heap-allocated so worker threads get a modest
  51. * 256KB stack -> predictable on 8GB board and embedded builds). */
  52. int portable_thread_create(pthread_t *t, void*(*fn)(void*), void*arg, size_t stack_bytes);
  53. #endif /* PORTABLE_H */