/***************************************************************************/ /** * @file sl_utility.c ******************************************************************************* * # License * Copyright 2024 Silicon Laboratories Inc. www.silabs.com ******************************************************************************* * * SPDX-License-Identifier: Zlib * * The licensor of this software is Silicon Laboratories Inc. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. * ******************************************************************************/ #include #include #include "sl_utility.h" #include "sl_constants.h" #include "sl_string.h" #include "cmsis_compiler.h" #include #include #ifdef SPRINTF_CHAR #define SPRINTF(x) strlen(sprintf /**/ x) #else #define SPRINTF(x) ((size_t)sprintf x) #endif #define DIGIT_VAL(c) \ (((c >= '0') && (c <= '9')) ? (c - '0') \ : ((c >= 'a') && (c <= 'z')) ? (c - 'a' + 10) \ : ((c >= 'A') && (c <= 'Z')) ? (c - 'A' + 10) \ : -1) typedef struct { int base; int len; } data_t; extern char *strtok_r(char *, const char *, char **); void convert_uint32_to_bytestream(uint16_t data, uint8_t *buffer) { buffer[0] = (uint8_t)(data & 0xFF); buffer[1] = (uint8_t)((data >> 8) & 0xFF); buffer[2] = (uint8_t)((data >> 16) & 0xFF); buffer[3] = (uint8_t)((data >> 24) & 0xFF); return; } sl_status_t convert_string_to_sl_ipv4_address(char *line, sl_ipv4_address_t *ip) { char *lasts = NULL; const char *token = strtok_r(line, ".", &lasts); for (uint8_t i = 0; i < 4; i++, token = strtok_r(NULL, ".", &lasts)) { if (token == NULL) { return SL_STATUS_COMMAND_IS_INVALID; } ip->bytes[i] = (uint8_t)strtoul(token, 0, 0); } return SL_STATUS_OK; } void print_sl_ip_address(const sl_ip_address_t *sl_ip_address) { if (sl_ip_address == NULL) { return; } if (sl_ip_address->type == SL_IPV4) { print_sl_ipv4_address(&sl_ip_address->ip.v4); } else if (sl_ip_address->type == SL_IPV6) { print_sl_ipv6_address(&sl_ip_address->ip.v6); } } void print_sl_ipv4_address(const sl_ipv4_address_t *ip_address) { printf("%d.%d.%d.%d", ip_address->bytes[0], ip_address->bytes[1], ip_address->bytes[2], ip_address->bytes[3]); } void print_sl_ipv6_address(const sl_ipv6_address_t *ip_address) { char temp_buffer[46] = { 0 }; sl_inet_ntop6((const unsigned char *)(ip_address), (char *)temp_buffer, sizeof(temp_buffer)); printf("%s\r\n", temp_buffer); } void print_mac_address(const sl_mac_address_t *mac_address) { if (mac_address == NULL) { return; } printf("%2X:%2X:%2X:%2X:%2X:%2X", mac_address->octet[0], mac_address->octet[1], mac_address->octet[2], mac_address->octet[3], mac_address->octet[4], mac_address->octet[5]); } char *sl_inet_ntop6(const unsigned char *input, char *dst, uint32_t size) { char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; char *tp; data_t best; data_t cur; unsigned int words[SL_IPV6_ADDRESS_LENGTH / 2]; int i; unsigned int ip_big_endian[4]; const unsigned char *src; src = (unsigned char *)&ip_big_endian; little_to_big_endian((const unsigned int *)input, (unsigned char *)ip_big_endian, SL_IPV6_ADDRESS_LENGTH); memset(words, '\0', sizeof words); for (i = 0; i < SL_IPV6_ADDRESS_LENGTH; i += 2) { int temp = src[i]; words[i / 2] = (temp << 8) | src[i + 1]; } best.base = -1; cur.base = -1; best.len = 0; cur.len = 0; for (i = 0; i < (SL_IPV6_ADDRESS_LENGTH / 2); i++) { if (words[i] == 0) { if (cur.base == -1) { cur.base = i; cur.len = 1; } else cur.len++; } else { if (cur.base != -1) { if (best.base == -1 || cur.len > best.len) best = cur; cur.base = -1; } } } if ((cur.base != -1) && (best.base == -1 || cur.len > best.len)) best = cur; if (best.base != -1 && best.len < 2) best.base = -1; /* * Format the result. */ tp = tmp; for (i = 0; i < (SL_IPV6_ADDRESS_LENGTH / 2); i++) { /* Are we inside the best run of 0x00's? */ if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { if (i == best.base) *tp++ = ':'; continue; } /* Are we following an initial run of 0x00s or any real hex? */ if (i != 0) *tp++ = ':'; tp += SPRINTF((tp, "%x", words[i])); } /* Was it a trailing run of 0x00's? */ if (best.base != -1 && (best.base + best.len) == (SL_IPV6_ADDRESS_LENGTH / 2)) *tp++ = ':'; *tp++ = '\0'; /* * Check for overflow, copy, and we're done. */ if ((uint32_t)(tp - tmp) > size) { printf("\r\n Error \r\n"); return NULL; } return memcpy(dst, tmp, size); } static int hex_digit_value(char ch) { if ('0' <= ch && ch <= '9') return ch - '0'; if ('a' <= ch && ch <= 'f') return ch - 'a' + 10; if ('A' <= ch && ch <= 'F') return ch - 'A' + 10; return -1; } void little_to_big_endian(const unsigned int *source, unsigned char *result, unsigned int length) { unsigned char *temp; unsigned int curr = 0; length /= 4; for (unsigned int i = 0; i < length; i++) { curr = source[i]; temp = &result[i * 4]; temp[3] = (curr & 0xFF); temp[2] = ((curr >> 8) & 0xFF); temp[1] = ((curr >> 16) & 0xFF); temp[0] = ((curr >> 24) & 0xFF); } } int sl_inet_pton6(const char *src, const char *src_endp, unsigned char *dst, unsigned int *ptr_result) { unsigned char tmp[SL_IPV6_ADDRESS_LENGTH]; unsigned char *tp; unsigned char *endp; unsigned char *colonp; const char *curtok __attribute__((__unused__)); int ch; size_t xdigits_seen; /* Number of hex digits since colon. */ unsigned int val; tp = memset(tmp, '\0', SL_IPV6_ADDRESS_LENGTH); endp = tp + SL_IPV6_ADDRESS_LENGTH; colonp = NULL; /* Leading :: requires some special handling. */ if (src == src_endp) return 0; if (*src == ':') { ++src; if (src == src_endp || *src != ':') return 0; } curtok = src; xdigits_seen = 0; val = 0; while (src < src_endp) { ch = *src++; int digit = hex_digit_value((char)ch); //printf(" digit :%d ",digit); if (digit >= 0) { if (xdigits_seen == 4) return 0; val <<= 4; val |= digit; if (val > 0xffff) return 0; ++xdigits_seen; continue; } if (ch == ':') { curtok = src; if (xdigits_seen == 0) { if (colonp) return 0; colonp = tp; continue; } else if (src == src_endp) return 0; if (tp + 2 > endp) return 0; *tp++ = (unsigned char)(val >> 8) & 0xff; *tp++ = (unsigned char)val & 0xff; xdigits_seen = 0; val = 0; continue; } } if (xdigits_seen > 0) { if (tp + 2 > endp) return 0; *tp++ = (unsigned char)(val >> 8) & 0xff; *tp++ = (unsigned char)val & 0xff; } if (colonp != NULL) { /* Replace :: with zeros. */ if (tp == endp) /* :: would expand to a zero-width field. */ return 0; size_t n = tp - colonp; memmove(endp - n, colonp, n); memset(colonp, 0, endp - n - colonp); tp = endp; } if (tp != endp) return 0; memcpy(dst, tmp, SL_IPV6_ADDRESS_LENGTH); little_to_big_endian((const unsigned int *)dst, (unsigned char *)ptr_result, SL_IPV6_ADDRESS_LENGTH); return 1; } sl_status_t convert_string_to_mac_address(const char *line, sl_mac_address_t *mac) { // Verify we have the exact number of characters. Basic argument verification if (sl_strnlen((char *)line, 18) != 17) { return SL_STATUS_INVALID_PARAMETER; } uint8_t index = 0; while (index < 6) { // Read all the data and verify validity int char1 = DIGIT_VAL(line[0]); int char2 = DIGIT_VAL(line[1]); if (char1 == -1 || char2 == -1 || (line[2] != '\0' && line[2] != ':')) { return SL_STATUS_INVALID_PARAMETER; } // Store value mac->octet[index++] = (uint8_t)((uint8_t)char1 << 4) + (uint8_t)char2; line += 3; } return SL_STATUS_OK; } void reverse_digits(unsigned char *xx, int no_digits) { uint8_t temp; for (int count = 0; count < (no_digits / 2); count++) { temp = xx[count]; xx[count] = xx[no_digits - count - 1]; xx[no_digits - count - 1] = temp; } } void print_firmware_version(const sl_wifi_firmware_version_t *firmware_version) { printf("\r\nFirmware version is: %x%x.%d.%d.%d.%d.%d.%d\r\n", firmware_version->chip_id, firmware_version->rom_id, firmware_version->major, firmware_version->minor, firmware_version->security_version, firmware_version->patch_num, firmware_version->customer_id, firmware_version->build_num); } __WEAK void sl_debug_log(const char *format, ...) { UNUSED_PARAMETER(format); } void sl_redirect_log(const char *format, ...) { UNUSED_PARAMETER(format); }