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.
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 namespace mbed_cellular_util { 00022 00023 void convert_ipv6(char* ip) 00024 { 00025 if (!ip) { 00026 return; 00027 } 00028 00029 int len = strlen(ip); 00030 int pos = 0; 00031 int i; 00032 00033 for (i = 0; i < len; i++) { 00034 if (ip[i] == '.') { 00035 pos++; 00036 } 00037 if (pos > 3) { 00038 break; 00039 } 00040 } 00041 00042 // 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 00043 // we need to convert it to hexadecimal format separated with colons 00044 if (pos > 3) { 00045 pos = 0; 00046 int ip_pos = 0; 00047 char b; 00048 bool set_colon = false; 00049 for (i = 0; i < len; i++) { 00050 if (ip[i] == '.') { 00051 b = (char)strtol (ip+ip_pos, NULL, 10); // convert to char to int so we can change it to hex string 00052 pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon); // omit leading zeroes with using set_colon flag 00053 if (set_colon) { 00054 ip[pos++] = ':'; 00055 set_colon = false; 00056 } else { 00057 set_colon = true; 00058 } 00059 ip_pos = i+1; // skip the '.' 00060 } 00061 00062 // handle the last part which does not end with '.' but '\0' 00063 if (i == len -1) { 00064 b = (char)strtol(ip+ip_pos, NULL, 10); 00065 pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon); 00066 ip[pos] = '\0'; 00067 } 00068 } 00069 } 00070 } 00071 00072 // For example "32.1.13.184.0.0.205.48.0.0.0.0.0.0.0.0" 00073 void separate_ip4like_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) 00074 { 00075 // ipv4-like notation 00076 int len = strlen(orig); 00077 int count = 0, i = 0, pos = 0; 00078 char *temp; 00079 00080 for (; i < len; i++) { 00081 if (orig[i] == '.') { 00082 count++; 00083 if (count == 4) { 00084 pos = i; 00085 } else if (count == 16) { 00086 pos = i; 00087 } 00088 } 00089 } 00090 00091 if (count == 3) { // normal ipv4, copy to ip 00092 if (ip_size > strlen(orig)) { 00093 memcpy(ip, orig, strlen(orig)); 00094 ip[strlen(orig)] = '\0'; 00095 } else { 00096 ip[0] = '\0'; 00097 } 00098 if (ip2) { 00099 ip2[0] = '\0'; 00100 } 00101 } else if (count == 7) { // ipv4 and subnet mask. Need to separate those. 00102 temp = &orig[pos]; 00103 if ((uint8_t)ip_size > temp-orig) { 00104 memcpy(ip, orig, temp-orig); 00105 ip[temp-orig] = '\0'; 00106 } 00107 temp++; // skip the '.' 00108 if (ip2 && (ip2_size > strlen(temp))) { 00109 memcpy(ip2, temp, strlen(temp)); 00110 ip2[strlen(temp)] = '\0'; 00111 } 00112 } else if (count == 15) { // only one ipv6 address in ipv4-like notation 00113 if (ip_size > strlen(orig)) { 00114 memcpy(ip, orig, strlen(orig)); 00115 ip[strlen(orig)] = '\0'; 00116 convert_ipv6(ip); 00117 } else { 00118 ip[0] = '\0'; 00119 } 00120 if (ip2) { 00121 ip2[0] = '\0'; 00122 } 00123 } else if (count == 31){ // ipv6 + ipv6subnet mask in ipv4-like notation separated by dot '.' 00124 temp = &orig[pos]; 00125 if ((uint8_t)ip_size > temp-orig) { 00126 memcpy(ip, orig, temp-orig); 00127 ip[temp-orig] = '\0'; 00128 convert_ipv6(ip); 00129 } 00130 temp++; // skip the '.' 00131 if (ip2 && (ip2_size > strlen(temp))) { 00132 memcpy(ip2, temp, strlen(temp)); 00133 ip2[strlen(temp)] = '\0'; 00134 convert_ipv6(ip2); 00135 } 00136 } 00137 } 00138 00139 void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) 00140 { 00141 // orig can include ipv4, ipv6, both or two ip4/ipv6 addresses. 00142 // also format depends on possible AT+CGPIAF 00143 if (!orig || !ip) { 00144 if (ip) { 00145 ip[0] = '\0'; 00146 } 00147 if (ip2) { 00148 ip2[0] = '\0'; 00149 } 00150 return; 00151 } 00152 // 1. try to found ':'. If it's found then we know that possible addresses are separated with space 00153 char *temp; 00154 temp = strchr(orig, ':'); 00155 00156 if (temp != NULL) { 00157 // found ':' 00158 temp = strstr(orig, " "); 00159 // found space as separator and it wasn't in beginning --> contains 2 ip addresses 00160 if (temp && temp != orig) { 00161 if ((uint8_t)ip_size > temp-orig) { 00162 memcpy(ip, orig, temp-orig); 00163 ip[temp-orig] = '\0'; 00164 } else { 00165 ip[0] = '\0'; 00166 } 00167 temp++; // skip the space 00168 if (ip2 && (ip2_size > strlen(temp))) { 00169 memcpy(ip2, temp, strlen(temp)); 00170 ip2[strlen(temp)] = '\0'; 00171 } else if (ip2) { 00172 ip2[0] = '\0'; 00173 } 00174 } else { 00175 // Space was the first char or no space found ---> only one ip, copy to ip 00176 size_t size = strlen(orig); 00177 if (temp) { 00178 size = strlen(temp); 00179 } 00180 00181 if (ip_size > size) { 00182 memcpy(ip, orig, size); 00183 ip[size] = '\0'; 00184 } else { 00185 ip[0] = '\0'; 00186 } 00187 if (ip2) { 00188 ip2[0] = '\0'; 00189 } 00190 } 00191 } else { 00192 temp = strstr(orig, " "); 00193 // found space as separator and it wasn't in beginning --> contains 2 ip addresses 00194 if (temp && temp != orig) { 00195 separate_ip4like_addresses(temp++, ip2, ip2_size, NULL, 0); 00196 orig[temp-orig-1] = '\0'; 00197 separate_ip4like_addresses(orig, ip, ip_size, NULL, 0); 00198 orig[temp-orig-1] = ' '; // put space back to keep orig as original 00199 } 00200 else { 00201 separate_ip4like_addresses(orig, ip, ip_size, ip2, ip2_size); 00202 } 00203 } 00204 } 00205 00206 void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size) 00207 { 00208 if (!ip || !ip2) { 00209 return; 00210 } 00211 // assume that that ipv6 is already in formatted to use ':' 00212 // 1. try to found ':'. If it's found then we know that this is ipv6 00213 char *temp; 00214 temp = strchr(ip, ':'); 00215 if (temp) { 00216 // ip has ipv6 address, we can leave 00217 return; 00218 } else { 00219 // ip was not ipv6, check if ip2 is 00220 temp = strchr(ip2, ':'); 00221 if (temp) { 00222 // ipv6 was found in ip2 but not in ip ---> we must swap them. Sadly ip and ip2 might not be pointers 00223 // so we can't just swap them, must use copy. 00224 if (strlen(ip) < ip2_size && strlen(ip2) < ip_size && strlen(ip) < 64) { 00225 char tmp[64]; 00226 strncpy(tmp, ip, strlen(ip)); 00227 tmp[strlen(ip)] = '\0'; 00228 strncpy(ip, ip2, strlen(ip2)); 00229 ip[strlen(ip2)] = '\0'; 00230 strncpy(ip2, tmp, strlen(tmp)); 00231 ip2[strlen(tmp)] = '\0'; 00232 } 00233 } 00234 } 00235 } 00236 00237 void int_to_hex_str(uint8_t num, char* buf) 00238 { 00239 char charNum = num; 00240 char_str_to_hex_str(&charNum, 1, buf); 00241 } 00242 00243 int hex_str_to_int(const char *hex_string, int hex_string_length) 00244 { 00245 const int base = 16; 00246 int character_as_integer, integer_output = 0; 00247 00248 for (int i=0;i<hex_string_length && hex_string[i] != '\0';i++) { 00249 if (hex_string[i] >= '0' && hex_string[i] <= '9') { 00250 character_as_integer = hex_string[i] - '0'; 00251 } else if (hex_string[i] >= 'A' && hex_string[i] <= 'F') { 00252 character_as_integer = hex_string[i] - 'A' + 10; 00253 } else { 00254 character_as_integer = hex_string[i] - 'a' + 10; 00255 } 00256 integer_output *= base; 00257 integer_output += character_as_integer; 00258 } 00259 00260 return integer_output; 00261 } 00262 00263 int hex_str_to_char_str(const char* str, uint16_t len, char *buf) 00264 { 00265 int strcount = 0; 00266 for (int i = 0; i+1 < len; i += 2) { 00267 int upper = hex_str_to_int(str+i, 1); 00268 int lower = hex_str_to_int(str+i+1, 1); 00269 buf[strcount] = ((upper<<4) & 0xF0) | (lower & 0x0F); 00270 strcount++; 00271 } 00272 00273 return strcount; 00274 } 00275 00276 void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) 00277 { 00278 if (!str || str_size < bit_cnt) { 00279 return; 00280 } 00281 int tmp, pos = 0; 00282 00283 for (int i = 31; i >= 0; i--) { 00284 tmp = num >> i; 00285 if (i < bit_cnt) { 00286 if (tmp&1) { 00287 str[pos] = 1 + '0'; 00288 } else { 00289 str[pos] = 0 + '0'; 00290 } 00291 pos++; 00292 } 00293 } 00294 } 00295 00296 int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero) 00297 { 00298 if (!str || !buf) { 00299 return 0; 00300 } 00301 00302 char *ptr = buf; 00303 int i=0; 00304 while (i < len) { 00305 if (omit_leading_zero == true && i == 0 && !(str[i]>>4 & 0x0F)) { 00306 *ptr++ = hex_values[(str[i]) & 0x0F]; 00307 } else { 00308 *ptr++ = hex_values[((str[i])>>4) & 0x0F]; 00309 *ptr++ = hex_values[(str[i]) & 0x0F]; 00310 } 00311 i++; 00312 } 00313 return ptr-buf; 00314 } 00315 00316 uint16_t get_dynamic_ip_port() 00317 { 00318 static uint16_t port; 00319 port++; 00320 if (port < 49152) { 00321 port = 49152; 00322 } 00323 return port; 00324 } 00325 00326 } // namespace mbed_cellular_util
Generated on Tue Jul 12 2022 18:18:29 by
