1 /*******************************************************************************
2  * @file  rsi_utils.c
3  *******************************************************************************
4  * # License
5  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6  *******************************************************************************
7  *
8  * SPDX-License-Identifier: Zlib
9  *
10  * The licensor of this software is Silicon Laboratories Inc.
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  *    claim that you wrote the original software. If you use this software
22  *    in a product, an acknowledgment in the product documentation would be
23  *    appreciated but is not required.
24  * 2. Altered source versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.
26  * 3. This notice may not be removed or altered from any source distribution.
27  *
28  ******************************************************************************/
29 /*
30   Include files
31  */
32 
33 #include "rsi_common.h"
34 #include <sl_string.h>
35 
36 #define MAX_MAC_ADDRESS_STRING_LENGTH  17
37 #define MAX_IPV4_ADDRESS_STRING_LENGTH 15
38 
39 /*
40   Global defines
41  */
42 /** @addtogroup DRIVER12
43 * @{
44 */
45 /*=============================================================================*/
46 /**
47  * @fn           void rsi_uint16_to_2bytes(uint8_t *dBuf, uint16_t val)
48  * @brief        Convert uint16 to two byte array.
49  * @param[in]    dBuf - Pointer to buffer to put the data in
50  * @param[in]    val  - Data to convert
51  * @return       void
52  */
rsi_uint16_to_2bytes(uint8_t * dBuf,uint16_t val)53 void rsi_uint16_to_2bytes(uint8_t *dBuf, uint16_t val)
54 {
55   if (rsi_driver_cb->endian == IS_LITTLE_ENDIAN) {
56     dBuf[0] = val & 0x00ff;
57     dBuf[1] = (val >> 8) & 0x00ff;
58   } else {
59     dBuf[1] = val & 0x00ff;
60     dBuf[0] = (val >> 8) & 0x00ff;
61   }
62 }
63 
64 /*=============================================================================*/
65 /**
66  * @fn              void rsi_uint32_to_4bytes(uint8_t *dBuf, uint32_t val)
67  * @brief           Convert uint32 to four byte array.
68  * @param[in]       dBuf - Pointer to buffer to put the data in
69  * @param[in]       val  - Data to convert
70  * @return          void
71  */
72 
rsi_uint32_to_4bytes(uint8_t * dBuf,uint32_t val)73 void rsi_uint32_to_4bytes(uint8_t *dBuf, uint32_t val)
74 {
75   if (rsi_driver_cb->endian == IS_LITTLE_ENDIAN) {
76     dBuf[0] = val & 0x000000ff;
77     dBuf[1] = (val >> 8) & 0x000000ff;
78     dBuf[2] = (val >> 16) & 0x000000ff;
79     dBuf[3] = (val >> 24) & 0x000000ff;
80   } else {
81     dBuf[3] = val & 0x000000ff;
82     dBuf[2] = (val >> 8) & 0x000000ff;
83     dBuf[1] = (val >> 16) & 0x000000ff;
84     dBuf[0] = (val >> 24) & 0x000000ff;
85   }
86 }
87 
88 /*=============================================================================*/
89 /**
90  * @fn          uint16_t rsi_bytes2R_to_uint16(uint8_t *dBuf)
91  * @brief       Convert a 2 byte array to uint16, first byte in array is LSB.
92  * @param[in]   dBuf - Pointer to a buffer to get the data from
93  * @return      Converted 16 bit data
94  */
rsi_bytes2R_to_uint16(const uint8_t * dBuf)95 uint16_t rsi_bytes2R_to_uint16(const uint8_t *dBuf)
96 {
97   uint16_t val;
98   if (rsi_driver_cb->endian == IS_LITTLE_ENDIAN) {
99     val = dBuf[1];
100     val <<= 8;
101     val |= dBuf[0] & 0x000000ff;
102   } else {
103     val = dBuf[0];
104     val <<= 8;
105     val |= dBuf[1] & 0x000000ff;
106   }
107   return val;
108 }
109 
110 /*=============================================================================*/
111 /**
112  * @fn           uint32_t rsi_bytes4R_to_uint32(uint8_t *dBuf)
113  * @brief        Convert a 4 byte array to uint32, first byte in array is LSB.
114  * @param[in]    dBuf - Pointer to a buffer to get the data from
115  * @return       Converted 32 bit data
116  */
117 
rsi_bytes4R_to_uint32(const uint8_t * dBuf)118 uint32_t rsi_bytes4R_to_uint32(const uint8_t *dBuf)
119 {
120   // the 32-bit value to return
121   uint32_t val;
122 
123   if (rsi_driver_cb->endian == IS_LITTLE_ENDIAN) {
124     val = dBuf[3];
125     val <<= 8;
126     val |= dBuf[2] & 0x000000ff;
127     val <<= 8;
128     val |= dBuf[1] & 0x000000ff;
129     val <<= 8;
130     val |= dBuf[0] & 0x000000ff;
131   } else {
132     val = dBuf[0];
133     val <<= 8;
134     val |= dBuf[1] & 0x000000ff;
135     val <<= 8;
136     val |= dBuf[2] & 0x000000ff;
137     val <<= 8;
138     val |= dBuf[3] & 0x000000ff;
139   }
140 
141   return val;
142 }
143 
144 /*==============================================*/
145 /**
146  * @fn         int8_t rsi_ascii_hex2num(int8_t ascii_hex_in)
147  * @brief      ASCII to hex conversion.
148  * @param[in]  ascii_hex_in - ASCII hex input
149  * @return     hex number
150  */
151 
rsi_ascii_hex2num(int8_t ascii_hex_in)152 int8_t rsi_ascii_hex2num(int8_t ascii_hex_in)
153 {
154   if ((ascii_hex_in >= '0') && (ascii_hex_in <= '9'))
155     return (ascii_hex_in - '0');
156   if ((ascii_hex_in >= 'A') && (ascii_hex_in <= 'F'))
157     return (ascii_hex_in - 'A' + 10);
158   if ((ascii_hex_in >= 'a') && (ascii_hex_in <= 'f'))
159     return (ascii_hex_in - 'a' + 10);
160 
161   return RSI_SUCCESS;
162 }
163 
164 /*=============================================================================*/
165 /**
166  * @fn          int8 rsi_char_hex2dec(int8_t *cBuf)
167  * @brief       Convert given ASCII hex notation to decimal notation (used for mac address).
168  * @param[in]   cBuf - ASCII hex notation string
169  * @return      Integer Value
170  */
rsi_char_hex2dec(int8_t * cBuf)171 int8_t rsi_char_hex2dec(int8_t *cBuf)
172 {
173   int8_t k       = 0;
174   size_t buf_len = strlen((char *)cBuf);
175   for (uint8_t i = 0; i < buf_len; i++) {
176     k = ((k * 16) + rsi_ascii_hex2num(cBuf[i]));
177   }
178   return k;
179 }
180 
181 /*=============================================================================*/
182 /**
183  * @fn             uint8_t *rsi_ascii_dev_address_to_6bytes_rev(uint8_t *hex_addr, int8_t *ascii_mac_address)
184  * @brief          Convert notation MAC address to a 6-byte hex address.
185  * @param[in]      asciiMacFormatAddress - Source address to convert, must be a null terminated string.
186  * @param[out]     hex_addr              - Converted hex address is returned here.
187  * @return         Hex address
188  */
189 
rsi_ascii_dev_address_to_6bytes_rev(uint8_t * hex_addr,int8_t * ascii_mac_address)190 uint8_t *rsi_ascii_dev_address_to_6bytes_rev(uint8_t *hex_addr, int8_t *ascii_mac_address)
191 {
192   uint8_t cBufPos; // which char in the ASCII representation
193   uint8_t byteNum; // which byte in the 32Bithex_address
194   int8_t cBuf[6];  // temporary buffer
195 
196   byteNum        = 5;
197   cBufPos        = 0;
198   size_t buf_len = strnlen((char *)ascii_mac_address, MAX_MAC_ADDRESS_STRING_LENGTH);
199   for (uint8_t i = 0; i < buf_len; i++) {
200     // this will take care of the first 5 octets
201     if (ascii_mac_address[i] == ':') {                                 // we are at the end of the address octet
202       cBuf[cBufPos]       = 0;                                         // terminate the string
203       cBufPos             = 0;                                         // reset for the next char
204       hex_addr[byteNum--] = (uint8_t)rsi_char_hex2dec((int8_t *)cBuf); // convert the strint to an integer
205     } else {
206       cBuf[cBufPos++] = ascii_mac_address[i];
207     }
208   }
209   // handle the last octet            // we are at the end of the string with no .
210   cBuf[cBufPos]     = 0x00;                                      // terminate the string
211   hex_addr[byteNum] = (uint8_t)rsi_char_hex2dec((int8_t *)cBuf); // convert the strint to an integer
212 
213   return hex_addr;
214 }
215 
216 /*=============================================================================*/
217 /**
218  * @fn          int8_t hex_to_ascii(uint8_t hex_num)
219  * @brief       Hex to ascii conversion.
220  * @param[in]   hex_num - hex number
221  * @return      Ascii value for given hex value
222  */
223 
hex_to_ascii(uint8_t hex_num)224 int8_t hex_to_ascii(uint8_t hex_num)
225 {
226   uint8_t ascii = 0;
227 
228   switch (hex_num & 0x0F) {
229     case 0:
230     case 1:
231     case 2:
232     case 3:
233     case 4:
234     case 5:
235     case 6:
236     case 7:
237     case 8:
238     case 9:
239       ascii = (hex_num & 0x0F) + '0';
240       return ascii;
241 
242     case 0xa:
243     case 0xb:
244     case 0xc:
245     case 0xd:
246     case 0xe:
247     case 0xf:
248       ascii = (hex_num & 0x0F) - 10 + 'A';
249       return ascii;
250     default:
251       break;
252   }
253 
254   return ascii;
255 }
256 
257 /*=============================================================================*/
258 /**
259  * @fn              int8_t *rsi_6byte_dev_address_to_ascii(uint8_t *ascii_mac_address, uint8_t *hex_addr)
260  * @brief           Convert given 6-byte hex address to ASCII Mac address.
261  * @param[in]       hex_addr              - Hex address input.
262  * @param[out]      asciiMacFormatAddress - Converted ASCII mac address is returned here.
263  * @return          Converted ASCII mac address
264  */
265 
rsi_6byte_dev_address_to_ascii(uint8_t * ascii_mac_address,const uint8_t * hex_addr)266 uint8_t *rsi_6byte_dev_address_to_ascii(uint8_t *ascii_mac_address, const uint8_t *hex_addr)
267 {
268   uint8_t cBufPos; // which char in the ASCII representation
269 
270   cBufPos = 0;
271   for (int8_t i = 5; i >= 0; i--) {
272     ascii_mac_address[cBufPos++] = hex_to_ascii(hex_addr[i] >> 4);
273     ascii_mac_address[cBufPos++] = hex_to_ascii(hex_addr[i]);
274     if (i != 0) {
275       ascii_mac_address[cBufPos++] = ':';
276     }
277   }
278   return ascii_mac_address;
279 }
280 
281 /*=========================================================================*/
282 /**
283  * @fn          uint8_t convert_lower_case_to_upper_case(uint8_t lwrcase)
284  * @brief       Convert the given lower-case character to upper case.
285  * @param[in]   lwrcase - Lower case character to convert
286  * @return      Converted Upper case character
287  */
288 
convert_lower_case_to_upper_case(uint8_t lwrcase)289 uint8_t convert_lower_case_to_upper_case(uint8_t lwrcase)
290 {
291   uint8_t digit = (lwrcase >= 'a' && lwrcase <= 'f') ? (lwrcase - 0x20) : lwrcase;
292   return (digit >= 'A' && digit <= 'F') ? digit - 0x37 : digit - '0';
293 }
294 
295 /*=========================================================================*/
296 /**
297  * @fn          void string2array(uint8_t *dst, uint8_t *src, uint32_t length)
298  * @brief       Convert the given string to destination array.
299  * @param[in]   dst    -  Pointer to destination array
300  * @param[in]   src    - Pointer to source string
301  * @param[in]   length - Length of the string
302  * @return      void
303  */
304 
string2array(uint8_t * dst,const uint8_t * src,uint32_t length)305 void string2array(uint8_t *dst, const uint8_t *src, uint32_t length)
306 {
307   for (uint32_t i = 0, j = 0; i < (length * 2) && j < length; i += 2, j++)
308     if (src[i] && src[i + 1]) {
309       dst[j] = (uint8_t)((convert_lower_case_to_upper_case(src[i])) * 16);
310       dst[j] += convert_lower_case_to_upper_case(src[i + 1]);
311     } else {
312       dst[j] = 0;
313     }
314 }
315 /*=========================================================================*/
316 /**
317  * @fn         uint8_t *rsi_itoa(uint32_t val, uint8_t *str)
318  * @brief      Convert integer value into null-terminated string and stores the result in the array given by str parameter.
319  * @param[in]  val - Value to be converted to a string
320  * @param[in]  str - Array in memory where to store the resulting null-terminated string
321  * @return     String
322  */
323 
rsi_itoa(uint32_t val,uint8_t * str)324 uint8_t *rsi_itoa(uint32_t val, uint8_t *str)
325 {
326   int16_t ii = 0;
327   int16_t jj = 0;
328   uint8_t tmp[10];
329   if (val == 0) {
330     // if value is zero then handling
331     str[jj] = '0';
332     jj++;
333     str[jj] = '\0';
334     return str;
335   }
336 
337   while (val) {
338     tmp[ii] = '0' + (val % 10);
339     val /= 10;
340     ii++;
341   }
342 
343   for (jj = 0, ii--; ii >= 0; ii--, jj++) {
344     str[jj] = tmp[ii];
345   }
346   str[jj] = '\0';
347 
348   return str;
349 }
350 
351 /*=========================================================================*/
352 /**
353  * @fn          int32_t rsi_atoi(const int8_t *str)
354  * @brief       Convert string to an integer.
355  * @param[in]   str - This is the string representation of an integral number
356  * @return      Converted Integer
357  */
rsi_atoi(const int8_t * str)358 int32_t rsi_atoi(const int8_t *str)
359 {
360   int32_t res              = 0;
361   int32_t i                = 0;
362   uint32_t negative_number = 0;
363 
364   if (str[i] == '-') {
365     negative_number = 1;
366     i++;
367   }
368   for (; (str[i] >= '0') && (str[i] <= '9'); ++i)
369     res = res * 10 + str[i] - '0';
370 
371   if (negative_number) {
372     res *= -1;
373   }
374   return res;
375 }
376 
377 /*=============================================================================*/
378 /**
379  * @fn         int8_t asciihex_2_num(int8_t ascii_hex_in)
380  * @brief      ASCII to hex conversion.
381  * @param[in]  ascii_hex_in - ASCII hex input
382  * @return     hex num
383  */
asciihex_2_num(int8_t ascii_hex_in)384 int8_t asciihex_2_num(int8_t ascii_hex_in)
385 {
386   if ((ascii_hex_in >= '0') && (ascii_hex_in <= '9'))
387     return (ascii_hex_in - '0');
388   if ((ascii_hex_in >= 'A') && (ascii_hex_in <= 'F'))
389     return (ascii_hex_in - 'A' + 10);
390   if ((ascii_hex_in >= 'a') && (ascii_hex_in <= 'f'))
391     return (ascii_hex_in - 'a' + 10);
392 
393   return RSI_SUCCESS;
394 }
395 
396 /*=============================================================================*/
397 /**
398  * @fn          int8_t rsi_charhex_2_dec(int8_t *cBuf)
399  * @brief       Convert given ASCII hex notation to decimal notation (used for mac address).
400  * @param[in]   cBuf - ASCII hex notation string.
401  * @return      value in integer
402  */
rsi_charhex_2_dec(int8_t * cBuf)403 int8_t rsi_charhex_2_dec(int8_t *cBuf)
404 {
405   int8_t k       = 0;
406   size_t buf_len = sl_strlen((char *)cBuf);
407   for (uint8_t i = 0; i < buf_len; i++) {
408     k = ((k * 16) + asciihex_2_num(cBuf[i]));
409   }
410   return k;
411 }
412 
413 /*=============================================================================*/
414 /**
415  * @fn              void rsi_ascii_mac_address_to_6bytes(uint8_t *hexAddr, int8_t *asciiMacAddress)
416  * @brief           Convert notation MAC address to a 6-byte hex address.
417  * @param[in]       asciiMacFormatAddress - source address to convert, must be a null terminated string.
418  * @param[out]      hexAddr               - Converted hex address is returned here.
419  * @return          void
420  */
rsi_ascii_mac_address_to_6bytes(uint8_t * hexAddr,int8_t * asciiMacAddress)421 void rsi_ascii_mac_address_to_6bytes(uint8_t *hexAddr, int8_t *asciiMacAddress)
422 {
423   uint8_t cBufPos; // which char in the ASCII representation
424   uint8_t byteNum; // which byte in the 32BitHexAddress
425   int8_t cBuf[6];  // temporary buffer
426 
427   byteNum        = 0;
428   cBufPos        = 0;
429   size_t buf_len = sl_strnlen((char *)asciiMacAddress, MAX_MAC_ADDRESS_STRING_LENGTH);
430   for (uint8_t i = 0; i < buf_len; i++) {
431     // this will take care of the first 5 octets
432     if (asciiMacAddress[i] == ':') {                                   // we are at the end of the address octet
433       cBuf[cBufPos]      = 0;                                          // terminate the string
434       cBufPos            = 0;                                          // reset for the next char
435       hexAddr[byteNum++] = (uint8_t)rsi_charhex_2_dec((int8_t *)cBuf); // convert the strint to an integer
436     } else {
437       cBuf[cBufPos++] = asciiMacAddress[i];
438     }
439   }
440   // handle the last octet                  // we are at the end of the string with no .
441   cBuf[cBufPos]    = 0x00;                                       // terminate the string
442   hexAddr[byteNum] = (uint8_t)rsi_charhex_2_dec((int8_t *)cBuf); // convert the strint to an integer
443 }
444 
445 /*=============================================================================*/
446 /**
447  * @fn            void rsi_ascii_dot_address_to_4bytes(uint8_t *hexAddr, int8_t *asciiDotAddress)
448  * @brief         Convert notation network address to 4-byte hex address.
449  * @param[in]     asciiDotAddress - source address to convert, must be a null terminated string.
450  * @param[out]    hexAddr         - Output value is passed back in the 4-byte Hex Address.
451  * @return        void
452  */
rsi_ascii_dot_address_to_4bytes(uint8_t * hexAddr,int8_t * asciiDotAddress)453 void rsi_ascii_dot_address_to_4bytes(uint8_t *hexAddr, int8_t *asciiDotAddress)
454 {
455   uint8_t cBufPos;
456   // which char in the ASCII representation
457   uint8_t byteNum;
458   // which byte in the 32BitHexAddress
459   int8_t cBuf[4];
460   // character buffer
461 
462   byteNum        = 0;
463   cBufPos        = 0;
464   size_t buf_len = sl_strnlen((char *)asciiDotAddress, MAX_IPV4_ADDRESS_STRING_LENGTH);
465   for (uint8_t i = 0; i < buf_len; i++) {
466     // this will take care of the first 3 octets
467     if (asciiDotAddress[i] == '.') {
468       // we are at the end of the address octet
469       cBuf[cBufPos] = 0;
470       // terminate the string
471       cBufPos = 0;
472       // reset for the next char
473       hexAddr[byteNum++] = (uint8_t)rsi_atoi(cBuf);
474       // convert the strint to an integer
475     } else {
476       cBuf[cBufPos++] = asciiDotAddress[i];
477     }
478   }
479   // handle the last octet
480   // we are at the end of the string with no .
481   cBuf[cBufPos] = 0x00;
482   // terminate the string
483   // convert the strint to an integer
484   hexAddr[byteNum] = (uint8_t)rsi_atoi(cBuf);
485 }
486 /*=============================================================================*/
487 /**
488  * @fn         uint32_t rsi_ntohl(uint32_t a)
489  * @brief      Converts the unsigned integer from network byte order to host byte order.
490  * @param[in]  a - Unsigned integer to convert.
491  * @return     Unsigned integer in host byte order
492  */
493 // network to host long
rsi_ntohl(uint32_t a)494 uint32_t rsi_ntohl(uint32_t a)
495 {
496   return (((a & 0xff000000) >> 24) | ((a & 0x00ff0000) >> 8) | ((a & 0x0000ff00) << 8) | ((a & 0x000000ff) << 24));
497 }
498 
499 /** @} */
500