Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CellularUtil.cpp Source File

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