Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
CellularUtil.cpp
00001 /* 00002 * Copyright (c) , Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #include "CellularUtil.h" 00018 #include <string.h> 00019 #include <stdlib.h> 00020 00021 00022 #include "randLIB.h" 00023 #define RANDOM_PORT_NUMBER_START 49152 00024 #define RANDOM_PORT_NUMBER_END 65535 00025 #define RANDOM_PORT_NUMBER_COUNT (RANDOM_PORT_NUMBER_END - RANDOM_PORT_NUMBER_START + 1) 00026 #define RANDOM_PORT_NUMBER_MAX_STEP 100 00027 00028 using namespace mbed; 00029 namespace mbed_cellular_util { 00030 00031 nsapi_version_t convert_ipv6(char *ip) 00032 { 00033 if (!ip) { 00034 return NSAPI_UNSPEC ; 00035 } 00036 00037 int len = strlen(ip); 00038 int pos = 0; 00039 int i; 00040 00041 for (i = 0; i < len; i++) { 00042 if (ip[i] == '.') { 00043 pos++; 00044 } 00045 if (pos > 3) { 00046 break; 00047 } 00048 } 00049 00050 // more that 3 periods mean that it was ipv6 but in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 00051 // we need to convert it to hexadecimal format separated with colons 00052 if (pos == 3) { 00053 00054 return NSAPI_IPv4 ; 00055 00056 } else if (pos > 3) { 00057 pos = 0; 00058 int ip_pos = 0; 00059 char b; 00060 bool set_colon = false; 00061 for (i = 0; i < len; i++) { 00062 if (ip[i] == '.') { 00063 b = (char)strtol(ip + ip_pos, NULL, 10); // convert to char to int so we can change it to hex string 00064 pos += char_str_to_hex_str(&b, 1, ip + pos, !set_colon); // omit leading zeroes with using set_colon flag 00065 if (set_colon) { 00066 ip[pos++] = ':'; 00067 set_colon = false; 00068 } else { 00069 set_colon = true; 00070 } 00071 ip_pos = i + 1; // skip the '.' 00072 } 00073 00074 // handle the last part which does not end with '.' but '\0' 00075 if (i == len - 1) { 00076 b = (char)strtol(ip + ip_pos, NULL, 10); 00077 pos += char_str_to_hex_str(&b, 1, ip + pos, !set_colon); 00078 ip[pos] = '\0'; 00079 } 00080 } 00081 00082 return NSAPI_IPv6 ; 00083 } 00084 00085 return NSAPI_UNSPEC ; 00086 } 00087 00088 // For example "32.1.13.184.0.0.205.48.0.0.0.0.0.0.0.0" 00089 void separate_ip4like_addresses(char *orig, char *ip, size_t ip_size, char *ip2, size_t ip2_size) 00090 { 00091 // ipv4-like notation 00092 int len = strlen(orig); 00093 int count = 0, i = 0, pos = 0; 00094 char *temp; 00095 00096 for (; i < len; i++) { 00097 if (orig[i] == '.') { 00098 count++; 00099 if (count == 4) { 00100 pos = i; 00101 } else if (count == 16) { 00102 pos = i; 00103 } 00104 } 00105 } 00106 00107 if (count == 3) { // normal ipv4, copy to ip 00108 if (ip_size > strlen(orig)) { 00109 memcpy(ip, orig, strlen(orig)); 00110 ip[strlen(orig)] = '\0'; 00111 } else { 00112 ip[0] = '\0'; 00113 } 00114 if (ip2) { 00115 ip2[0] = '\0'; 00116 } 00117 } else if (count == 7) { // ipv4 and subnet mask. Need to separate those. 00118 temp = &orig[pos]; 00119 if ((uint8_t)ip_size > temp - orig) { 00120 memcpy(ip, orig, temp - orig); 00121 ip[temp - orig] = '\0'; 00122 } 00123 temp++; // skip the '.' 00124 if (ip2 && (ip2_size > strlen(temp))) { 00125 memcpy(ip2, temp, strlen(temp)); 00126 ip2[strlen(temp)] = '\0'; 00127 } 00128 } else if (count == 15) { // only one ipv6 address in ipv4-like notation 00129 if (ip_size > strlen(orig)) { 00130 memcpy(ip, orig, strlen(orig)); 00131 ip[strlen(orig)] = '\0'; 00132 convert_ipv6(ip); 00133 } else { 00134 ip[0] = '\0'; 00135 } 00136 if (ip2) { 00137 ip2[0] = '\0'; 00138 } 00139 } else if (count == 31) { // ipv6 + ipv6subnet mask in ipv4-like notation separated by dot '.' 00140 temp = &orig[pos]; 00141 if ((uint8_t)ip_size > temp - orig) { 00142 memcpy(ip, orig, temp - orig); 00143 ip[temp - orig] = '\0'; 00144 convert_ipv6(ip); 00145 } 00146 temp++; // skip the '.' 00147 if (ip2 && (ip2_size > strlen(temp))) { 00148 memcpy(ip2, temp, strlen(temp)); 00149 ip2[strlen(temp)] = '\0'; 00150 convert_ipv6(ip2); 00151 } 00152 } 00153 } 00154 00155 void separate_ip_addresses(char *orig, char *ip, size_t ip_size, char *ip2, size_t ip2_size) 00156 { 00157 // orig can include ipv4, ipv6, both or two ip4/ipv6 addresses. 00158 // also format depends on possible AT+CGPIAF 00159 if (!orig || !ip) { 00160 if (ip) { 00161 ip[0] = '\0'; 00162 } 00163 if (ip2) { 00164 ip2[0] = '\0'; 00165 } 00166 return; 00167 } 00168 // 1. try to found ':'. If it's found then we know that possible addresses are separated with space 00169 char *temp; 00170 temp = strchr(orig, ':'); 00171 00172 if (temp != NULL) { 00173 // found ':' 00174 temp = strstr(orig, " "); 00175 // found space as separator and it wasn't in beginning --> contains 2 ip addresses 00176 if (temp && temp != orig) { 00177 if ((uint8_t)ip_size > temp - orig) { 00178 memcpy(ip, orig, temp - orig); 00179 ip[temp - orig] = '\0'; 00180 } else { 00181 ip[0] = '\0'; 00182 } 00183 temp++; // skip the space 00184 if (ip2 && (ip2_size > strlen(temp))) { 00185 memcpy(ip2, temp, strlen(temp)); 00186 ip2[strlen(temp)] = '\0'; 00187 } else if (ip2) { 00188 ip2[0] = '\0'; 00189 } 00190 } else { 00191 // Space was the first char or no space found ---> only one ip, copy to ip 00192 size_t size = strlen(orig); 00193 if (temp) { 00194 size = strlen(temp); 00195 } 00196 00197 if (ip_size > size) { 00198 memcpy(ip, orig, size); 00199 ip[size] = '\0'; 00200 } else { 00201 ip[0] = '\0'; 00202 } 00203 if (ip2) { 00204 ip2[0] = '\0'; 00205 } 00206 } 00207 } else { 00208 separate_ip4like_addresses(orig, ip, ip_size, ip2, ip2_size); 00209 } 00210 } 00211 00212 void prefer_ipv6(char *ip, size_t ip_size, char *ip2, size_t ip2_size) 00213 { 00214 if (!ip || !ip2) { 00215 return; 00216 } 00217 // assume that that ipv6 is already in formatted to use ':' 00218 // 1. try to found ':'. If it's found then we know that this is ipv6 00219 char *temp; 00220 temp = strchr(ip, ':'); 00221 if (temp) { 00222 // ip has ipv6 address, we can leave 00223 return; 00224 } else { 00225 // ip was not ipv6, check if ip2 is 00226 temp = strchr(ip2, ':'); 00227 if (temp) { 00228 // ipv6 was found in ip2 but not in ip ---> we must swap them. Sadly ip and ip2 might not be pointers 00229 // so we can't just swap them, must use copy. 00230 if (strlen(ip) < ip2_size && strlen(ip2) < ip_size && strlen(ip) < 64 && strlen(ip2) < 64) { 00231 char tmp[64]; 00232 strncpy(tmp, ip, strlen(ip)); 00233 tmp[strlen(ip)] = '\0'; 00234 strncpy(ip, ip2, strlen(ip2)); 00235 ip[strlen(ip2)] = '\0'; 00236 strncpy(ip2, tmp, strlen(tmp)); 00237 ip2[strlen(tmp)] = '\0'; 00238 } 00239 } 00240 } 00241 } 00242 00243 void int_to_hex_str(uint8_t num, char *buf) 00244 { 00245 char charNum = num; 00246 char_str_to_hex_str(&charNum, 1, buf); 00247 } 00248 00249 int hex_str_to_int(const char *hex_string, int hex_string_length) 00250 { 00251 const int base = 16; 00252 int character_as_integer, integer_output = 0; 00253 00254 for (int i = 0; i < hex_string_length && hex_string[i] != '\0'; i++) { 00255 if (hex_string[i] >= '0' && hex_string[i] <= '9') { 00256 character_as_integer = hex_string[i] - '0'; 00257 } else if (hex_string[i] >= 'A' && hex_string[i] <= 'F') { 00258 character_as_integer = hex_string[i] - 'A' + 10; 00259 } else { 00260 character_as_integer = hex_string[i] - 'a' + 10; 00261 } 00262 integer_output *= base; 00263 integer_output += character_as_integer; 00264 } 00265 00266 return integer_output; 00267 } 00268 00269 int hex_str_to_char_str(const char *str, uint16_t len, char *buf) 00270 { 00271 int strcount = 0; 00272 if (str && buf) { 00273 for (int i = 0; i + 1 < len; i += 2) { 00274 char tmp; 00275 hex_to_char(str + i, tmp); 00276 buf[strcount] = tmp; 00277 strcount++; 00278 } 00279 } 00280 00281 return strcount; 00282 } 00283 00284 void hex_to_char(const char *hex, char &buf) 00285 { 00286 if (hex) { 00287 int upper = hex_str_to_int(hex, 1); 00288 int lower = hex_str_to_int(hex + 1, 1); 00289 buf = ((upper << 4) & 0xF0) | (lower & 0x0F); 00290 } 00291 } 00292 00293 void uint_to_binary_str(uint32_t num, char *str, int str_size, int bit_cnt) 00294 { 00295 if (!str || str_size < bit_cnt) { 00296 return; 00297 } 00298 int tmp, pos = 0; 00299 00300 for (int i = 31; i >= 0; i--) { 00301 tmp = num >> i; 00302 if (i < bit_cnt) { 00303 if (tmp & 1) { 00304 str[pos] = 1 + '0'; 00305 } else { 00306 str[pos] = 0 + '0'; 00307 } 00308 pos++; 00309 } 00310 } 00311 } 00312 00313 uint32_t binary_str_to_uint(const char *binary_string, int binary_string_length) 00314 { 00315 if (!binary_string || !binary_string_length) { 00316 return 0; 00317 } 00318 00319 int integer_output = 0, base_exp = 1; 00320 00321 for (int i = binary_string_length - 1; i >= 0; i--) { 00322 if (binary_string[i] == '1') { 00323 integer_output += base_exp; 00324 } 00325 if (binary_string[i] != '\0') { 00326 base_exp <<= 1; 00327 } 00328 } 00329 00330 return integer_output; 00331 } 00332 00333 int char_str_to_hex_str(const char *str, uint16_t len, char *buf, bool omit_leading_zero) 00334 { 00335 if (!str || !buf) { 00336 return 0; 00337 } 00338 00339 char *ptr = buf; 00340 int i = 0; 00341 while (i < len) { 00342 if (omit_leading_zero == true && i == 0 && !(str[i] >> 4 & 0x0F)) { 00343 *ptr++ = hex_values[(str[i]) & 0x0F]; 00344 } else { 00345 *ptr++ = hex_values[((str[i]) >> 4) & 0x0F]; 00346 *ptr++ = hex_values[(str[i]) & 0x0F]; 00347 } 00348 i++; 00349 } 00350 return ptr - buf; 00351 } 00352 00353 uint16_t get_dynamic_ip_port() 00354 { 00355 static uint16_t port_counter = RANDOM_PORT_NUMBER_COUNT; 00356 00357 if (port_counter == RANDOM_PORT_NUMBER_COUNT) { 00358 randLIB_seed_random(); 00359 port_counter = randLIB_get_random_in_range(0, RANDOM_PORT_NUMBER_COUNT - 1); 00360 } 00361 00362 port_counter += randLIB_get_random_in_range(1, RANDOM_PORT_NUMBER_MAX_STEP); 00363 port_counter %= RANDOM_PORT_NUMBER_COUNT; 00364 00365 return (RANDOM_PORT_NUMBER_START + port_counter); 00366 } 00367 00368 pdp_type_t string_to_pdp_type(const char *pdp_type_str) 00369 { 00370 pdp_type_t pdp_type = DEFAULT_PDP_TYPE; 00371 int len = strlen(pdp_type_str); 00372 00373 if (len == 6 && memcmp(pdp_type_str, "IPV4V6", len) == 0) { 00374 pdp_type = IPV4V6_PDP_TYPE; 00375 } else if (len == 4 && memcmp(pdp_type_str, "IPV6", len) == 0) { 00376 pdp_type = IPV6_PDP_TYPE; 00377 } else if (len == 2 && memcmp(pdp_type_str, "IP", len) == 0) { 00378 pdp_type = IPV4_PDP_TYPE; 00379 } else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) { 00380 pdp_type = NON_IP_PDP_TYPE; 00381 } 00382 return pdp_type; 00383 } 00384 00385 } // namespace mbed_cellular_util
Generated on Tue Jul 12 2022 13:54:05 by
