diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-26 14:58:07 -0400 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-26 17:10:36 -0400 |
commit | cf4af09e9a20e9cdaec4b3896eb6d10c27f89eba (patch) | |
tree | 016f876531f7dfc822be17f686074f0c859fd508 | |
parent | 42fb27570262b52e2ca889030c621b5f4af76fe1 (diff) |
No more (static inline) function bodies in headers
-rw-r--r-- | lib9p/srv.c | 9 | ||||
-rw-r--r-- | lib9p/srv_include/lib9p/srv.h | 9 | ||||
-rw-r--r-- | libdhcp/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libdhcp/dhcp_common.c | 104 | ||||
-rw-r--r-- | libdhcp/dhcp_common.h | 96 | ||||
-rw-r--r-- | libhw_cr/CMakeLists.txt | 1 | ||||
-rw-r--r-- | libhw_cr/host_util.c | 29 | ||||
-rw-r--r-- | libhw_cr/host_util.h | 33 | ||||
-rw-r--r-- | libhw_cr/rp2040_dma.c | 18 | ||||
-rw-r--r-- | libhw_cr/rp2040_dma.h | 5 | ||||
-rw-r--r-- | libhw_cr/w5500_ll.c | 105 | ||||
-rw-r--r-- | libhw_cr/w5500_ll.h | 91 | ||||
-rw-r--r-- | libhw_generic/alarmclock.c | 16 | ||||
-rw-r--r-- | libhw_generic/include/libhw/generic/alarmclock.h | 19 | ||||
-rw-r--r-- | libmisc/CMakeLists.txt | 4 | ||||
-rw-r--r-- | libmisc/endian.c | 136 | ||||
-rw-r--r-- | libmisc/fmt.c | 14 | ||||
-rw-r--r-- | libmisc/hash.c | 24 | ||||
-rw-r--r-- | libmisc/include/libmisc/endian.h | 219 | ||||
-rw-r--r-- | libmisc/include/libmisc/fmt.h | 18 | ||||
-rw-r--r-- | libmisc/include/libmisc/hash.h | 20 | ||||
-rw-r--r-- | libmisc/include/libmisc/rand.h | 32 | ||||
-rw-r--r-- | libmisc/include/libmisc/utf8.h | 33 | ||||
-rw-r--r-- | libmisc/rand.c | 38 | ||||
-rw-r--r-- | libmisc/utf8.c | 40 |
25 files changed, 596 insertions, 518 deletions
diff --git a/lib9p/srv.c b/lib9p/srv.c index 56fc3ec..32e9a9a 100644 --- a/lib9p/srv.c +++ b/lib9p/srv.c @@ -61,6 +61,15 @@ void lib9p_srv_acknowledge_flush(struct lib9p_srv_ctx *ctx) { /* structs ********************************************************************/ +void lib9p_srv_stat_assert(struct lib9p_srv_stat stat) { + assert( ((bool)(stat.mode & LIB9P_DM_DIR )) == ((bool)(stat.qid.type & LIB9P_QT_DIR )) ); + assert( ((bool)(stat.mode & LIB9P_DM_APPEND)) == ((bool)(stat.qid.type & LIB9P_QT_APPEND)) ); + assert( ((bool)(stat.mode & LIB9P_DM_EXCL )) == ((bool)(stat.qid.type & LIB9P_QT_EXCL )) ); + assert( ((bool)(stat.mode & LIB9P_DM_AUTH )) == ((bool)(stat.qid.type & LIB9P_QT_AUTH )) ); + assert( ((bool)(stat.mode & LIB9P_DM_TMP )) == ((bool)(stat.qid.type & LIB9P_QT_TMP )) ); + assert( (stat.size == 0) || !(stat.mode & LIB9P_DM_DIR) ); +} + enum srv_filetype { SRV_FILETYPE_FILE, SRV_FILETYPE_DIR, diff --git a/lib9p/srv_include/lib9p/srv.h b/lib9p/srv_include/lib9p/srv.h index c40c85a..eb87d6f 100644 --- a/lib9p/srv_include/lib9p/srv.h +++ b/lib9p/srv_include/lib9p/srv.h @@ -96,14 +96,7 @@ struct lib9p_srv_stat { #endif }; -static inline void lib9p_srv_stat_assert(struct lib9p_srv_stat stat) { - assert( ((bool)(stat.mode & LIB9P_DM_DIR )) == ((bool)(stat.qid.type & LIB9P_QT_DIR )) ); - assert( ((bool)(stat.mode & LIB9P_DM_APPEND)) == ((bool)(stat.qid.type & LIB9P_QT_APPEND)) ); - assert( ((bool)(stat.mode & LIB9P_DM_EXCL )) == ((bool)(stat.qid.type & LIB9P_QT_EXCL )) ); - assert( ((bool)(stat.mode & LIB9P_DM_AUTH )) == ((bool)(stat.qid.type & LIB9P_QT_AUTH )) ); - assert( ((bool)(stat.mode & LIB9P_DM_TMP )) == ((bool)(stat.qid.type & LIB9P_QT_TMP )) ); - assert( (stat.size == 0) || !(stat.mode & LIB9P_DM_DIR) ); -} +void lib9p_srv_stat_assert(struct lib9p_srv_stat stat); /* interface definitions ******************************************************/ diff --git a/libdhcp/CMakeLists.txt b/libdhcp/CMakeLists.txt index dee7cb6..69ad470 100644 --- a/libdhcp/CMakeLists.txt +++ b/libdhcp/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(libdhcp INTERFACE) target_include_directories(libdhcp PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_sources(libdhcp INTERFACE dhcp_client.c + dhcp_common.c ) target_link_libraries(libdhcp INTERFACE libmisc diff --git a/libdhcp/dhcp_common.c b/libdhcp/dhcp_common.c new file mode 100644 index 0000000..d691836 --- /dev/null +++ b/libdhcp/dhcp_common.c @@ -0,0 +1,104 @@ +/* libdhcp/dhcp_common.c - Base definitions for the DHCP protocol + * + * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include "dhcp_common.h" + +/** + * DHCP Options + * https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options + */ +bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) { + switch (opt) { + /* RFC 2132 */ + case DHCP_OPT_PAD: return len == 0; + case DHCP_OPT_SUBNET_MASK: return len == 4; + case DHCP_OPT_TIME_OFFSET: return len == 4; + case DHCP_OPT_ROUTER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_TIME_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_NAME_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_DOMAIN_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_LOG_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_QUOTES_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_LPR_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_IMPRESS_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_RLP_SERVER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_HOSTNAME: return len >= 1; + case DHCP_OPT_BOOT_FILE_SIZE: return len == 2; + case DHCP_OPT_MERIT_DUMP_FILE: return len >= 1; + case DHCP_OPT_DOMAIN_NAME: return len >= 1; + case DHCP_OPT_SWAP_SERVER: return len == 4; /* IANA says length is "N", but RFC 2132 says "length is 4"; likely releated to errata ID 487 */ + case DHCP_OPT_ROOT_PATH: return len >= 1; + case DHCP_OPT_EXTENSION_FILE: return len >= 1; + case DHCP_OPT_FORWARD_ONOFF: return len == 1; + case DHCP_OPT_SRCRTE_ONOFF: return len == 1; + case DHCP_OPT_POLICY_FILTER: return len >= 8 && len % 8 == 0; + case DHCP_OPT_MAX_DG_ASSEMBLY: return len == 2; + case DHCP_OPT_DEFAULT_IP_TTL: return len == 1; + case DHCP_OPT_MTU_TIMEOUT: return len == 4; + case DHCP_OPT_MTU_PLATEAU: return len >= 2 && len % 2 == 0; + case DHCP_OPT_MTU_INTERFACE: return len == 2; + case DHCP_OPT_MTU_SUBNET: return len == 1; + case DHCP_OPT_BROADCAST_ADDRESS: return len == 4; + case DHCP_OPT_MASK_DISCOVERY: return len == 1; + case DHCP_OPT_MASK_SUPPLIER: return len == 1; + case DHCP_OPT_ROUTER_DISCOVERY: return len == 1; + case DHCP_OPT_ROUTER_REQUEST: return len == 4; + case DHCP_OPT_STATIC_ROUTE: return len >= 8 && len % 8 == 0; + case DHCP_OPT_TRAILERS: return len == 1; + case DHCP_OPT_ARP_TIMEOUT: return len == 4; + case DHCP_OPT_ETHERNET: return len == 1; + case DHCP_OPT_DEFAULT_TCP_TTL: return len == 1; + case DHCP_OPT_KEEPALIVE_TIME: return len == 4; + case DHCP_OPT_KEEPALIVE_DATA: return len == 1; + case DHCP_OPT_NIS_DOMAIN: return len >= 1; + case DHCP_OPT_NIS_SERVERS: return len >= 4 && len % 4 == 0; + case DHCP_OPT_NTP_SERVERS: return len >= 4 && len % 4 == 0; + case DHCP_OPT_VENDOR_SPECIFIC: return len >= 1; + case DHCP_OPT_NETBIOS_NAME_SRV: return len >= 4 && len % 4 == 0; + case DHCP_OPT_NETBIOS_DIST_SRV: return len >= 4 && len % 4 == 0; + case DHCP_OPT_NETBIOS_NODE_TYPE: return len == 1; + case DHCP_OPT_NETBIOS_SCOPE: return len >= 1; + case DHCP_OPT_X_WINDOW_FONT: return len >= 4 && len % 4 == 0; + case DHCP_OPT_X_WINDOW_MANAGER: return len >= 4 && len % 4 == 0; + case DHCP_OPT_ADDRESS_REQUEST: return len == 4; + case DHCP_OPT_ADDRESS_TIME: return len == 4; + case DHCP_OPT_OVERLOAD: return len == 1; + case DHCP_OPT_DHCP_MSG_TYPE: return len == 1; + case DHCP_OPT_DHCP_SERVER_ID: return len == 4; + case DHCP_OPT_PARAMETER_LIST: return len >= 1; + case DHCP_OPT_DHCP_MESSAGE: return len >= 1; + case DHCP_OPT_DHCP_MAX_MSG_SIZE: return len == 2; + case DHCP_OPT_RENEWAL_TIME: return len == 4; + case DHCP_OPT_REBINDING_TIME: return len == 4; + case DHCP_OPT_CLASS_ID: return len >= 1; + case DHCP_OPT_CLIENT_ID: return len >= 2; + + /* RFC 2132 */ + case DHCP_OPT_END: return len == 0; + + /* Unrecognized */ + default: + return true; + } +} + +/** + * DHCP Message Type 53 Values + * https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#message-type-53 + */ +const char *dhcp_msgtyp_str(uint8_t typ) { + switch (typ) { + case DHCP_MSGTYP_DISCOVER: return "DHCP_MSGTYP_DISCOVER"; + case DHCP_MSGTYP_OFFER: return "DHCP_MSGTYP_OFFER"; + case DHCP_MSGTYP_REQUEST: return "DHCP_MSGTYP_REQUEST"; + case DHCP_MSGTYP_DECLINE: return "DHCP_MSGTYP_DECLINE"; + case DHCP_MSGTYP_ACK: return "DHCP_MSGTYP_ACK"; + case DHCP_MSGTYP_NAK: return "DHCP_MSGTYP_NAK"; + case DHCP_MSGTYP_RELEASE: return "DHCP_MSGTYP_RELEASE"; + case DHCP_MSGTYP_INFORM: return "DHCP_MSGTYP_INFORM"; + default: return const_byte_str(typ); + } +} diff --git a/libdhcp/dhcp_common.h b/libdhcp/dhcp_common.h index 5b51ce2..a0cdd3c 100644 --- a/libdhcp/dhcp_common.h +++ b/libdhcp/dhcp_common.h @@ -1,6 +1,6 @@ /* libdhcp/dhcp_common.h - Base definitions for the DHCP protocol * - * Copyright (C) 2024 Luke T. Shumaker <lukeshu@lukeshu.com> + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later * * ----------------------------------------------------------------------------- @@ -67,8 +67,9 @@ #ifndef _LIBDHCP_DHCP_COMMON_H_ #define _LIBDHCP_DHCP_COMMON_H_ -#include <libmisc/endian.h> -#include <libmisc/log.h> /* for const_byte_str() */ +#include <libhw/generic/net.h> /* for struct net_ip4_addr */ +#include <libmisc/endian.h> /* for uint{n}be_t */ +#include <libmisc/log.h> /* for const_byte_str() */ /* Config *********************************************************************/ @@ -215,80 +216,7 @@ static const uint8_t dhcp_magic_cookie[] = {99, 130, 83, 99}; /* ... */ #define DHCP_OPT_END ((uint8_t)255) /* RFC2132: length: 0; meaning: None */ -static inline bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) { - switch (opt) { - /* RFC 2132 */ - case DHCP_OPT_PAD: return len == 0; - case DHCP_OPT_SUBNET_MASK: return len == 4; - case DHCP_OPT_TIME_OFFSET: return len == 4; - case DHCP_OPT_ROUTER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_TIME_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_NAME_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_DOMAIN_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_LOG_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_QUOTES_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_LPR_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_IMPRESS_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_RLP_SERVER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_HOSTNAME: return len >= 1; - case DHCP_OPT_BOOT_FILE_SIZE: return len == 2; - case DHCP_OPT_MERIT_DUMP_FILE: return len >= 1; - case DHCP_OPT_DOMAIN_NAME: return len >= 1; - case DHCP_OPT_SWAP_SERVER: return len == 4; /* IANA says length is "N", but RFC 2132 says "length is 4"; likely releated to errata ID 487 */ - case DHCP_OPT_ROOT_PATH: return len >= 1; - case DHCP_OPT_EXTENSION_FILE: return len >= 1; - case DHCP_OPT_FORWARD_ONOFF: return len == 1; - case DHCP_OPT_SRCRTE_ONOFF: return len == 1; - case DHCP_OPT_POLICY_FILTER: return len >= 8 && len % 8 == 0; - case DHCP_OPT_MAX_DG_ASSEMBLY: return len == 2; - case DHCP_OPT_DEFAULT_IP_TTL: return len == 1; - case DHCP_OPT_MTU_TIMEOUT: return len == 4; - case DHCP_OPT_MTU_PLATEAU: return len >= 2 && len % 2 == 0; - case DHCP_OPT_MTU_INTERFACE: return len == 2; - case DHCP_OPT_MTU_SUBNET: return len == 1; - case DHCP_OPT_BROADCAST_ADDRESS: return len == 4; - case DHCP_OPT_MASK_DISCOVERY: return len == 1; - case DHCP_OPT_MASK_SUPPLIER: return len == 1; - case DHCP_OPT_ROUTER_DISCOVERY: return len == 1; - case DHCP_OPT_ROUTER_REQUEST: return len == 4; - case DHCP_OPT_STATIC_ROUTE: return len >= 8 && len % 8 == 0; - case DHCP_OPT_TRAILERS: return len == 1; - case DHCP_OPT_ARP_TIMEOUT: return len == 4; - case DHCP_OPT_ETHERNET: return len == 1; - case DHCP_OPT_DEFAULT_TCP_TTL: return len == 1; - case DHCP_OPT_KEEPALIVE_TIME: return len == 4; - case DHCP_OPT_KEEPALIVE_DATA: return len == 1; - case DHCP_OPT_NIS_DOMAIN: return len >= 1; - case DHCP_OPT_NIS_SERVERS: return len >= 4 && len % 4 == 0; - case DHCP_OPT_NTP_SERVERS: return len >= 4 && len % 4 == 0; - case DHCP_OPT_VENDOR_SPECIFIC: return len >= 1; - case DHCP_OPT_NETBIOS_NAME_SRV: return len >= 4 && len % 4 == 0; - case DHCP_OPT_NETBIOS_DIST_SRV: return len >= 4 && len % 4 == 0; - case DHCP_OPT_NETBIOS_NODE_TYPE: return len == 1; - case DHCP_OPT_NETBIOS_SCOPE: return len >= 1; - case DHCP_OPT_X_WINDOW_FONT: return len >= 4 && len % 4 == 0; - case DHCP_OPT_X_WINDOW_MANAGER: return len >= 4 && len % 4 == 0; - case DHCP_OPT_ADDRESS_REQUEST: return len == 4; - case DHCP_OPT_ADDRESS_TIME: return len == 4; - case DHCP_OPT_OVERLOAD: return len == 1; - case DHCP_OPT_DHCP_MSG_TYPE: return len == 1; - case DHCP_OPT_DHCP_SERVER_ID: return len == 4; - case DHCP_OPT_PARAMETER_LIST: return len >= 1; - case DHCP_OPT_DHCP_MESSAGE: return len >= 1; - case DHCP_OPT_DHCP_MAX_MSG_SIZE: return len == 2; - case DHCP_OPT_RENEWAL_TIME: return len == 4; - case DHCP_OPT_REBINDING_TIME: return len == 4; - case DHCP_OPT_CLASS_ID: return len >= 1; - case DHCP_OPT_CLIENT_ID: return len >= 2; - - /* RFC 2132 */ - case DHCP_OPT_END: return len == 0; - - /* Unrecognized */ - default: - return true; - } -}; +bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len); /** * DHCP Message Type 53 Values @@ -303,18 +231,6 @@ static inline bool dhcp_opt_length_is_valid(uint8_t opt, uint16_t len) { #define DHCP_MSGTYP_RELEASE ((uint8_t) 7) /* RFC2132, client->server */ #define DHCP_MSGTYP_INFORM ((uint8_t) 8) /* RFC2132, client->server */ -static const char *dhcp_msgtyp_str(uint8_t typ) { - switch (typ) { - case DHCP_MSGTYP_DISCOVER: return "DHCP_MSGTYP_DISCOVER"; - case DHCP_MSGTYP_OFFER: return "DHCP_MSGTYP_OFFER"; - case DHCP_MSGTYP_REQUEST: return "DHCP_MSGTYP_REQUEST"; - case DHCP_MSGTYP_DECLINE: return "DHCP_MSGTYP_DECLINE"; - case DHCP_MSGTYP_ACK: return "DHCP_MSGTYP_ACK"; - case DHCP_MSGTYP_NAK: return "DHCP_MSGTYP_NAK"; - case DHCP_MSGTYP_RELEASE: return "DHCP_MSGTYP_RELEASE"; - case DHCP_MSGTYP_INFORM: return "DHCP_MSGTYP_INFORM"; - default: return const_byte_str(typ); - } -} +const char *dhcp_msgtyp_str(uint8_t typ); #endif /* _LIBDHCP_DHCP_COMMON_H_ */ diff --git a/libhw_cr/CMakeLists.txt b/libhw_cr/CMakeLists.txt index ba20b26..9dd6a27 100644 --- a/libhw_cr/CMakeLists.txt +++ b/libhw_cr/CMakeLists.txt @@ -24,6 +24,7 @@ if (PICO_PLATFORM STREQUAL "rp2040") rp2040_hwspi.c rp2040_hwtimer.c w5500.c + w5500_ll.c ) target_link_libraries(libhw_cr INTERFACE hardware_gpio diff --git a/libhw_cr/host_util.c b/libhw_cr/host_util.c index 7b3200c..8cacd57 100644 --- a/libhw_cr/host_util.c +++ b/libhw_cr/host_util.c @@ -7,6 +7,8 @@ #include <error.h> /* for error(3gnu) */ #include <signal.h> /* for SIGRTMIN, SIGRTMAX */ +#include <libhw/generic/alarmclock.h> /* for {X}S_PER_S */ + #include "host_util.h" int host_sigrt_alloc(void) { @@ -19,3 +21,30 @@ int host_sigrt_alloc(void) { error(1, 0, "SIGRTMAX exceeded"); return ret; } + +host_us_time_t ns_to_host_us_time(uint64_t time_ns) { + host_us_time_t ret; + ret.tv_sec = time_ns + /NS_PER_S; + ret.tv_usec = (time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S) + /(NS_PER_S/US_PER_S); + return ret; +} + +host_ns_time_t ns_to_host_ns_time(uint64_t time_ns) { + host_ns_time_t ret; + ret.tv_sec = time_ns + /NS_PER_S; + ret.tv_nsec = time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S; + return ret; +} + +uint64_t ns_from_host_us_time(host_us_time_t host_time) { + return (((uint64_t)host_time.tv_sec) * NS_PER_S) + + ((uint64_t)host_time.tv_usec * (NS_PER_S/US_PER_S)); +} + +uint64_t ns_from_host_ns_time(host_ns_time_t host_time) { + return (((uint64_t)host_time.tv_sec) * NS_PER_S) + + ((uint64_t)host_time.tv_nsec); +} diff --git a/libhw_cr/host_util.h b/libhw_cr/host_util.h index 3f0a671..4adb94e 100644 --- a/libhw_cr/host_util.h +++ b/libhw_cr/host_util.h @@ -7,41 +7,18 @@ #ifndef _LIBHW_CR_HOST_UTIL_H_ #define _LIBHW_CR_HOST_UTIL_H_ +#include <stdint.h> /* for uint{n}_t */ #include <sys/time.h> /* for struct timeval */ #include <time.h> /* for struct timespec */ -#include <libhw/generic/alarmclock.h> /* for {X}S_PER_S */ - int host_sigrt_alloc(void); typedef struct timeval host_us_time_t; typedef struct timespec host_ns_time_t; -static inline host_us_time_t ns_to_host_us_time(uint64_t time_ns) { - host_us_time_t ret; - ret.tv_sec = time_ns - /NS_PER_S; - ret.tv_usec = (time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S) - /(NS_PER_S/US_PER_S); - return ret; -} - -static inline host_ns_time_t ns_to_host_ns_time(uint64_t time_ns) { - host_ns_time_t ret; - ret.tv_sec = time_ns - /NS_PER_S; - ret.tv_nsec = time_ns - ((uint64_t)ret.tv_sec)*NS_PER_S; - return ret; -} - -static inline uint64_t ns_from_host_us_time(host_us_time_t host_time) { - return (((uint64_t)host_time.tv_sec) * NS_PER_S) + - ((uint64_t)host_time.tv_usec * (NS_PER_S/US_PER_S)); -} - -static inline uint64_t ns_from_host_ns_time(host_ns_time_t host_time) { - return (((uint64_t)host_time.tv_sec) * NS_PER_S) + - ((uint64_t)host_time.tv_nsec); -} +host_us_time_t ns_to_host_us_time(uint64_t time_ns); +host_ns_time_t ns_to_host_ns_time(uint64_t time_ns); +uint64_t ns_from_host_us_time(host_us_time_t host_time); +uint64_t ns_from_host_ns_time(host_ns_time_t host_time); #endif /* _LIBHW_CR_HOST_UTIL_H_ */ diff --git a/libhw_cr/rp2040_dma.c b/libhw_cr/rp2040_dma.c index e117c19..8901f06 100644 --- a/libhw_cr/rp2040_dma.c +++ b/libhw_cr/rp2040_dma.c @@ -1,5 +1,8 @@ /* libhw_cr/rp2040_dma.c - Utilities for sharing the DMA IRQs * + * Copyright (c) 2020 Raspberry Pi (Trading) Ltd. + * SPDX-License-Identifier: BSD-3-Clause + * * Copyright (C) 2025 Luke T. Shumaker <lukeshu@lukeshu.com> * SPDX-License-Identifier: AGPL-3.0-or-later */ @@ -8,6 +11,21 @@ #include "rp2040_dma.h" +/* Borrowed from <hardware/dma.h> *********************************************/ + +dma_channel_hw_t *dma_channel_hw_addr(uint channel) { + assert(channel < NUM_DMA_CHANNELS); + return &dma_hw->ch[channel]; +} + +enum dma_channel_transfer_size { + DMA_SIZE_8 = 0, ///< Byte transfer (8 bits) + DMA_SIZE_16 = 1, ///< Half word transfer (16 bits) + DMA_SIZE_32 = 2 ///< Word transfer (32 bits) +}; + +/* Our own code ***************************************************************/ + struct dmairq_handler_entry { dmairq_handler_t fn; void *arg; diff --git a/libhw_cr/rp2040_dma.h b/libhw_cr/rp2040_dma.h index e8bceec..5c1c7bb 100644 --- a/libhw_cr/rp2040_dma.h +++ b/libhw_cr/rp2040_dma.h @@ -21,10 +21,7 @@ /* Borrowed from <hardware/dma.h> *********************************************/ -static inline dma_channel_hw_t *dma_channel_hw_addr(uint channel) { - assert(channel < NUM_DMA_CHANNELS); - return &dma_hw->ch[channel]; -} +dma_channel_hw_t *dma_channel_hw_addr(uint channel); enum dma_channel_transfer_size { DMA_SIZE_8 = 0, ///< Byte transfer (8 bits) diff --git a/libhw_cr/w5500_ll.c b/libhw_cr/w5500_ll.c new file mode 100644 index 0000000..d9f4fc5 --- /dev/null +++ b/libhw_cr/w5500_ll.c @@ -0,0 +1,105 @@ +/* libhw_cr/w5500_ll.c - Low-level library for the WIZnet W5500 chip + * + * Based entirely on the W5500 datasheet, v1.1.0. + * https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/alloc.h> /* for stack_alloc() */ +#include <libmisc/fmt.h> + +#include "w5500_ll.h" + +#if CONFIG_W5500_LL_DEBUG +static void fmt_print_ctl_block(lo_interface fmt_dest, uint8_t b) { + static char *strs[] = { + "RES", + "REG", + "TX", + "RX", + }; + fmt_print("CTL_BLOCK_SOCK(", (base10, (((b)>>5) & 0b111)), ", ", strs[((b)>>3)&0b11], ")"); +} +#endif + +void +#if CONFIG_W5500_LL_DEBUG +_w5500ll_writev(const char *func, +#else +w5500ll_writev( +#endif + lo_interface spi spidev, uint16_t addr, uint8_t block, + const struct iovec *iov, int iovcnt, + size_t skip, size_t max) +{ + assert(!LO_IS_NULL(spidev)); + assert((block & ~CTL_MASK_BLOCK) == 0); + assert(iov); + assert(iovcnt > 0); +#if CONFIG_W5500_LL_DEBUG + log_n_debugln(W5500_LL, + func, "(): w5500ll_write(spidev", + ", addr=", (base16_u16_, addr), + ", block=", (ctl_block, block), + ", iov", + ", iovcnt=", iovcnt, + ")"); +#endif + + uint8_t header[] = { + (uint8_t)((addr >> 8) & 0xFF), + (uint8_t)(addr & 0xFF), + (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM, + }; + int inner_cnt = 1+io_slice_cnt(iov, iovcnt, skip, max); + struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); + inner[0] = (struct duplex_iovec){ + .iov_read_to = IOVEC_DISCARD, + .iov_write_from = header, + .iov_len = sizeof(header), + }; + io_slice_wr_to_duplex(&inner[1], iov, iovcnt, skip, max); + LO_CALL(spidev, readwritev, inner, inner_cnt); +} + +void +#if CONFIG_W5500_LL_DEBUG +_w5500ll_readv(const char *func, +#else +w5500ll_readv( +#endif + lo_interface spi spidev, uint16_t addr, uint8_t block, + const struct iovec *iov, int iovcnt, + size_t max) +{ + assert(!LO_IS_NULL(spidev)); + assert((block & ~CTL_MASK_BLOCK) == 0); + assert(iov); + assert(iovcnt > 0); +#if CONFIG_W5500_LL_DEBUG + log_n_debugln(W5500_LL, + func, "(): w5500ll_read(spidev", + ", addr=", (base16_u16_, addr), + ", block=", (ctl_block, block), + ", iov", + ", iovcnt=", iovcnt, + ")"); +#endif + + uint8_t header[] = { + (uint8_t)((addr >> 8) & 0xFF), + (uint8_t)(addr & 0xFF), + (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM, + }; + int inner_cnt = 1+io_slice_cnt(iov, iovcnt, 0, max); + struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); + inner[0] = (struct duplex_iovec){ + .iov_read_to = IOVEC_DISCARD, + .iov_write_from = header, + .iov_len = sizeof(header), + }; + io_slice_rd_to_duplex(&inner[1], iov, iovcnt, 0, max); + LO_CALL(spidev, readwritev, inner, inner_cnt); +} diff --git a/libhw_cr/w5500_ll.h b/libhw_cr/w5500_ll.h index aa41e7a..eeb2fb7 100644 --- a/libhw_cr/w5500_ll.h +++ b/libhw_cr/w5500_ll.h @@ -1,4 +1,4 @@ -/* libhw_cr/w5500_ll.h - Low-level header library for the WIZnet W5500 chip +/* libhw_cr/w5500_ll.h - Low-level library for the WIZnet W5500 chip * * Based entirely on the W5500 datasheet, v1.1.0. * https://docs.wiznet.io/img/products/w5500/W5500_ds_v110e.pdf @@ -13,8 +13,7 @@ #include <stdint.h> /* for uint{n}_t */ #include <string.h> /* for memcmp() */ -#include <libmisc/alloc.h> /* for stack_alloc() */ -#include <libmisc/assert.h> /* for assert(), static_assert() */ +#include <libmisc/assert.h> /* for static_assert() */ #include <libmisc/endian.h> /* for uint16be_t */ #include <libhw/generic/net.h> /* for struct net_eth_addr, struct net_ip4_addr */ @@ -53,102 +52,28 @@ #define CTL_OM_FDM2 0b10 /* fixed-length data mode: 2 byte data length */ #define CTL_OM_FDM4 0b11 /* fixed-length data mode: 4 byte data length */ -#if CONFIG_W5500_LL_DEBUG -static void fmt_print_ctl_block(lo_interface fmt_dest, uint8_t b) { - static char *strs[] = { - "RES", - "REG", - "TX", - "RX", - }; - fmt_print("CTL_BLOCK_SOCK(", (base10, (((b)>>5) & 0b111)), ", ", strs[((b)>>3)&0b11], ")"); -} -#endif - /* Even though SPI is a full-duplex protocol, the W5500's spiframe on top of it is only half-duplex. * Lame. */ -static inline void #if CONFIG_W5500_LL_DEBUG #define w5500ll_writev(...) _w5500ll_writev(__func__, __VA_ARGS__) -_w5500ll_writev(const char *func, +void _w5500ll_writev(const char *func, #else -w5500ll_writev( +void w5500ll_writev( #endif lo_interface spi spidev, uint16_t addr, uint8_t block, const struct iovec *iov, int iovcnt, - size_t skip, size_t max) -{ - assert(!LO_IS_NULL(spidev)); - assert((block & ~CTL_MASK_BLOCK) == 0); - assert(iov); - assert(iovcnt > 0); -#if CONFIG_W5500_LL_DEBUG - log_n_debugln(W5500_LL, - func, "(): w5500ll_write(spidev", - ", addr=", (base16_u16_, addr), - ", block=", (ctl_block, block), - ", iov", - ", iovcnt=", iovcnt, - ")"); -#endif + size_t skip, size_t max); - uint8_t header[] = { - (uint8_t)((addr >> 8) & 0xFF), - (uint8_t)(addr & 0xFF), - (block & CTL_MASK_BLOCK) | CTL_W | CTL_OM_VDM, - }; - int inner_cnt = 1+io_slice_cnt(iov, iovcnt, skip, max); - struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); - inner[0] = (struct duplex_iovec){ - .iov_read_to = IOVEC_DISCARD, - .iov_write_from = header, - .iov_len = sizeof(header), - }; - io_slice_wr_to_duplex(&inner[1], iov, iovcnt, skip, max); - LO_CALL(spidev, readwritev, inner, inner_cnt); -} - -static inline void #if CONFIG_W5500_LL_DEBUG #define w5500ll_readv(...) _w5500ll_read(__func__, __VA_ARGS__) -_w5500ll_readv(const char *func, +void _w5500ll_readv(const char *func, #else -w5500ll_readv( +void w5500ll_readv( #endif lo_interface spi spidev, uint16_t addr, uint8_t block, const struct iovec *iov, int iovcnt, - size_t max) -{ - assert(!LO_IS_NULL(spidev)); - assert((block & ~CTL_MASK_BLOCK) == 0); - assert(iov); - assert(iovcnt > 0); -#if CONFIG_W5500_LL_DEBUG - log_n_debugln(W5500_LL, - func, "(): w5500ll_read(spidev", - ", addr=", (base16_u16_, addr), - ", block=", (ctl_block, block), - ", iov", - ", iovcnt=", iovcnt, - ")"); -#endif - - uint8_t header[] = { - (uint8_t)((addr >> 8) & 0xFF), - (uint8_t)(addr & 0xFF), - (block & CTL_MASK_BLOCK) | CTL_R | CTL_OM_VDM, - }; - int inner_cnt = 1+io_slice_cnt(iov, iovcnt, 0, max); - struct duplex_iovec *inner = stack_alloc(inner_cnt, struct duplex_iovec); - inner[0] = (struct duplex_iovec){ - .iov_read_to = IOVEC_DISCARD, - .iov_write_from = header, - .iov_len = sizeof(header), - }; - io_slice_rd_to_duplex(&inner[1], iov, iovcnt, 0, max); - LO_CALL(spidev, readwritev, inner, inner_cnt); -} + size_t max); /* Common chip-wide registers. ***********************************************/ diff --git a/libhw_generic/alarmclock.c b/libhw_generic/alarmclock.c index e3aaea3..3579829 100644 --- a/libhw_generic/alarmclock.c +++ b/libhw_generic/alarmclock.c @@ -7,3 +7,19 @@ #include <libhw/generic/alarmclock.h> lo_interface alarmclock bootclock = {}; + +void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns) { + alarmclock_sleep_until_ns(clock, LO_CALL(clock, get_time_ns) + delta_ns); +} + +void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us) { + alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S)); +} + +void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms) { + alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S)); +} + +void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s) { + alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S); +} diff --git a/libhw_generic/include/libhw/generic/alarmclock.h b/libhw_generic/include/libhw/generic/alarmclock.h index 7f603cb..697d4be 100644 --- a/libhw_generic/include/libhw/generic/alarmclock.h +++ b/libhw_generic/include/libhw/generic/alarmclock.h @@ -62,21 +62,10 @@ LO_INTERFACE(alarmclock); void alarmclock_sleep_until_ns(lo_interface alarmclock clock, uint64_t abstime_ns); -static inline void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns) { - alarmclock_sleep_until_ns(clock, LO_CALL(clock, get_time_ns) + delta_ns); -} - -static inline void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us) { - alarmclock_sleep_for_ns(clock, delta_us * (NS_PER_S/US_PER_S)); -} - -static inline void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms) { - alarmclock_sleep_for_ns(clock, delta_ms * (NS_PER_S/MS_PER_S)); -} - -static inline void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s) { - alarmclock_sleep_for_ns(clock, delta_s * NS_PER_S); -} +void alarmclock_sleep_for_ns(lo_interface alarmclock clock, uint64_t delta_ns); +void alarmclock_sleep_for_us(lo_interface alarmclock clock, uint64_t delta_us); +void alarmclock_sleep_for_ms(lo_interface alarmclock clock, uint64_t delta_ms); +void alarmclock_sleep_for_s(lo_interface alarmclock clock, uint64_t delta_s); /* Globals ********************************************************************/ diff --git a/libmisc/CMakeLists.txt b/libmisc/CMakeLists.txt index 48407bd..c6405ad 100644 --- a/libmisc/CMakeLists.txt +++ b/libmisc/CMakeLists.txt @@ -7,11 +7,15 @@ add_library(libmisc INTERFACE) target_include_directories(libmisc PUBLIC INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include) target_sources(libmisc INTERFACE assert.c + endian.c fmt.c + hash.c intercept.c linkedlist.c log.c map.c + rand.c + utf8.c ) add_lib_test(libmisc test_assert) diff --git a/libmisc/endian.c b/libmisc/endian.c new file mode 100644 index 0000000..2528f48 --- /dev/null +++ b/libmisc/endian.c @@ -0,0 +1,136 @@ +/* libmisc/endian.c - Endian-conversion helpers + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/macro.h> /* for LM_FORCE_SEMICOLON */ + +#include <libmisc/endian.h> + +#define endian_declare_wrappers(NBIT, ENDIAN) \ + uint##NBIT##ENDIAN##_t uint##NBIT##ENDIAN##_marshal(uint##NBIT##_t in) { \ + uint##NBIT##ENDIAN##_t out; \ + uint##NBIT##ENDIAN##_encode(out.octets, in); \ + return out; \ + } \ + uint##NBIT##_t uint##NBIT##ENDIAN##_unmarshal(uint##NBIT##ENDIAN##_t in) { \ + return uint##NBIT##ENDIAN##_decode(in.octets); \ + } \ + LM_FORCE_SEMICOLON + +/* Big endian *****************************************************************/ + +size_t uint16be_encode(uint8_t *out, uint16_t in) { + out[0] = (uint8_t)((in >> 8) & 0xFF); + out[1] = (uint8_t)((in >> 0) & 0xFF); + return 2; +} + +uint16_t uint16be_decode(uint8_t *in) { + return (((uint16_t)(in[0])) << 8) + | (((uint16_t)(in[1])) << 0) + ; +} + +size_t uint32be_encode(uint8_t *out, uint32_t in) { + out[0] = (uint8_t)((in >> 24) & 0xFF); + out[1] = (uint8_t)((in >> 16) & 0xFF); + out[2] = (uint8_t)((in >> 8) & 0xFF); + out[3] = (uint8_t)((in >> 0) & 0xFF); + return 4; +} + +uint32_t uint32be_decode(uint8_t *in) { + return (((uint32_t)(in[0])) << 24) + | (((uint32_t)(in[1])) << 16) + | (((uint32_t)(in[2])) << 8) + | (((uint32_t)(in[3])) << 0) + ; +} + +size_t uint64be_encode(uint8_t *out, uint64_t in) { + out[0] = (uint8_t)((in >> 56) & 0xFF); + out[1] = (uint8_t)((in >> 48) & 0xFF); + out[2] = (uint8_t)((in >> 40) & 0xFF); + out[3] = (uint8_t)((in >> 32) & 0xFF); + out[4] = (uint8_t)((in >> 24) & 0xFF); + out[5] = (uint8_t)((in >> 16) & 0xFF); + out[6] = (uint8_t)((in >> 8) & 0xFF); + out[7] = (uint8_t)((in >> 0) & 0xFF); + return 8; +} + +uint64_t uint64be_decode(uint8_t *in) { + return (((uint64_t)(in[0])) << 56) + | (((uint64_t)(in[1])) << 48) + | (((uint64_t)(in[2])) << 40) + | (((uint64_t)(in[3])) << 32) + | (((uint64_t)(in[4])) << 24) + | (((uint64_t)(in[5])) << 16) + | (((uint64_t)(in[6])) << 8) + | (((uint64_t)(in[7])) << 0) + ; +} + +endian_declare_wrappers(16, be); +endian_declare_wrappers(32, be); +endian_declare_wrappers(64, be); + +/* Little endian **************************************************************/ + +size_t uint16le_encode(uint8_t *out, uint16_t in) { + out[0] = (uint8_t)((in >> 0) & 0xFF); + out[1] = (uint8_t)((in >> 8) & 0xFF); + return 2; +} + +uint16_t uint16le_decode(uint8_t *in) { + return (((uint16_t)(in[0])) << 0) + | (((uint16_t)(in[1])) << 8) + ; +} + +size_t uint32le_encode(uint8_t *out, uint32_t in) { + out[0] = (uint8_t)((in >> 0) & 0xFF); + out[1] = (uint8_t)((in >> 8) & 0xFF); + out[2] = (uint8_t)((in >> 16) & 0xFF); + out[3] = (uint8_t)((in >> 24) & 0xFF); + return 4; +} + +uint32_t uint32le_decode(uint8_t *in) { + return (((uint32_t)(in[0])) << 0) + | (((uint32_t)(in[1])) << 8) + | (((uint32_t)(in[2])) << 16) + | (((uint32_t)(in[3])) << 24) + ; +} + +size_t uint64le_encode(uint8_t *out, uint64_t in) { + out[0] = (uint8_t)((in >> 0) & 0xFF); + out[1] = (uint8_t)((in >> 8) & 0xFF); + out[2] = (uint8_t)((in >> 16) & 0xFF); + out[3] = (uint8_t)((in >> 24) & 0xFF); + out[4] = (uint8_t)((in >> 32) & 0xFF); + out[5] = (uint8_t)((in >> 40) & 0xFF); + out[6] = (uint8_t)((in >> 48) & 0xFF); + out[7] = (uint8_t)((in >> 56) & 0xFF); + return 8; +} + +uint64_t uint64le_decode(uint8_t *in) { + return (((uint64_t)(in[0])) << 0) + | (((uint64_t)(in[1])) << 8) + | (((uint64_t)(in[2])) << 16) + | (((uint64_t)(in[3])) << 24) + | (((uint64_t)(in[4])) << 32) + | (((uint64_t)(in[5])) << 40) + | (((uint64_t)(in[6])) << 48) + | (((uint64_t)(in[7])) << 56) + ; +} + +endian_declare_wrappers(16, le); +endian_declare_wrappers(32, le); +endian_declare_wrappers(64, le); diff --git a/libmisc/fmt.c b/libmisc/fmt.c index 6cf1d8d..d3ca14a 100644 --- a/libmisc/fmt.c +++ b/libmisc/fmt.c @@ -14,6 +14,20 @@ static const char *const hexdig = "0123456789ABCDEF"; /* small/trivial formatters ***************************************************/ +void fmt_print_mem(lo_interface fmt_dest w, const void *_str, size_t size) { + const uint8_t *str = _str; + while (size--) + fmt_print_byte(w, *(str++)); +} +void fmt_print_str(lo_interface fmt_dest w, const char *str) { + while (*str) + fmt_print_byte(w, *(str++)); +} +void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size) { + while (size-- && *str) + fmt_print_byte(w, *(str++)); +} + void fmt_print_byte(lo_interface fmt_dest w, uint8_t b) { LO_CALL(w, putb, b); } diff --git a/libmisc/hash.c b/libmisc/hash.c new file mode 100644 index 0000000..3814cec --- /dev/null +++ b/libmisc/hash.c @@ -0,0 +1,24 @@ +/* libmisc/hash.c - General-purpose hash utilities + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/hash.h> + +/* djb2 hash */ +void hash_init(hash_t *hash) { + *hash = 5381; +} +void hash_write(hash_t *hash, void *dat, size_t len) { + for (size_t i = 0; i < len; i++) + *hash = (*hash * 33) + (hash_t)(((unsigned char *)dat)[i]); +} + +/* utilities */ +hash_t hash(void *dat, size_t len) { + hash_t h; + hash_init(&h); + hash_write(&h, dat, len); + return h; +} diff --git a/libmisc/include/libmisc/endian.h b/libmisc/include/libmisc/endian.h index 75240fe..966c3bc 100644 --- a/libmisc/include/libmisc/endian.h +++ b/libmisc/include/libmisc/endian.h @@ -10,204 +10,25 @@ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for uint{n}_t */ -#include <libmisc/assert.h> - -/* Big endian *****************************************************************/ - -typedef struct { - uint8_t octets[2]; -} uint16be_t; -static_assert(sizeof(uint16be_t) == 2); - -static inline size_t uint16be_encode(uint8_t *out, uint16_t in) { - out[0] = (uint8_t)((in >> 8) & 0xFF); - out[1] = (uint8_t)((in >> 0) & 0xFF); - return 2; -} - -static inline uint16_t uint16be_decode(uint8_t *in) { - return (((uint16_t)(in[0])) << 8) - | (((uint16_t)(in[1])) << 0) - ; -} - -static inline uint16be_t uint16be_marshal(uint16_t in) { - uint16be_t out; - uint16be_encode(out.octets, in); - return out; -} - -static inline uint16_t uint16be_unmarshal(uint16be_t in) { - return uint16be_decode(in.octets); -} - -typedef struct { - uint8_t octets[4]; -} uint32be_t; -static_assert(sizeof(uint32be_t) == 4); - -static inline size_t uint32be_encode(uint8_t *out, uint32_t in) { - out[0] = (uint8_t)((in >> 24) & 0xFF); - out[1] = (uint8_t)((in >> 16) & 0xFF); - out[2] = (uint8_t)((in >> 8) & 0xFF); - out[3] = (uint8_t)((in >> 0) & 0xFF); - return 4; -} - -static inline uint32_t uint32be_decode(uint8_t *in) { - return (((uint32_t)(in[0])) << 24) - | (((uint32_t)(in[1])) << 16) - | (((uint32_t)(in[2])) << 8) - | (((uint32_t)(in[3])) << 0) - ; -} - -static inline uint32be_t uint32be_marshal(uint32_t in) { - uint32be_t out; - uint32be_encode(out.octets, in); - return out; -} - -static inline uint32_t uint32be_unmarshal(uint32be_t in) { - return uint32be_decode(in.octets); -} - -typedef struct { - uint8_t octets[8]; -} uint64be_t; -static_assert(sizeof(uint64be_t) == 8); - -static inline size_t uint64be_encode(uint8_t *out, uint64_t in) { - out[0] = (uint8_t)((in >> 56) & 0xFF); - out[1] = (uint8_t)((in >> 48) & 0xFF); - out[2] = (uint8_t)((in >> 40) & 0xFF); - out[3] = (uint8_t)((in >> 32) & 0xFF); - out[4] = (uint8_t)((in >> 24) & 0xFF); - out[5] = (uint8_t)((in >> 16) & 0xFF); - out[6] = (uint8_t)((in >> 8) & 0xFF); - out[7] = (uint8_t)((in >> 0) & 0xFF); - return 8; -} - -static inline uint64_t uint64be_decode(uint8_t *in) { - return (((uint64_t)(in[0])) << 56) - | (((uint64_t)(in[1])) << 48) - | (((uint64_t)(in[2])) << 40) - | (((uint64_t)(in[3])) << 32) - | (((uint64_t)(in[4])) << 24) - | (((uint64_t)(in[5])) << 16) - | (((uint64_t)(in[6])) << 8) - | (((uint64_t)(in[7])) << 0) - ; -} - -static inline uint64be_t uint64be_marshal(uint64_t in) { - uint64be_t out; - uint64be_encode(out.octets, in); - return out; -} - -static inline uint64_t uint64be_unmarshal(uint64be_t in) { - return uint64be_decode(in.octets); -} - -/* Little endian **************************************************************/ - -typedef struct { - uint8_t octets[2]; -} uint16le_t; -static_assert(sizeof(uint16le_t) == 2); - -static inline size_t uint16le_encode(uint8_t *out, uint16_t in) { - out[0] = (uint8_t)((in >> 0) & 0xFF); - out[1] = (uint8_t)((in >> 8) & 0xFF); - return 2; -} - -static inline uint16_t uint16le_decode(uint8_t *in) { - return (((uint16_t)(in[0])) << 0) - | (((uint16_t)(in[1])) << 8) - ; -} - -static inline uint16le_t uint16le_marshal(uint16_t in) { - uint16le_t out; - uint16le_encode(out.octets, in); - return out; -} - -static inline uint16_t uint16le_unmarshal(uint16le_t in) { - return uint16le_decode(in.octets); -} - -typedef struct { - uint8_t octets[4]; -} uint32le_t; -static_assert(sizeof(uint32le_t) == 4); - -static inline size_t uint32le_encode(uint8_t *out, uint32_t in) { - out[0] = (uint8_t)((in >> 0) & 0xFF); - out[1] = (uint8_t)((in >> 8) & 0xFF); - out[2] = (uint8_t)((in >> 16) & 0xFF); - out[3] = (uint8_t)((in >> 24) & 0xFF); - return 4; -} - -static inline uint32_t uint32le_decode(uint8_t *in) { - return (((uint32_t)(in[0])) << 0) - | (((uint32_t)(in[1])) << 8) - | (((uint32_t)(in[2])) << 16) - | (((uint32_t)(in[3])) << 24) - ; -} - -static inline uint32le_t uint32le_marshal(uint32_t in) { - uint32le_t out; - uint32le_encode(out.octets, in); - return out; -} - -static inline uint32_t uint32le_unmarshal(uint32le_t in) { - return uint32le_decode(in.octets); -} - -typedef struct { - uint8_t octets[8]; -} uint64le_t; -static_assert(sizeof(uint64le_t) == 8); - -static inline size_t uint64le_encode(uint8_t *out, uint64_t in) { - out[0] = (uint8_t)((in >> 0) & 0xFF); - out[1] = (uint8_t)((in >> 8) & 0xFF); - out[2] = (uint8_t)((in >> 16) & 0xFF); - out[3] = (uint8_t)((in >> 24) & 0xFF); - out[4] = (uint8_t)((in >> 32) & 0xFF); - out[5] = (uint8_t)((in >> 40) & 0xFF); - out[6] = (uint8_t)((in >> 48) & 0xFF); - out[7] = (uint8_t)((in >> 56) & 0xFF); - return 8; -} - -static inline uint64_t uint64le_decode(uint8_t *in) { - return (((uint64_t)(in[0])) << 0) - | (((uint64_t)(in[1])) << 8) - | (((uint64_t)(in[2])) << 16) - | (((uint64_t)(in[3])) << 24) - | (((uint64_t)(in[4])) << 32) - | (((uint64_t)(in[5])) << 40) - | (((uint64_t)(in[6])) << 48) - | (((uint64_t)(in[7])) << 56) - ; -} - -static inline uint64le_t uint64le_marshal(uint64_t in) { - uint64le_t out; - uint64le_encode(out.octets, in); - return out; -} - -static inline uint64_t uint64le_unmarshal(uint64le_t in) { - return uint64le_decode(in.octets); -} +#define _endian_declare_conv(NBIT, ENDIAN) \ + /* byte array encode/decode */ \ + size_t uint##NBIT##ENDIAN##_encode(uint8_t *out, uint##NBIT##_t in); \ + uint##NBIT##_t uint##NBIT##ENDIAN##_decode(uint8_t *in); \ + /* struct marshal/unmarshal */ \ + typedef struct { \ + uint8_t octets[NBIT/8]; \ + } uint##NBIT##ENDIAN##_t; \ + uint##NBIT##ENDIAN##_t uint##NBIT##ENDIAN##_marshal(uint##NBIT##_t in); \ + uint##NBIT##_t uint##NBIT##ENDIAN##_unmarshal(uint##NBIT##ENDIAN##_t in) + +_endian_declare_conv(16, be); +_endian_declare_conv(32, be); +_endian_declare_conv(64, be); + +_endian_declare_conv(16, le); +_endian_declare_conv(32, le); +_endian_declare_conv(64, le); + +#undef _endian_declare_conv #endif /* _LIBMISC_ENDIAN_H_ */ diff --git a/libmisc/include/libmisc/fmt.h b/libmisc/include/libmisc/fmt.h index c29c085..4abe730 100644 --- a/libmisc/include/libmisc/fmt.h +++ b/libmisc/include/libmisc/fmt.h @@ -24,21 +24,9 @@ LO_INTERFACE(fmt_dest); /* Simple bytes. */ void fmt_print_byte(lo_interface fmt_dest w, uint8_t b); - -/* These are `static inline` so that the compiler can unroll the loops. */ -static inline void fmt_print_mem(lo_interface fmt_dest w, const void *_str, size_t size) { - const uint8_t *str = _str; - while (size--) - fmt_print_byte(w, *(str++)); -} -static inline void fmt_print_str(lo_interface fmt_dest w, const char *str) { - while (*str) - fmt_print_byte(w, *(str++)); -} -static inline void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size) { - while (size-- && *str) - fmt_print_byte(w, *(str++)); -} +void fmt_print_mem(lo_interface fmt_dest w, const void *str, size_t size); +void fmt_print_str(lo_interface fmt_dest w, const char *str); +void fmt_print_strn(lo_interface fmt_dest w, const char *str, size_t size); /* Quoted bytes. */ void fmt_print_qbyte(lo_interface fmt_dest w, uint8_t b); diff --git a/libmisc/include/libmisc/hash.h b/libmisc/include/libmisc/hash.h index 58a895f..029bd3b 100644 --- a/libmisc/include/libmisc/hash.h +++ b/libmisc/include/libmisc/hash.h @@ -10,22 +10,12 @@ #include <stddef.h> /* for size_t */ #include <stdint.h> /* for uint{n}_t */ -/* djb2 hash */ -typedef uint32_t hash_t; -static inline void hash_init(hash_t *hash) { - *hash = 5381; -} -static inline void hash_write(hash_t *hash, void *dat, size_t len) { - for (size_t i = 0; i < len; i++) - *hash = (*hash * 33) + (hash_t)(((unsigned char *)dat)[i]); -} +/* base */ +typedef uint32_t hash_t; /* size subject to change */ +void hash_init(hash_t *hash); +void hash_write(hash_t *hash, void *dat, size_t len); /* utilities */ -static inline hash_t hash(void *dat, size_t len) { - hash_t h; - hash_init(&h); - hash_write(&h, dat, len); - return h; -} +hash_t hash(void *dat, size_t len); #endif /* _LIBMISC_HASH_H_ */ diff --git a/libmisc/include/libmisc/rand.h b/libmisc/include/libmisc/rand.h index 7ef238b..ca16f42 100644 --- a/libmisc/include/libmisc/rand.h +++ b/libmisc/include/libmisc/rand.h @@ -7,40 +7,12 @@ #ifndef _LIBMISC_RAND_H_ #define _LIBMISC_RAND_H_ -#include <stdint.h> /* for uint{n}_t, UINT{n}_C() */ -#include <stdlib.h> /* for random() */ - -#include <libmisc/assert.h> +#include <stdint.h> /* for uint{n}_t */ /** * Return a psuedo-random number in the half-open interval [0,cnt). * `cnt` must not be greater than 1<<63. */ -static inline uint64_t rand_uint63n(uint64_t cnt) { - assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0); - if (cnt <= UINT64_C(1)<<31) { - uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt; - uint32_t rnd; - do { - rnd = random(); - } while (rnd >= fair_cnt); - return rnd % cnt; - } else if (cnt <= UINT64_C(1)<<62) { - uint64_t fair_cnt = ((UINT64_C(1)<<62) / cnt) * cnt; - uint64_t rnd; - do { - rnd = (((uint64_t)random()) << 31) | random(); - } while (rnd >= fair_cnt); - return rnd % cnt; - } else if (cnt <= UINT64_C(1)<<63) { - uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt; - uint64_t rnd; - do { - rnd = (((uint64_t)random()) << 62) | (((uint64_t)random()) << 31) | random(); - } while (rnd >= fair_cnt); - return rnd % cnt; - } - assert_notreached("cnt is out of bounds"); -} +uint64_t rand_uint63n(uint64_t cnt); #endif /* _LIBMISC_RAND_H_ */ diff --git a/libmisc/include/libmisc/utf8.h b/libmisc/include/libmisc/utf8.h index b5e1b0b..54fcc92 100644 --- a/libmisc/include/libmisc/utf8.h +++ b/libmisc/include/libmisc/utf8.h @@ -15,38 +15,9 @@ * bytes. Invalid UTF-8 is indicated with chlen=0. For valid UTF-8, * chlen is always in the range [1, 4]. */ -static inline void utf8_decode_codepoint(const uint8_t *str, size_t len, uint32_t *ret_ch, uint8_t *ret_chlen) { - uint32_t ch; - uint8_t chlen; - if ((str[0] & 0b10000000) == 0b00000000) { ch = str[0] & 0b01111111; chlen = 1; } - else if ((str[0] & 0b11100000) == 0b11000000) { ch = str[0] & 0b00011111; chlen = 2; } - else if ((str[0] & 0b11110000) == 0b11100000) { ch = str[0] & 0b00001111; chlen = 3; } - else if ((str[0] & 0b11111000) == 0b11110000) { ch = str[0] & 0b00000111; chlen = 4; } - else goto invalid; - if ((ch == 0 && chlen != 1) || chlen > len) goto invalid; - for (uint8_t i = 1; i < chlen; i++) { - if ((str[i] & 0b11000000) != 0b10000000) goto invalid; - ch = (ch << 6) | (str[i] & 0b00111111); - } - if (ch > 0x10FFFF) goto invalid; - *ret_ch = ch; - *ret_chlen = chlen; - return; - invalid: - *ret_chlen = 0; -} +void utf8_decode_codepoint(const uint8_t *str, size_t len, uint32_t *ret_ch, uint8_t *ret_chlen); -static inline bool _utf8_is_valid(const uint8_t *str, size_t len, bool forbid_nul) { - for (size_t pos = 0; pos < len;) { - uint32_t ch; - uint8_t chlen; - utf8_decode_codepoint(&str[pos], len-pos, &ch, &chlen); - if (chlen == 0 || (forbid_nul && ch == 0)) - return false; - pos += chlen; - } - return true; -} +bool _utf8_is_valid(const uint8_t *str, size_t len, bool forbid_nul); #define utf8_is_valid(str, len) _utf8_is_valid(str, len, false) #define utf8_is_valid_without_nul(str, len) _utf8_is_valid(str, len, true) diff --git a/libmisc/rand.c b/libmisc/rand.c new file mode 100644 index 0000000..d1643ee --- /dev/null +++ b/libmisc/rand.c @@ -0,0 +1,38 @@ +/* libmisc/rand.c - Non-crytpographic random-number utilities + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <stdlib.h> /* for random() */ + +#include <libmisc/assert.h> + +#include <libmisc/rand.h> + +uint64_t rand_uint63n(uint64_t cnt) { + assert(cnt != 0 && ((cnt-1) & 0x8000000000000000) == 0); + if (cnt <= UINT64_C(1)<<31) { + uint32_t fair_cnt = ((UINT32_C(1)<<31) / cnt) * cnt; + uint32_t rnd; + do { + rnd = random(); + } while (rnd >= fair_cnt); + return rnd % cnt; + } else if (cnt <= UINT64_C(1)<<62) { + uint64_t fair_cnt = ((UINT64_C(1)<<62) / cnt) * cnt; + uint64_t rnd; + do { + rnd = (((uint64_t)random()) << 31) | random(); + } while (rnd >= fair_cnt); + return rnd % cnt; + } else if (cnt <= UINT64_C(1)<<63) { + uint64_t fair_cnt = ((UINT64_C(1)<<63) / cnt) * cnt; + uint64_t rnd; + do { + rnd = (((uint64_t)random()) << 62) | (((uint64_t)random()) << 31) | random(); + } while (rnd >= fair_cnt); + return rnd % cnt; + } + assert_notreached("cnt is out of bounds"); +} diff --git a/libmisc/utf8.c b/libmisc/utf8.c new file mode 100644 index 0000000..5f91021 --- /dev/null +++ b/libmisc/utf8.c @@ -0,0 +1,40 @@ +/* libmisc/utf8.c - UTF-8 routines + * + * Copyright (C) 2024-2025 Luke T. Shumaker <lukeshu@lukeshu.com> + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include <libmisc/utf8.h> + +void utf8_decode_codepoint(const uint8_t *str, size_t len, uint32_t *ret_ch, uint8_t *ret_chlen) { + uint32_t ch; + uint8_t chlen; + if ((str[0] & 0b10000000) == 0b00000000) { ch = str[0] & 0b01111111; chlen = 1; } + else if ((str[0] & 0b11100000) == 0b11000000) { ch = str[0] & 0b00011111; chlen = 2; } + else if ((str[0] & 0b11110000) == 0b11100000) { ch = str[0] & 0b00001111; chlen = 3; } + else if ((str[0] & 0b11111000) == 0b11110000) { ch = str[0] & 0b00000111; chlen = 4; } + else goto invalid; + if ((ch == 0 && chlen != 1) || chlen > len) goto invalid; + for (uint8_t i = 1; i < chlen; i++) { + if ((str[i] & 0b11000000) != 0b10000000) goto invalid; + ch = (ch << 6) | (str[i] & 0b00111111); + } + if (ch > 0x10FFFF) goto invalid; + *ret_ch = ch; + *ret_chlen = chlen; + return; + invalid: + *ret_chlen = 0; +} + +bool _utf8_is_valid(const uint8_t *str, size_t len, bool forbid_nul) { + for (size_t pos = 0; pos < len;) { + uint32_t ch; + uint8_t chlen; + utf8_decode_codepoint(&str[pos], len-pos, &ch, &chlen); + if (chlen == 0 || (forbid_nul && ch == 0)) + return false; + pos += chlen; + } + return true; +} |