mirror of https://github.com/ARMmbed/mbed-os.git
Squashed 'connectivity/libraries/nanostack-libservice/' content from commit c6cae6992a
git-subtree-dir: connectivity/libraries/nanostack-libservice git-subtree-split: c6cae6992a12f62f19cf7875f889304d5c1ded6dpull/13454/head^2
commit
f4cdbeb7c1
|
@ -0,0 +1 @@
|
|||
output/*
|
|
@ -0,0 +1 @@
|
|||
test/*
|
|
@ -0,0 +1,2 @@
|
|||
test/*
|
||||
output/*
|
|
@ -0,0 +1,2 @@
|
|||
Unless specifically indicated otherwise in a file, files are licensed
|
||||
under the Apache 2.0 license, as can be found in: apache-2.0.txt
|
|
@ -0,0 +1,13 @@
|
|||
SRCS := \
|
||||
source/IPv6_fcf_lib/ip_fsc.c \
|
||||
source/libBits/common_functions.c \
|
||||
source/libip6string/ip6tos.c \
|
||||
source/libip6string/stoip6.c \
|
||||
source/libList/ns_list.c \
|
||||
source/nsdynmemLIB/nsdynmemLIB.c \
|
||||
source/nvmHelper/ns_nvm_helper.c \
|
||||
|
||||
LIB := libservice.a
|
||||
EXPORT_HEADERS := mbed-client-libservice
|
||||
|
||||
include ../exported_rules.mk
|
|
@ -0,0 +1,3 @@
|
|||
# mbed-client-libservice module
|
||||
|
||||
Collection of helper libraries for mbed-client and 6LowPAN/IPv6/RPL/MLE/Thread stack.
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
|
||||
Apache License
|
||||
|
||||
Version 2.0, January 2004
|
||||
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,632 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef COMMON_FUNCTIONS_H_
|
||||
#define COMMON_FUNCTIONS_H_
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Common write 64-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 64 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param value 64-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8]);
|
||||
|
||||
/*
|
||||
* Common read 64-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 64 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 64-bit variable
|
||||
*/
|
||||
NS_INLINE uint64_t common_read_64_bit(const uint8_t data_buf[__static 8]);
|
||||
|
||||
/*
|
||||
* Common write 32-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 32 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param value 32-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]);
|
||||
|
||||
/*
|
||||
* Common read 32-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 32 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 32-bit variable
|
||||
*/
|
||||
NS_INLINE uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]);
|
||||
|
||||
/*
|
||||
* Common write 32-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 32 bits in little-endian byte order.
|
||||
*
|
||||
* \param value 32-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4]);
|
||||
|
||||
/*
|
||||
* Common read 32-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 32 bits in little-endian byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 32-bit variable
|
||||
*/
|
||||
NS_INLINE uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4]);
|
||||
|
||||
/*
|
||||
* Common write 24-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 24 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param value 24-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3]);
|
||||
|
||||
/*
|
||||
* Common read 24-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 24 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 24-bit variable
|
||||
*/
|
||||
NS_INLINE uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3]);
|
||||
|
||||
/*
|
||||
* Common write 24-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 24 bits in little-endian byte order.
|
||||
*
|
||||
* \param value 24-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_24_bit_inverse(uint_fast24_t value, uint8_t ptr[__static 3]);
|
||||
|
||||
/*
|
||||
* Common read 24-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 24 bits in little-endian byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 24-bit variable
|
||||
*/
|
||||
NS_INLINE uint_fast24_t common_read_24_bit_inverse(const uint8_t data_buf[__static 3]);
|
||||
|
||||
/*
|
||||
* Common write 16-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 16 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param value 16-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]);
|
||||
|
||||
/*
|
||||
* Common read 16-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 16 bits in big-endian (network) byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 16-bit variable
|
||||
*/
|
||||
NS_INLINE uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]);
|
||||
|
||||
/*
|
||||
* Common write 16-bit variable to 8-bit pointer.
|
||||
*
|
||||
* Write 16 bits in little-endian byte order.
|
||||
*
|
||||
* \param value 16-bit variable
|
||||
* \param ptr pointer where data to be written
|
||||
*
|
||||
* \return updated pointer
|
||||
*/
|
||||
NS_INLINE uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]);
|
||||
|
||||
/*
|
||||
* Common read 16-bit variable from 8-bit pointer.
|
||||
*
|
||||
* Read 16 bits in little-endian byte order.
|
||||
*
|
||||
* \param data_buf pointer where data to be read
|
||||
*
|
||||
* \return 16-bit variable
|
||||
*/
|
||||
NS_INLINE uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2]);
|
||||
|
||||
/*
|
||||
* Count bits in a byte
|
||||
*
|
||||
* \param value byte to inspect
|
||||
*
|
||||
* \return number of 1-bits in byte
|
||||
*/
|
||||
NS_INLINE uint_fast8_t common_count_bits(uint8_t value);
|
||||
|
||||
/*
|
||||
* Count leading zeros in a byte
|
||||
*
|
||||
* \deprecated Use common_count_leading_zeros_8
|
||||
*
|
||||
* \param value byte to inspect
|
||||
*
|
||||
* \return number of leading zeros in byte (0-8)
|
||||
*/
|
||||
NS_INLINE uint_fast8_t common_count_leading_zeros(uint8_t value);
|
||||
|
||||
/*
|
||||
* Count leading zeros in a byte
|
||||
*
|
||||
* \param value byte to inspect
|
||||
*
|
||||
* \return number of leading zeros in byte (0-8)
|
||||
*/
|
||||
NS_INLINE uint_fast8_t common_count_leading_zeros_8(uint8_t value);
|
||||
|
||||
/*
|
||||
* Count leading zeros in a 16-bit value
|
||||
*
|
||||
* \param value value to inspect
|
||||
*
|
||||
* \return number of leading zeros in byte (0-16)
|
||||
*/
|
||||
NS_INLINE uint_fast8_t common_count_leading_zeros_16(uint16_t value);
|
||||
|
||||
/*
|
||||
* Count leading zeros in a 32-bit value
|
||||
*
|
||||
* \param value value to inspect
|
||||
*
|
||||
* \return number of leading zeros in byte (0-32)
|
||||
*/
|
||||
NS_INLINE uint_fast8_t common_count_leading_zeros_32(uint32_t value);
|
||||
|
||||
/*
|
||||
* Compare 8-bit serial numbers
|
||||
*
|
||||
* Compare two 8-bit serial numbers, according to RFC 1982 Serial Number
|
||||
* Arithmetic.
|
||||
*
|
||||
* \param s1 first serial number
|
||||
* \param s2 second serial number
|
||||
*
|
||||
* \return true if s1 > s2
|
||||
* \return false if s1 <= s2, or the comparison is undefined
|
||||
*/
|
||||
NS_INLINE bool common_serial_number_greater_8(uint8_t s1, uint8_t s2);
|
||||
|
||||
/*
|
||||
* Compare 16-bit serial numbers
|
||||
*
|
||||
* Compare two 16-bit serial numbers, according to RFC 1982 Serial Number
|
||||
* Arithmetic.
|
||||
*
|
||||
* \param s1 first serial number
|
||||
* \param s2 second serial number
|
||||
*
|
||||
* \return true if s1 > s2
|
||||
* \return false if s1 <= s2, or the comparison is undefined
|
||||
*/
|
||||
NS_INLINE bool common_serial_number_greater_16(uint16_t s1, uint16_t s2);
|
||||
|
||||
/*
|
||||
* Compare 32-bit serial numbers
|
||||
*
|
||||
* Compare two 32-bit serial numbers, according to RFC 1982 Serial Number
|
||||
* Arithmetic.
|
||||
*
|
||||
* \param s1 first serial number
|
||||
* \param s2 second serial number
|
||||
*
|
||||
* \return true if s1 > s2
|
||||
* \return false if s1 <= s2, or the comparison is undefined
|
||||
*/
|
||||
NS_INLINE bool common_serial_number_greater_32(uint32_t s1, uint32_t s2);
|
||||
|
||||
/*
|
||||
* Test a bit in an bit array.
|
||||
*
|
||||
* Check whether a particular bit is set in a bit string. The bit array
|
||||
* is in big-endian (network) bit order.
|
||||
*
|
||||
* \param bitset pointer to bit array
|
||||
* \param bit index of bit - 0 is the most significant bit of the first byte
|
||||
*
|
||||
* \return true if the bit is set
|
||||
*/
|
||||
NS_INLINE bool bit_test(const uint8_t *bitset, uint_fast8_t bit);
|
||||
|
||||
/*
|
||||
* Set a bit in an bit array.
|
||||
*
|
||||
* Set a bit in a bit array. The array is in big-endian (network) bit order.
|
||||
*
|
||||
* \param bitset pointer to bit array
|
||||
* \param bit index of bit - 0 is the most significant bit of the first byte
|
||||
*/
|
||||
NS_INLINE void bit_set(uint8_t *bitset, uint_fast8_t bit);
|
||||
|
||||
/*
|
||||
* Clear a bit in an bit array.
|
||||
*
|
||||
* Clear a bit in a bit array. The bit array is in big-endian (network) bit order.
|
||||
*
|
||||
* \param bitset pointer to bit array
|
||||
* \param bit index of bit - 0 is the most significant bit of the first byte
|
||||
*/
|
||||
NS_INLINE void bit_clear(uint8_t *bitset, uint_fast8_t bit);
|
||||
|
||||
/*
|
||||
* Compare two bitstrings.
|
||||
*
|
||||
* Compare two bitstrings of specified length. The bit strings are in
|
||||
* big-endian (network) bit order.
|
||||
*
|
||||
* \param a pointer to first string
|
||||
* \param b pointer to second string
|
||||
* \param bits number of bits to compare
|
||||
*
|
||||
* \return true if the strings compare equal
|
||||
*/
|
||||
bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits);
|
||||
|
||||
/*
|
||||
* Copy a bitstring
|
||||
*
|
||||
* Copy a bitstring of specified length. The bit string is in big-endian
|
||||
* (network) bit order. Bits beyond the bitlength at the destination are not
|
||||
* modified.
|
||||
*
|
||||
* For example, copying 4 bits sets the first 4 bits of dst[0] from src[0],
|
||||
* the lower 4 bits of dst[0] are unmodified.
|
||||
*
|
||||
* \param dst destination pointer
|
||||
* \param src source pointer
|
||||
* \param bits number of bits to copy
|
||||
*
|
||||
* \return the value of dst
|
||||
*/
|
||||
uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits);
|
||||
|
||||
/*
|
||||
* Copy a bitstring and pad last byte with zeros
|
||||
*
|
||||
* Copy a bitstring of specified length. The bit string is in big-endian
|
||||
* (network) bit order. Bits beyond the bitlength in the last destination byte are
|
||||
* zeroed.
|
||||
*
|
||||
* For example, copying 4 bits sets the first 4 bits of dst[0] from src[0], and
|
||||
* the lower 4 bits of dst[0] are set to 0.
|
||||
*
|
||||
* \param dst destination pointer
|
||||
* \param src source pointer
|
||||
* \param bits number of bits to copy
|
||||
*
|
||||
* \return the value of dst
|
||||
*/
|
||||
uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits);
|
||||
|
||||
/* Provide definitions, either for inlining, or for common_functions.c */
|
||||
#if defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN
|
||||
#ifndef COMMON_FUNCTIONS_FN
|
||||
#define COMMON_FUNCTIONS_FN NS_INLINE
|
||||
#endif
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8])
|
||||
{
|
||||
*ptr++ = value >> 56;
|
||||
*ptr++ = value >> 48;
|
||||
*ptr++ = value >> 40;
|
||||
*ptr++ = value >> 32;
|
||||
*ptr++ = value >> 24;
|
||||
*ptr++ = value >> 16;
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint64_t common_read_64_bit(const uint8_t data_buf[__static 8])
|
||||
{
|
||||
uint64_t temp_64;
|
||||
temp_64 = (uint64_t)(*data_buf++) << 56;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 48;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 40;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 32;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 24;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 16;
|
||||
temp_64 += (uint64_t)(*data_buf++) << 8;
|
||||
temp_64 += *data_buf++;
|
||||
return temp_64;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4])
|
||||
{
|
||||
*ptr++ = value >> 24;
|
||||
*ptr++ = value >> 16;
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint32_t common_read_32_bit(const uint8_t data_buf[__static 4])
|
||||
{
|
||||
uint32_t temp_32;
|
||||
temp_32 = (uint32_t)(*data_buf++) << 24;
|
||||
temp_32 += (uint32_t)(*data_buf++) << 16;
|
||||
temp_32 += (uint32_t)(*data_buf++) << 8;
|
||||
temp_32 += *data_buf++;
|
||||
return temp_32;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4])
|
||||
{
|
||||
*ptr++ = value;
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value >> 16;
|
||||
*ptr++ = value >> 24;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4])
|
||||
{
|
||||
uint32_t temp_32;
|
||||
temp_32 = *data_buf++;
|
||||
temp_32 += (uint32_t)(*data_buf++) << 8;
|
||||
temp_32 += (uint32_t)(*data_buf++) << 16;
|
||||
temp_32 += (uint32_t)(*data_buf++) << 24;
|
||||
return temp_32;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3])
|
||||
{
|
||||
*ptr++ = value >> 16;
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3])
|
||||
{
|
||||
uint_fast24_t temp_24;
|
||||
temp_24 = (uint_fast24_t)(*data_buf++) << 16;
|
||||
temp_24 += (uint_fast24_t)(*data_buf++) << 8;
|
||||
temp_24 += *data_buf++;
|
||||
return temp_24;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_24_bit_inverse(uint_fast24_t value, uint8_t ptr[__static 3])
|
||||
{
|
||||
*ptr++ = value;
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value >> 16;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast24_t common_read_24_bit_inverse(const uint8_t data_buf[__static 3])
|
||||
{
|
||||
uint_fast24_t temp_24;
|
||||
temp_24 = *data_buf++;
|
||||
temp_24 += (uint_fast24_t)(*data_buf++) << 8;
|
||||
temp_24 += (uint_fast24_t)(*data_buf++) << 16;
|
||||
return temp_24;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2])
|
||||
{
|
||||
*ptr++ = value >> 8;
|
||||
*ptr++ = value;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint16_t common_read_16_bit(const uint8_t data_buf[__static 2])
|
||||
{
|
||||
uint16_t temp_16;
|
||||
temp_16 = (uint16_t)(*data_buf++) << 8;
|
||||
temp_16 += *data_buf++;
|
||||
return temp_16;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2])
|
||||
{
|
||||
*ptr++ = value;
|
||||
*ptr++ = value >> 8;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2])
|
||||
{
|
||||
uint16_t temp_16;
|
||||
temp_16 = *data_buf++;
|
||||
temp_16 += (uint16_t)(*data_buf++) << 8;
|
||||
return temp_16;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast8_t common_count_bits(uint8_t value)
|
||||
{
|
||||
/* First step sets each bit pair to be count of bits (00,01,10) */
|
||||
/* [00-00 = 00, 01-00 = 01, 10-01 = 01, 11-01 = 10] */
|
||||
uint_fast8_t count = value - ((value >> 1) & 0x55);
|
||||
/* Add bit pairs to make each nibble contain count of bits (0-4) */
|
||||
count = (count & 0x33) + ((count >> 2) & 0x33);
|
||||
/* Final result is sum of nibbles (0-8) */
|
||||
count = (count >> 4) + (count & 0x0F);
|
||||
return count;
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros(uint8_t value)
|
||||
{
|
||||
return common_count_leading_zeros_8(value);
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_8(uint8_t value)
|
||||
{
|
||||
#if defined __GNUC__
|
||||
return value ? __builtin_clz((unsigned int) value << 24) : 8;
|
||||
#else
|
||||
uint_fast8_t cnt = 0;
|
||||
if (value == 0) {
|
||||
return 8;
|
||||
}
|
||||
if ((value & 0xF0) == 0) {
|
||||
value <<= 4;
|
||||
cnt += 4;
|
||||
}
|
||||
if ((value & 0xC0) == 0) {
|
||||
value <<= 2;
|
||||
cnt += 2;
|
||||
}
|
||||
if ((value & 0x80) == 0) {
|
||||
cnt += 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#endif
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_16(uint16_t value)
|
||||
{
|
||||
#if defined __GNUC__
|
||||
return value ? __builtin_clz((unsigned int) value << 16) : 16;
|
||||
#else
|
||||
uint_fast8_t cnt = 0;
|
||||
if (value == 0) {
|
||||
return 16;
|
||||
}
|
||||
if ((value & 0xFF00) == 0) {
|
||||
value <<= 8;
|
||||
cnt += 8;
|
||||
}
|
||||
if ((value & 0xF000) == 0) {
|
||||
value <<= 4;
|
||||
cnt += 4;
|
||||
}
|
||||
if ((value & 0xC000) == 0) {
|
||||
value <<= 2;
|
||||
cnt += 2;
|
||||
}
|
||||
if ((value & 0x8000) == 0) {
|
||||
cnt += 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#endif
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_32(uint32_t value)
|
||||
{
|
||||
#if defined __GNUC__
|
||||
return value ? __builtin_clz(value) : 32;
|
||||
#else
|
||||
uint_fast8_t cnt = 0;
|
||||
if (value == 0) {
|
||||
return 32;
|
||||
}
|
||||
if ((value & 0xFFFF0000) == 0) {
|
||||
value <<= 16;
|
||||
cnt += 16;
|
||||
}
|
||||
if ((value & 0xFF000000) == 0) {
|
||||
value <<= 8;
|
||||
cnt += 8;
|
||||
}
|
||||
if ((value & 0xF0000000) == 0) {
|
||||
value <<= 4;
|
||||
cnt += 4;
|
||||
}
|
||||
if ((value & 0xC0000000) == 0) {
|
||||
value <<= 2;
|
||||
cnt += 2;
|
||||
}
|
||||
if ((value & 0x80000000) == 0) {
|
||||
cnt += 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
#endif
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN bool common_serial_number_greater_8(uint8_t s1, uint8_t s2)
|
||||
{
|
||||
return (s1 > s2 && s1 - s2 < UINT8_C(0x80)) || (s1 < s2 && s2 - s1 > UINT8_C(0x80));
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN bool common_serial_number_greater_16(uint16_t s1, uint16_t s2)
|
||||
{
|
||||
return (s1 > s2 && s1 - s2 < UINT16_C(0x8000)) || (s1 < s2 && s2 - s1 > UINT16_C(0x8000));
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN bool common_serial_number_greater_32(uint32_t s1, uint32_t s2)
|
||||
{
|
||||
return (s1 > s2 && s1 - s2 < UINT32_C(0x80000000)) || (s1 < s2 && s2 - s1 > UINT32_C(0x80000000));
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN bool bit_test(const uint8_t *bitset, uint_fast8_t bit)
|
||||
{
|
||||
return bitset[bit >> 3] & (0x80 >> (bit & 7));
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN void bit_set(uint8_t *bitset, uint_fast8_t bit)
|
||||
{
|
||||
bitset[bit >> 3] |= (0x80 >> (bit & 7));
|
||||
}
|
||||
|
||||
COMMON_FUNCTIONS_FN void bit_clear(uint8_t *bitset, uint_fast8_t bit)
|
||||
{
|
||||
bitset[bit >> 3] &= ~(0x80 >> (bit & 7));
|
||||
}
|
||||
|
||||
#endif /* defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*__COMMON_FUNCTIONS_H_*/
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef IP4STRING_H
|
||||
#define IP4STRING_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
/**
|
||||
* Print binary IPv4 address to a string.
|
||||
*
|
||||
* String must contain enough room for full address, 16 bytes exact.
|
||||
*
|
||||
* \param ip4addr IPv4 address.
|
||||
* \param p buffer to write string to.
|
||||
* \return length of generated string excluding the terminating null character
|
||||
*/
|
||||
uint_fast8_t ip4tos(const void *ip4addr, char *p);
|
||||
|
||||
/**
|
||||
* Convert numeric IPv4 address string to a binary.
|
||||
*
|
||||
* \param ip4addr IPv4 address in string format.
|
||||
* \param len Length of IPv4 string, maximum of 16..
|
||||
* \param dest buffer for address. MUST be 4 bytes.
|
||||
* \return boolean set to true if conversion succeed, false if it didn't
|
||||
*/
|
||||
bool stoip4(const char *ip4addr, size_t len, void *dest);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef IP6STRING_H
|
||||
#define IP6STRING_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
#define MAX_IPV6_STRING_LEN_WITH_TRAILING_NULL 40
|
||||
|
||||
/**
|
||||
* Print binary IPv6 address to a string.
|
||||
*
|
||||
* String must contain enough room for full address, 40 bytes exact.
|
||||
* IPv4 tunneling addresses are not covered.
|
||||
*
|
||||
* \param ip6addr IPv6 address.
|
||||
* \param p buffer to write string to.
|
||||
* \return length of generated string excluding the terminating null character
|
||||
*/
|
||||
uint_fast8_t ip6tos(const void *ip6addr, char *p);
|
||||
|
||||
/**
|
||||
* Print binary IPv6 prefix to a string.
|
||||
*
|
||||
* String buffer `p` must contain enough room for a full address and prefix length, 44 bytes exact.
|
||||
* Bits in the `prefix` buffer beyond `prefix_len` bits are not shown and only the bytes containing the
|
||||
* prefix bits are read. I.e. for a 20 bit prefix 3 bytes are read, and for a 0 bit prefix 0 bytes are
|
||||
* read (thus if `prefix_len` is zero, `prefix` can be NULL).
|
||||
* `prefix_len` must be 0 to 128.
|
||||
*
|
||||
* \param prefix IPv6 prefix.
|
||||
* \param prefix_len length of `prefix` in bits.
|
||||
* \param p buffer to write string to.
|
||||
* \return length of generated string excluding the terminating null character, or 0 for an error, such as 'prefix_len' > 128
|
||||
*/
|
||||
uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p);
|
||||
|
||||
/**
|
||||
* Convert numeric IPv6 address string to a binary.
|
||||
*
|
||||
* IPv4 tunneling addresses are not covered.
|
||||
*
|
||||
* \param ip6addr IPv6 address in string format.
|
||||
* \param len Length of ipv6 string, maximum of 41.
|
||||
* \param dest buffer for address. MUST be 16 bytes. Filled with 0 on error.
|
||||
* \return boolean set to true if conversion succeed, false if it didn't
|
||||
*/
|
||||
bool stoip6(const char *ip6addr, size_t len, void *dest);
|
||||
/**
|
||||
* Find out numeric IPv6 address prefix length.
|
||||
*
|
||||
* \param ip6addr IPv6 address in string format
|
||||
* \return prefix length or 0 if it not given
|
||||
*/
|
||||
unsigned char sipv6_prefixlength(const char *ip6addr);
|
||||
|
||||
/**
|
||||
* Convert numeric IPv6 address string with prefix to a binary.
|
||||
*
|
||||
* IPv4 tunneling addresses are not covered.
|
||||
*
|
||||
* \param ip6addr IPv6 address in string format.
|
||||
* \param dest buffer for address. MUST be 16 bytes.
|
||||
* \param prefix_len_out length of prefix, is set to -1 if no prefix given
|
||||
*
|
||||
* \return 0 on success, negative value otherwise. prefix_len_out contains prefix length.
|
||||
*/
|
||||
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef _NS_FSC_H
|
||||
#define _NS_FSC_H
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
#define NEXT_HEADER_TCP 0x06
|
||||
#define NEXT_HEADER_UDP 0x11
|
||||
#define NEXT_HEADER_ICMP6 0x3A
|
||||
|
||||
extern uint16_t ip_fcf_v(uint_fast8_t count, const ns_iovec_t vec[static count]);
|
||||
extern uint16_t ipv6_fcf(const uint8_t src_address[static 16], const uint8_t dest_address[static 16],
|
||||
uint16_t data_length, const uint8_t data_ptr[static data_length], uint8_t next_protocol);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,764 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef NS_LIST_H_
|
||||
#define NS_LIST_H_
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file
|
||||
* \brief Linked list support library
|
||||
*
|
||||
* The ns_list.h file provides a doubly-linked list/queue, providing O(1)
|
||||
* performance for all insertion/removal operations, and access to either
|
||||
* end of the list.
|
||||
*
|
||||
* Memory footprint is two pointers for the list head, and two pointers in each
|
||||
* list entry. It is similar in concept to BSD's TAILQ.
|
||||
*
|
||||
* Although the API is symmetrical and O(1) in both directions, due to internal
|
||||
* pointer design, it is *slightly* more efficient to insert at the end when
|
||||
* used as a queue, and to iterate forwards rather than backwards.
|
||||
*
|
||||
* Example of an entry type that can be stored to this list.
|
||||
* ~~~
|
||||
* typedef struct example_entry
|
||||
* {
|
||||
* uint8_t *data;
|
||||
* uint32_t data_count;
|
||||
* ns_list_link_t link;
|
||||
* }
|
||||
* example_entry_t;
|
||||
*
|
||||
* static NS_LIST_HEAD(example_entry_t, link) my_list;
|
||||
* ns_list_init(&my_list);
|
||||
* ~~~
|
||||
* OR
|
||||
* ~~~
|
||||
* NS_LIST_HEAD(example_entry_t, link) my_list = NS_LIST_INIT(my_list);
|
||||
* ~~~
|
||||
* OR
|
||||
* ~~~
|
||||
* static NS_LIST_DEFINE(my_list, example_entry_t, link);
|
||||
* ~~~
|
||||
* OR
|
||||
* ~~~
|
||||
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
|
||||
* example_list_t NS_LIST_NAME_INIT(my_list);
|
||||
* ~~~
|
||||
* NOTE: the link field SHALL NOT be accessed by the user.
|
||||
*
|
||||
* An entry can exist on multiple lists by having multiple link fields.
|
||||
*
|
||||
* All the list operations are implemented as macros, most of which are backed
|
||||
* by optionally-inline functions. The macros do not evaluate any arguments more
|
||||
* than once, unless documented.
|
||||
*
|
||||
* In macro documentation, `list_t` refers to a list type defined using
|
||||
* NS_LIST_HEAD(), and `entry_t` to the entry type that was passed to it.
|
||||
*/
|
||||
|
||||
/** \brief Underlying generic linked list head.
|
||||
*
|
||||
* Users should not use this type directly, but use the NS_LIST_HEAD() macro.
|
||||
*/
|
||||
typedef struct ns_list {
|
||||
void *first_entry; ///< Pointer to first entry, or NULL if list is empty
|
||||
void **last_nextptr; ///< Pointer to last entry's `next` pointer, or
|
||||
///< to head's `first_entry` pointer if list is empty
|
||||
} ns_list_t;
|
||||
|
||||
/** \brief Declare a list head type
|
||||
*
|
||||
* This union stores the real list head, and also encodes as compile-time type
|
||||
* information the offset of the link pointer, and the type of the entry.
|
||||
*
|
||||
* Note that type information is compiler-dependent; this means
|
||||
* ns_list_get_first() could return either `void *`, or a pointer to the actual
|
||||
* entry type. So `ns_list_get_first()->data` is not a portable construct -
|
||||
* always assign returned entry pointers to a properly typed pointer variable.
|
||||
* This assignment will be then type-checked where the compiler supports it, and
|
||||
* will dereference correctly on compilers that don't support this extension.
|
||||
*
|
||||
* If you need to support C++03 compilers that cannot return properly-typed
|
||||
* pointers, such as IAR 7, you need to use NS_LIST_TYPECOERCE to force the type.
|
||||
* ~~~
|
||||
* NS_LIST_HEAD(example_entry_t, link) my_list;
|
||||
*
|
||||
* example_entry_t *entry = ns_list_get_first(&my_list);
|
||||
* do_something(entry->data);
|
||||
* ~~~
|
||||
* Each use of this macro generates a new anonymous union, so these two lists
|
||||
* have different types:
|
||||
* ~~~
|
||||
* NS_LIST_HEAD(example_entry_t, link) my_list1;
|
||||
* NS_LIST_HEAD(example_entry_t, link) my_list2;
|
||||
* ~~~
|
||||
* If you need to use a list type in multiple places, eg as a function
|
||||
* parameter, use typedef:
|
||||
* ~~~
|
||||
* typedef NS_LIST_HEAD(example_entry_t, link) example_list_t;
|
||||
*
|
||||
* void example_function(example_list_t *);
|
||||
* ~~~
|
||||
*/
|
||||
#define NS_LIST_HEAD(entry_type, field) \
|
||||
NS_LIST_HEAD_BY_OFFSET_(entry_type, offsetof(entry_type, field))
|
||||
|
||||
/** \brief Declare a list head type for an incomplete entry type.
|
||||
*
|
||||
* This declares a list head, similarly to NS_LIST_HEAD(), but unlike that
|
||||
* this can be used in contexts where the entry type may be incomplete.
|
||||
*
|
||||
* To use this, the link pointer must be the first member in the
|
||||
* actual complete structure. This is NOT checked - the definition of the
|
||||
* element should probably test NS_STATIC_ASSERT(offsetof(type, link) == 0)
|
||||
* if outside users are known to be using NS_LIST_HEAD_INCOMPLETE().
|
||||
* ~~~
|
||||
* struct opaque;
|
||||
* NS_LIST_HEAD_INCOMPLETE(struct opaque) opaque_list;
|
||||
* ~~~
|
||||
*/
|
||||
#define NS_LIST_HEAD_INCOMPLETE(entry_type) \
|
||||
NS_LIST_HEAD_BY_OFFSET_(entry_type, 0)
|
||||
|
||||
/// \privatesection
|
||||
/** \brief Internal macro defining a list head, given the offset to the link pointer
|
||||
* The +1 allows for link_offset being 0 - we can't declare a 0-size array
|
||||
*/
|
||||
#define NS_LIST_HEAD_BY_OFFSET_(entry_type, link_offset) \
|
||||
union \
|
||||
{ \
|
||||
ns_list_t slist; \
|
||||
NS_FUNNY_COMPARE_OK \
|
||||
NS_STATIC_ASSERT(link_offset <= (ns_list_offset_t) -1, "link offset too large") \
|
||||
NS_FUNNY_COMPARE_RESTORE \
|
||||
char (*offset)[link_offset + 1]; \
|
||||
entry_type *type; \
|
||||
}
|
||||
|
||||
/** \brief Get offset of link field in entry.
|
||||
* \return `(ns_list_offset_t)` The offset of the link field for entries on the specified list
|
||||
*/
|
||||
#define NS_LIST_OFFSET_(list) ((ns_list_offset_t) (sizeof *(list)->offset - 1))
|
||||
|
||||
/** \brief Get the entry pointer type.
|
||||
* \def NS_LIST_PTR_TYPE_
|
||||
*
|
||||
* \return An unqualified pointer type to an entry on the specified list.
|
||||
*
|
||||
* Only available if the compiler provides a "typeof" operator.
|
||||
*/
|
||||
#if defined __cplusplus && __cplusplus >= 201103L
|
||||
#define NS_LIST_PTR_TYPE_(list) decltype((list)->type)
|
||||
#elif defined __GNUC__
|
||||
#define NS_LIST_PTR_TYPE_(list) __typeof__((list)->type)
|
||||
#endif
|
||||
|
||||
/** \brief Check for compatible pointer types
|
||||
*
|
||||
* This test will produce a diagnostic about a pointer mismatch on
|
||||
* the == inside the sizeof operator. For example ARM/Norcroft C gives the error:
|
||||
*
|
||||
* operand types are incompatible ("entry_t *" and "other_t *")
|
||||
*/
|
||||
#ifdef CPPCHECK
|
||||
#define NS_PTR_MATCH_(a, b, str) ((void) 0)
|
||||
#else
|
||||
#define NS_PTR_MATCH_(a, b, str) ((void) sizeof ((a) == (b)))
|
||||
#endif
|
||||
|
||||
/** \brief Internal macro to cast returned entry pointers to correct type.
|
||||
*
|
||||
* Not portable in C, alas. With GCC or C++11, the "get entry" macros return
|
||||
* correctly-typed pointers. Otherwise, the macros return `void *`.
|
||||
*
|
||||
* The attempt at a portable version would work if the C `?:` operator wasn't
|
||||
* broken - `x ? (t *) : (void *)` should really have type `(t *)` in C, but
|
||||
* it has type `(void *)`, which only makes sense for C++. The `?:` is left in,
|
||||
* in case some day it works. Some compilers may still warn if this is
|
||||
* assigned to a different type.
|
||||
*/
|
||||
#ifdef NS_LIST_PTR_TYPE_
|
||||
#define NS_LIST_TYPECAST_(list, val) ((NS_LIST_PTR_TYPE_(list)) (val))
|
||||
#else
|
||||
#define NS_LIST_TYPECAST_(list, val) (0 ? (list)->type : (val))
|
||||
#endif
|
||||
|
||||
/** \brief Macro to force correct type if necessary.
|
||||
*
|
||||
* In C, doesn't matter if NS_LIST_TYPECAST_ works or not, as it's legal
|
||||
* to assign void * to a pointer. In C++, we can't do that, so need
|
||||
* a back-up plan for C++03. This forces the type, so breaks type-safety -
|
||||
* only activate when needed, meaning we still get typechecks on other
|
||||
* toolchains.
|
||||
*
|
||||
* If a straight assignment of a ns_list function to a pointer fails
|
||||
* on a C++03 compiler, use the following construct. This will not be
|
||||
* required with C++11 compilers.
|
||||
* ~~~
|
||||
* type *elem = NS_LIST_TYPECOERCE(type *, ns_list_get_first(list));
|
||||
* ~~~
|
||||
*/
|
||||
#if defined(NS_LIST_PTR_TYPE_) || !defined(__cplusplus)
|
||||
#define NS_LIST_TYPECOERCE(type, val) (val)
|
||||
#else
|
||||
#define NS_LIST_TYPECOERCE(type, val) (type) (val)
|
||||
#endif
|
||||
|
||||
/** \brief Internal macro to check types of input entry pointer. */
|
||||
#define NS_LIST_TYPECHECK_(list, entry) \
|
||||
(NS_PTR_MATCH_((list)->type, (entry), "incorrect entry type for list"), (entry))
|
||||
|
||||
/** \brief Type used to pass link offset to underlying functions
|
||||
*
|
||||
* We could use size_t, but it would be unnecessarily large on 8-bit systems,
|
||||
* where we can be (pretty) confident we won't have next pointers more than
|
||||
* 256 bytes into a structure.
|
||||
*/
|
||||
typedef uint_fast8_t ns_list_offset_t;
|
||||
|
||||
/// \publicsection
|
||||
/** \brief The type for the link member in the user's entry structure.
|
||||
*
|
||||
* Users should not access this member directly - just pass its name to the
|
||||
* list head macros. The funny prev pointer simplifies common operations
|
||||
* (eg insertion, removal), at the expense of complicating rare reverse iteration.
|
||||
*
|
||||
* NB - the list implementation relies on next being the first member.
|
||||
*/
|
||||
typedef struct ns_list_link {
|
||||
void *next; ///< Pointer to next entry, or NULL if none
|
||||
void **prev; ///< Pointer to previous entry's (or head's) next pointer
|
||||
} ns_list_link_t;
|
||||
|
||||
/** \brief "Poison" value placed in unattached entries' link pointers.
|
||||
* \internal What are good values for this? Platform dependent, maybe just NULL
|
||||
*/
|
||||
#define NS_LIST_POISON ((void *) 0xDEADBEEF)
|
||||
|
||||
/** \brief Initialiser for an entry's link member
|
||||
*
|
||||
* This initialiser is not required by the library, but a user may want an
|
||||
* initialiser to include in their own entry initialiser. See
|
||||
* ns_list_link_init() for more discussion.
|
||||
*/
|
||||
#define NS_LIST_LINK_INIT(name) \
|
||||
NS_FUNNY_INTPTR_OK \
|
||||
{ NS_LIST_POISON, NS_LIST_POISON } \
|
||||
NS_FUNNY_INTPTR_RESTORE
|
||||
|
||||
/** \hideinitializer \brief Initialise an entry's list link
|
||||
*
|
||||
* This "initialises" an unattached entry's link by filling the fields with
|
||||
* poison. This is optional, as unattached entries field pointers are not
|
||||
* meaningful, and it is not valid to call ns_list_get_next or similar on
|
||||
* an unattached entry.
|
||||
*
|
||||
* \param entry Pointer to an entry
|
||||
* \param field The name of the link member to initialise
|
||||
*/
|
||||
#define ns_list_link_init(entry, field) ns_list_link_init_(&(entry)->field)
|
||||
|
||||
/** \hideinitializer \brief Initialise a list
|
||||
*
|
||||
* Initialise a list head before use. A list head must be initialised using this
|
||||
* function or one of the NS_LIST_INIT()-type macros before use. A zero-initialised
|
||||
* list head is *not* valid.
|
||||
*
|
||||
* If used on a list containing existing entries, those entries will
|
||||
* become detached. (They are not modified, but their links are now effectively
|
||||
* undefined).
|
||||
*
|
||||
* \param list Pointer to a NS_LIST_HEAD() structure.
|
||||
*/
|
||||
#define ns_list_init(list) ns_list_init_(&(list)->slist)
|
||||
|
||||
/** \brief Initialiser for an empty list
|
||||
*
|
||||
* Usage in an enclosing initialiser:
|
||||
* ~~~
|
||||
* static my_type_including_list_t x = {
|
||||
* "Something",
|
||||
* 23,
|
||||
* NS_LIST_INIT(x),
|
||||
* };
|
||||
* ~~~
|
||||
* NS_LIST_DEFINE() or NS_LIST_NAME_INIT() may provide a shorter alternative
|
||||
* in simpler cases.
|
||||
*/
|
||||
#define NS_LIST_INIT(name) { { NULL, &(name).slist.first_entry } }
|
||||
|
||||
/** \brief Name and initialiser for an empty list
|
||||
*
|
||||
* Usage:
|
||||
* ~~~
|
||||
* list_t NS_LIST_NAME_INIT(foo);
|
||||
* ~~~
|
||||
* acts as
|
||||
* ~~~
|
||||
* list_t foo = { empty list };
|
||||
* ~~~
|
||||
* Also useful with designated initialisers:
|
||||
* ~~~
|
||||
* .NS_LIST_NAME_INIT(foo),
|
||||
* ~~~
|
||||
* acts as
|
||||
* ~~~
|
||||
* .foo = { empty list },
|
||||
* ~~~
|
||||
*/
|
||||
#define NS_LIST_NAME_INIT(name) name = NS_LIST_INIT(name)
|
||||
|
||||
/** \brief Define a list, and initialise to empty.
|
||||
*
|
||||
* Usage:
|
||||
* ~~~
|
||||
* static NS_LIST_DEFINE(my_list, entry_t, link);
|
||||
* ~~~
|
||||
* acts as
|
||||
* ~~~
|
||||
* static list_type my_list = { empty list };
|
||||
* ~~~
|
||||
*/
|
||||
#define NS_LIST_DEFINE(name, type, field) \
|
||||
NS_LIST_HEAD(type, field) NS_LIST_NAME_INIT(name)
|
||||
|
||||
/** \hideinitializer \brief Add an entry to the start of the linked list.
|
||||
*
|
||||
* ns_list_add_to_end() is *slightly* more efficient than ns_list_add_to_start().
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
|
||||
*/
|
||||
#define ns_list_add_to_start(list, entry) \
|
||||
ns_list_add_to_start_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
|
||||
|
||||
/** \hideinitializer \brief Add an entry to the end of the linked list.
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
|
||||
*/
|
||||
#define ns_list_add_to_end(list, entry) \
|
||||
ns_list_add_to_end_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
|
||||
|
||||
/** \hideinitializer \brief Add an entry before a specified entry.
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param before `(entry_t *)` Existing entry before which to place the new entry.
|
||||
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
|
||||
*/
|
||||
#define ns_list_add_before(list, before, entry) \
|
||||
ns_list_add_before_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, before), NS_LIST_TYPECHECK_(list, entry))
|
||||
|
||||
/** \hideinitializer \brief Add an entry after a specified entry.
|
||||
*
|
||||
* ns_list_add_before() is *slightly* more efficient than ns_list_add_after().
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param after `(entry_t *)` Existing entry after which to place the new entry.
|
||||
* \param entry `(entry_t * restrict)` Pointer to new entry to add.
|
||||
*/
|
||||
#define ns_list_add_after(list, after, entry) \
|
||||
ns_list_add_after_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, after), NS_LIST_TYPECHECK_(list, entry))
|
||||
|
||||
/** \brief Check if a list is empty.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
*
|
||||
* \return `(bool)` true if the list is empty.
|
||||
*/
|
||||
#define ns_list_is_empty(list) ((bool) ((list)->slist.first_entry == NULL))
|
||||
|
||||
/** \brief Get the first entry.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
*
|
||||
* \return `(entry_t *)` Pointer to first entry.
|
||||
* \return NULL if list is empty.
|
||||
*/
|
||||
#define ns_list_get_first(list) NS_LIST_TYPECAST_(list, (list)->slist.first_entry)
|
||||
|
||||
/** \hideinitializer \brief Get the previous entry.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
* \param current `(const entry_t *)` Pointer to current entry.
|
||||
*
|
||||
* \return `(entry_t *)` Pointer to previous entry.
|
||||
* \return NULL if current entry is first.
|
||||
*/
|
||||
#define ns_list_get_previous(list, current) \
|
||||
NS_LIST_TYPECAST_(list, ns_list_get_previous_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
|
||||
|
||||
/** \hideinitializer \brief Get the next entry.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
* \param current `(const entry_t *)` Pointer to current entry.
|
||||
*
|
||||
* \return `(entry_t *)` Pointer to next entry.
|
||||
* \return NULL if current entry is last.
|
||||
*/
|
||||
#define ns_list_get_next(list, current) \
|
||||
NS_LIST_TYPECAST_(list, ns_list_get_next_(NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current)))
|
||||
|
||||
/** \hideinitializer \brief Get the last entry.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
*
|
||||
* \return `(entry_t *)` Pointer to last entry.
|
||||
* \return NULL if list is empty.
|
||||
*/
|
||||
#define ns_list_get_last(list) \
|
||||
NS_LIST_TYPECAST_(list, ns_list_get_last_(&(list)->slist, NS_LIST_OFFSET_(list)))
|
||||
|
||||
/** \hideinitializer \brief Remove an entry.
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param entry `(entry_t *)` Entry on list to be removed.
|
||||
*/
|
||||
#define ns_list_remove(list, entry) \
|
||||
ns_list_remove_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, entry))
|
||||
|
||||
/** \hideinitializer \brief Replace an entry.
|
||||
*
|
||||
* \param list `(list_t *)` Pointer to list.
|
||||
* \param current `(entry_t *)` Existing entry on list to be replaced.
|
||||
* \param replacement `(entry_t * restrict)` New entry to be the replacement.
|
||||
*/
|
||||
#define ns_list_replace(list, current, replacement) \
|
||||
ns_list_replace_(&(list)->slist, NS_LIST_OFFSET_(list), NS_LIST_TYPECHECK_(list, current), NS_LIST_TYPECHECK_(list, replacement))
|
||||
|
||||
/** \hideinitializer \brief Concatenate two lists.
|
||||
*
|
||||
* Attach the entries on the source list to the end of the destination
|
||||
* list, leaving the source list empty.
|
||||
*
|
||||
* \param dst `(list_t *)` Pointer to destination list.
|
||||
* \param src `(list_t *)` Pointer to source list.
|
||||
*
|
||||
*/
|
||||
#define ns_list_concatenate(dst, src) \
|
||||
(NS_PTR_MATCH_(dst, src, "concatenating different list types"), \
|
||||
ns_list_concatenate_(&(dst)->slist, &(src)->slist, NS_LIST_OFFSET_(src)))
|
||||
|
||||
/** \brief Iterate forwards over a list.
|
||||
*
|
||||
* Example:
|
||||
* ~~~
|
||||
* ns_list_foreach(const my_entry_t, cur, &my_list)
|
||||
* {
|
||||
* printf("%s\n", cur->name);
|
||||
* }
|
||||
* ~~~
|
||||
* Deletion of the current entry is not permitted as its next is checked after
|
||||
* running user code.
|
||||
*
|
||||
* The iteration pointer is declared inside the loop, using C99/C++, so it
|
||||
* is not accessible after the loop. This encourages good code style, and
|
||||
* matches the semantics of C++11's "ranged for", which only provides the
|
||||
* declaration form:
|
||||
* ~~~
|
||||
* for (const my_entry_t cur : my_list)
|
||||
* ~~~
|
||||
* If you need to see the value of the iteration pointer after a `break`,
|
||||
* you will need to assign it to a variable declared outside the loop before
|
||||
* breaking:
|
||||
* ~~~
|
||||
* my_entry_t *match = NULL;
|
||||
* ns_list_foreach(my_entry_t, cur, &my_list)
|
||||
* {
|
||||
* if (cur->id == id)
|
||||
* {
|
||||
* match = cur;
|
||||
* break;
|
||||
* }
|
||||
* }
|
||||
* ~~~
|
||||
*
|
||||
* The user has to specify the entry type for the pointer definition, as type
|
||||
* extraction from the list argument isn't portable. On the other hand, this
|
||||
* also permits const qualifiers, as in the example above, and serves as
|
||||
* documentation. The entry type will be checked against the list type where the
|
||||
* compiler supports it.
|
||||
*
|
||||
* \param type Entry type `([const] entry_t)`.
|
||||
* \param e Name for iteration pointer to be defined
|
||||
* inside the loop.
|
||||
* \param list `(const list_t *)` Pointer to list - evaluated multiple times.
|
||||
*/
|
||||
#define ns_list_foreach(type, e, list) \
|
||||
for (type *e = NS_LIST_TYPECOERCE(type *, ns_list_get_first(list)); \
|
||||
e; e = NS_LIST_TYPECOERCE(type *, ns_list_get_next(list, e)))
|
||||
|
||||
/** \brief Iterate forwards over a list, where user may delete.
|
||||
*
|
||||
* As ns_list_foreach(), but deletion of current entry is permitted as its
|
||||
* next pointer is recorded before running user code.
|
||||
*
|
||||
* Example:
|
||||
* ~~~
|
||||
* ns_list_foreach_safe(my_entry_t, cur, &my_list)
|
||||
* {
|
||||
* ns_list_remove(cur);
|
||||
* }
|
||||
* ~~~
|
||||
* \param type Entry type `(entry_t)`.
|
||||
* \param e Name for iteration pointer to be defined
|
||||
* inside the loop.
|
||||
* \param list `(list_t *)` Pointer to list - evaluated multiple times.
|
||||
*/
|
||||
#define ns_list_foreach_safe(type, e, list) \
|
||||
for (type *e = NS_LIST_TYPECOERCE(type *, ns_list_get_first(list)), *_next##e; \
|
||||
e && (_next##e = NS_LIST_TYPECOERCE(type *, ns_list_get_next(list, e)), true); e = _next##e)
|
||||
|
||||
/** \brief Iterate backwards over a list.
|
||||
*
|
||||
* As ns_list_foreach(), but going backwards - see its documentation.
|
||||
* Iterating forwards is *slightly* more efficient.
|
||||
*/
|
||||
#define ns_list_foreach_reverse(type, e, list) \
|
||||
for (type *e = NS_LIST_TYPECOERCE(type *, ns_list_get_last(list)); \
|
||||
e; e = NS_LIST_TYPECOERCE(type *, ns_list_get_previous(list, e)))
|
||||
|
||||
/** \brief Iterate backwards over a list, where user may delete.
|
||||
*
|
||||
* As ns_list_foreach_safe(), but going backwards - see its documentation.
|
||||
* Iterating forwards is *slightly* more efficient.
|
||||
*/
|
||||
#define ns_list_foreach_reverse_safe(type, e, list) \
|
||||
for (type *e = NS_LIST_TYPECOERCE(type *, ns_list_get_last(list)), *_next##e; \
|
||||
e && (_next##e = NS_LIST_TYPECOERCE(type *, ns_list_get_previous(list, e)), true); e = _next##e)
|
||||
|
||||
/** \hideinitializer \brief Count entries on a list
|
||||
*
|
||||
* Unlike other operations, this is O(n). Note: if list might contain over
|
||||
* 65535 entries, this function **must not** be used to get the entry count.
|
||||
*
|
||||
* \param list `(const list_t *)` Pointer to list.
|
||||
|
||||
* \return `(uint_fast16_t)` Number of entries that are stored in list.
|
||||
*/
|
||||
#define ns_list_count(list) ns_list_count_(&(list)->slist, NS_LIST_OFFSET_(list))
|
||||
|
||||
/** \privatesection
|
||||
* Internal functions - designed to be accessed using corresponding macros above
|
||||
*/
|
||||
NS_INLINE void ns_list_init_(ns_list_t *list);
|
||||
NS_INLINE void ns_list_link_init_(ns_list_link_t *link);
|
||||
NS_INLINE void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
|
||||
NS_INLINE void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t link_offset, void *restrict entry);
|
||||
NS_INLINE void ns_list_add_before_(ns_list_offset_t link_offset, void *before, void *restrict entry);
|
||||
NS_INLINE void ns_list_add_after_(ns_list_t *list, ns_list_offset_t link_offset, void *after, void *restrict entry);
|
||||
NS_INLINE void *ns_list_get_next_(ns_list_offset_t link_offset, const void *current);
|
||||
NS_INLINE void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t link_offset, const void *current);
|
||||
NS_INLINE void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset);
|
||||
NS_INLINE void ns_list_remove_(ns_list_t *list, ns_list_offset_t link_offset, void *entry);
|
||||
NS_INLINE void ns_list_replace_(ns_list_t *list, ns_list_offset_t link_offset, void *current, void *restrict replacement);
|
||||
NS_INLINE void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset);
|
||||
NS_INLINE uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t link_offset);
|
||||
|
||||
/* Provide definitions, either for inlining, or for ns_list.c */
|
||||
#if defined NS_ALLOW_INLINING || defined NS_LIST_FN
|
||||
#ifndef NS_LIST_FN
|
||||
#define NS_LIST_FN NS_INLINE
|
||||
#endif
|
||||
|
||||
/* Pointer to the link member in entry e */
|
||||
#define NS_LIST_LINK_(e, offset) ((ns_list_link_t *)((char *)(e) + offset))
|
||||
|
||||
/* Lvalue of the next link pointer in entry e */
|
||||
#define NS_LIST_NEXT_(e, offset) (NS_LIST_LINK_(e, offset)->next)
|
||||
|
||||
/* Lvalue of the prev link pointer in entry e */
|
||||
#define NS_LIST_PREV_(e, offset) (NS_LIST_LINK_(e, offset)->prev)
|
||||
|
||||
/* Convert a pointer to a link member back to the entry;
|
||||
* works for linkptr either being a ns_list_link_t pointer, or its next pointer,
|
||||
* as the next pointer is first in the ns_list_link_t */
|
||||
#define NS_LIST_ENTRY_(linkptr, offset) ((void *)((char *)(linkptr) - offset))
|
||||
|
||||
NS_LIST_FN void ns_list_init_(ns_list_t *list)
|
||||
{
|
||||
list->first_entry = NULL;
|
||||
list->last_nextptr = &list->first_entry;
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_link_init_(ns_list_link_t *link)
|
||||
{
|
||||
NS_FUNNY_INTPTR_OK
|
||||
link->next = NS_LIST_POISON;
|
||||
link->prev = NS_LIST_POISON;
|
||||
NS_FUNNY_INTPTR_RESTORE
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_add_to_start_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
|
||||
{
|
||||
void *next;
|
||||
|
||||
NS_LIST_PREV_(entry, offset) = &list->first_entry;
|
||||
NS_LIST_NEXT_(entry, offset) = next = list->first_entry;
|
||||
|
||||
if (next) {
|
||||
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
|
||||
} else {
|
||||
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
|
||||
}
|
||||
|
||||
list->first_entry = entry;
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_add_after_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict entry)
|
||||
{
|
||||
void *next;
|
||||
|
||||
NS_LIST_PREV_(entry, offset) = &NS_LIST_NEXT_(current, offset);
|
||||
NS_LIST_NEXT_(entry, offset) = next = NS_LIST_NEXT_(current, offset);
|
||||
|
||||
if (next) {
|
||||
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(entry, offset);
|
||||
} else {
|
||||
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
|
||||
}
|
||||
|
||||
NS_LIST_NEXT_(current, offset) = entry;
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_add_before_(ns_list_offset_t offset, void *current, void *restrict entry)
|
||||
{
|
||||
void **prev_nextptr;
|
||||
|
||||
NS_LIST_NEXT_(entry, offset) = current;
|
||||
NS_LIST_PREV_(entry, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
|
||||
*prev_nextptr = entry;
|
||||
NS_LIST_PREV_(current, offset) = &NS_LIST_NEXT_(entry, offset);
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_add_to_end_(ns_list_t *list, ns_list_offset_t offset, void *restrict entry)
|
||||
{
|
||||
void **prev_nextptr;
|
||||
|
||||
NS_LIST_NEXT_(entry, offset) = NULL;
|
||||
NS_LIST_PREV_(entry, offset) = prev_nextptr = list->last_nextptr;
|
||||
*prev_nextptr = entry;
|
||||
list->last_nextptr = &NS_LIST_NEXT_(entry, offset);
|
||||
}
|
||||
|
||||
NS_LIST_FN void *ns_list_get_next_(ns_list_offset_t offset, const void *current)
|
||||
{
|
||||
return NS_LIST_NEXT_(current, offset);
|
||||
}
|
||||
|
||||
NS_LIST_FN void *ns_list_get_previous_(const ns_list_t *list, ns_list_offset_t offset, const void *current)
|
||||
{
|
||||
if (current == list->first_entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Tricky. We don't have a direct previous pointer, but a pointer to the
|
||||
// pointer that points to us - ie &head->first_entry OR &{prev}->next.
|
||||
// This makes life easier on insertion and removal, but this is where we
|
||||
// pay the price.
|
||||
|
||||
// We have to check manually for being the first entry above, so we know it's
|
||||
// a real link's next pointer. Then next is the first field of
|
||||
// ns_list_link_t, so we can use the normal offset value.
|
||||
|
||||
return NS_LIST_ENTRY_(NS_LIST_PREV_(current, offset), offset);
|
||||
}
|
||||
|
||||
NS_LIST_FN void *ns_list_get_last_(const ns_list_t *list, ns_list_offset_t offset)
|
||||
{
|
||||
if (!list->first_entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// See comments in ns_list_get_previous_()
|
||||
return NS_LIST_ENTRY_(list->last_nextptr, offset);
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_remove_(ns_list_t *list, ns_list_offset_t offset, void *removed)
|
||||
{
|
||||
void *next;
|
||||
void **prev_nextptr;
|
||||
|
||||
next = NS_LIST_NEXT_(removed, offset);
|
||||
prev_nextptr = NS_LIST_PREV_(removed, offset);
|
||||
if (next) {
|
||||
NS_LIST_PREV_(next, offset) = prev_nextptr;
|
||||
} else {
|
||||
list->last_nextptr = prev_nextptr;
|
||||
}
|
||||
*prev_nextptr = next;
|
||||
|
||||
ns_list_link_init_(NS_LIST_LINK_(removed, offset));
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_replace_(ns_list_t *list, ns_list_offset_t offset, void *current, void *restrict replacement)
|
||||
{
|
||||
void *next;
|
||||
void **prev_nextptr;
|
||||
|
||||
NS_LIST_PREV_(replacement, offset) = prev_nextptr = NS_LIST_PREV_(current, offset);
|
||||
NS_LIST_NEXT_(replacement, offset) = next = NS_LIST_NEXT_(current, offset);
|
||||
|
||||
if (next) {
|
||||
NS_LIST_PREV_(next, offset) = &NS_LIST_NEXT_(replacement, offset);
|
||||
} else {
|
||||
list->last_nextptr = &NS_LIST_NEXT_(replacement, offset);
|
||||
}
|
||||
*prev_nextptr = replacement;
|
||||
|
||||
ns_list_link_init_(NS_LIST_LINK_(current, offset));
|
||||
}
|
||||
|
||||
NS_LIST_FN void ns_list_concatenate_(ns_list_t *dst, ns_list_t *src, ns_list_offset_t offset)
|
||||
{
|
||||
ns_list_link_t *src_first;
|
||||
|
||||
src_first = src->first_entry;
|
||||
if (!src_first) {
|
||||
return;
|
||||
}
|
||||
|
||||
*dst->last_nextptr = src_first;
|
||||
NS_LIST_PREV_(src_first, offset) = dst->last_nextptr;
|
||||
dst->last_nextptr = src->last_nextptr;
|
||||
|
||||
ns_list_init_(src);
|
||||
}
|
||||
|
||||
NS_LIST_FN uint_fast16_t ns_list_count_(const ns_list_t *list, ns_list_offset_t offset)
|
||||
{
|
||||
uint_fast16_t count = 0;
|
||||
|
||||
for (void *p = list->first_entry; p; p = NS_LIST_NEXT_(p, offset)) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif /* defined NS_ALLOW_INLINING || defined NS_LIST_FN */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NS_LIST_H_ */
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2016-2017 ARM Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* NanoStack NVM helper functions to read, write and delete key-value pairs to platform NVM.
|
||||
*
|
||||
* Client can use following methods:
|
||||
* -ns_nvm_data_write to write data to a key in platform NVM
|
||||
* -ns_nvm_data_read to read data from key in platform NVM
|
||||
* -ns_nvm_key_delete to delete a key from platform NVM
|
||||
*
|
||||
* If a API call returns NS_NVM_OK then a provided callback function will be called
|
||||
* and status argument indicates success or failure of the operation. If API call
|
||||
* returns error then callback will not be called.
|
||||
*
|
||||
* When client writes data this module will:
|
||||
* -initialize the NVM if not already initialized
|
||||
* -(re)create the key with a given size
|
||||
* -write data to the key
|
||||
* -flush data to the NVM
|
||||
*
|
||||
* When client reads data this module will:
|
||||
* -initialize the NVM if not initialized
|
||||
* -read data from the key
|
||||
*
|
||||
* When client deletes a key this module will:
|
||||
* -initialize the NVM if not initialized
|
||||
* -delete the key from NVM
|
||||
*/
|
||||
|
||||
/*
|
||||
* API function and callback function return statuses
|
||||
*/
|
||||
#define NS_NVM_OK 0
|
||||
#define NS_NVM_DATA_NOT_FOUND -1
|
||||
#define NS_NVM_ERROR -2
|
||||
#define NS_NVM_MEMORY -3
|
||||
|
||||
/**
|
||||
* callback type for NanoStack NVM
|
||||
*/
|
||||
typedef void (ns_nvm_callback)(int status, void *context);
|
||||
|
||||
/**
|
||||
* \brief Delete key from NVM
|
||||
*
|
||||
* \param callback function to be called when key deletion is ready
|
||||
* \param key_name Name of the key to be deleted from NVM
|
||||
* \param context argument will be provided as an argument when callback is called
|
||||
*
|
||||
* \return NS_NVM_OK if key deletion is in progress and callback will be called
|
||||
* \return NS_NVM_ERROR in error case, callback will not be called
|
||||
* \return provided callback function will be called with status indicating success or failure.
|
||||
*/
|
||||
int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context);
|
||||
|
||||
/**
|
||||
* \brief Read data from NVM
|
||||
*
|
||||
* \param callback function to be called when data is read
|
||||
* \param key_name Name of the key whose data will be read
|
||||
* \param buf buffer where data will be stored
|
||||
* \param buf_len address of variable containing provided buffer length
|
||||
* \param context argument will be provided as an argument when callback is called
|
||||
*
|
||||
* \return NS_NVM_OK if read is in progress and callback will be called
|
||||
* \return NS_NVM_ERROR in error case, callback will not be called
|
||||
* \return provided callback function will be called with status indicating success or failure.
|
||||
*/
|
||||
int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context);
|
||||
|
||||
/**
|
||||
* \brief Write data to NVM
|
||||
*
|
||||
* \param callback function to be called when data writing is completed
|
||||
* \param key_name Name of the key whose data will be read
|
||||
* \param buf buffer where data will be stored
|
||||
* \param buf_len address of variable containing provided buffer length
|
||||
* \param context argument will be provided as an argument when callback is called
|
||||
*
|
||||
* \return NS_NVM_OK if read is in progress and callback will be called
|
||||
* \return NS_NVM_ERROR in error case, callback will not be called
|
||||
* \return provided callback function will be called with status indicating success or failure.
|
||||
*/
|
||||
int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context);
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2017 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file ns_trace.h
|
||||
* Trace interface abstraction for NanoStack library as well as application.
|
||||
*
|
||||
* Actual used trace library is mbed-trace. For usage details check mbed_trace.h.
|
||||
*
|
||||
*/
|
||||
#ifndef NS_TRACE_H_
|
||||
#define NS_TRACE_H_
|
||||
|
||||
#if defined(HAVE_DEBUG) && !defined(FEA_TRACE_SUPPORT)
|
||||
#define FEA_TRACE_SUPPORT
|
||||
#endif
|
||||
|
||||
#include "ns_types.h"
|
||||
#include "mbed-trace/mbed_trace.h"
|
||||
|
||||
#endif /* NS_TRACE_H_ */
|
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* ns_types.h - Basic compiler and type setup for Nanostack libraries.
|
||||
*/
|
||||
#ifndef NS_TYPES_H_
|
||||
#define NS_TYPES_H_
|
||||
|
||||
/** \file
|
||||
* \brief Basic compiler and type setup
|
||||
*
|
||||
* We currently assume C99 or later.
|
||||
*
|
||||
* C99 features being relied on:
|
||||
*
|
||||
* - <inttypes.h> and <stdbool.h>
|
||||
* - inline (with C99 semantics, not C++ as per default GCC);
|
||||
* - designated initialisers;
|
||||
* - compound literals;
|
||||
* - restrict;
|
||||
* - [static N] in array parameters;
|
||||
* - declarations in for statements;
|
||||
* - mixing declarations and statements
|
||||
*
|
||||
* Compilers should be set to C99 or later mode when building Nanomesh source.
|
||||
* For GCC this means "-std=gnu99" (C99 with usual GNU extensions).
|
||||
*
|
||||
* Also, a little extra care is required for public header files that could be
|
||||
* included from C++, especially as C++ lacks some C99 features.
|
||||
*
|
||||
* (TODO: as this is exposed to API users, do we need a predefine to distinguish
|
||||
* internal and external use, for finer control? Not yet, but maybe...)
|
||||
*/
|
||||
|
||||
/* Make sure <stdint.h> defines its macros if C++ */
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS
|
||||
#endif
|
||||
#ifndef __STDC_CONSTANT_MACROS
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h> // includes <stdint.h>; debugf() users need PRIu32 etc
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Create the optional <stdint.h> 24-bit types if they don't exist (worth trying
|
||||
* to use them, as they could exist and be more efficient than 32-bit on 8-bit
|
||||
* systems...)
|
||||
*/
|
||||
#ifndef UINT_LEAST24_MAX
|
||||
typedef uint_least32_t uint_least24_t;
|
||||
#define UINT_LEAST24_MAX UINT_LEAST32_MAX
|
||||
#define UINT24_C(x) UINT32_C(x)
|
||||
#define PRIoLEAST24 PRIoLEAST32
|
||||
#define PRIuLEAST24 PRIuLEAST32
|
||||
#define PRIxLEAST24 PRIxLEAST32
|
||||
#define PRIXLEAST24 PRIXLEAST32
|
||||
#endif
|
||||
|
||||
#ifndef INT_LEAST24_MAX
|
||||
typedef int_least32_t int_least24_t;
|
||||
#define INT_LEAST24_MIN INT_LEAST32_MIN
|
||||
#define INT_LEAST24_MAX INT_LEAST32_MAX
|
||||
#define INT24_C(x) INT32_C(x)
|
||||
#define PRIdLEAST24 PRIdLEAST32
|
||||
#define PRIiLEAST24 PRIiLEAST32
|
||||
#endif
|
||||
|
||||
#ifndef UINT_FAST24_MAX
|
||||
typedef uint_fast32_t uint_fast24_t;
|
||||
#define UINT_FAST24_MAX UINT_FAST32_MAX
|
||||
#define PRIoFAST24 PRIoFAST32
|
||||
#define PRIuFAST24 PRIuFAST32
|
||||
#define PRIxFAST24 PRIxFAST32
|
||||
#define PRIXFAST24 PRIXFAST32
|
||||
#endif
|
||||
|
||||
#ifndef INT_FAST24_MAX
|
||||
typedef int_fast32_t int_fast24_t;
|
||||
#define INT_FAST24_MIN INT_FAST32_MIN
|
||||
#define INT_FAST24_MAX INT_FAST32_MAX
|
||||
#define PRIdFAST24 PRIdFAST32
|
||||
#define PRIiFAST24 PRIiFAST32
|
||||
#endif
|
||||
|
||||
/* Function attribute - C11 "noreturn" or C++11 "[[noreturn]]" */
|
||||
#ifndef NS_NORETURN
|
||||
#if defined __cplusplus && __cplusplus >= 201103L
|
||||
#define NS_NORETURN [[noreturn]]
|
||||
#elif !defined __cplusplus && __STDC_VERSION__ >= 201112L
|
||||
#define NS_NORETURN _Noreturn
|
||||
#elif defined __GNUC__
|
||||
#define NS_NORETURN __attribute__((__noreturn__))
|
||||
#elif defined __IAR_SYSTEMS_ICC__
|
||||
#define NS_NORETURN __noreturn
|
||||
#else
|
||||
#define NS_NORETURN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* C11's "alignas" macro, emulated for integer expressions if necessary */
|
||||
#ifndef __alignas_is_defined
|
||||
#if defined __TASKING__
|
||||
#define alignas(n) __align(n)
|
||||
#define __alignas_is_defined 1
|
||||
#elif (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L)
|
||||
# if defined __ARMCC_VERSION && __ARMCC_VERSION < 6120000
|
||||
/* Workaround for Arm Compiler versions prior to 6.12 */
|
||||
# if !defined __cplusplus
|
||||
# define alignas _Alignas
|
||||
# endif
|
||||
# define __alignas_is_defined 1
|
||||
# else
|
||||
# include <stdalign.h>
|
||||
# endif
|
||||
#elif defined __GNUC__
|
||||
#define alignas(n) __attribute__((__aligned__(n)))
|
||||
#define __alignas_is_defined 1
|
||||
#elif defined __IAR_SYSTEMS_ICC__
|
||||
/* Does this really just apply to the next variable? */
|
||||
#define alignas(n) __Alignas(data_alignment=n)
|
||||
#define __Alignas(x) _Pragma(#x)
|
||||
#define __alignas_is_defined 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Marker for functions or objects that may be unused, suppressing warnings.
|
||||
* Place after the identifier:
|
||||
* ~~~
|
||||
* static int X MAYBE_UNUSED = 3;
|
||||
* static int foo(void) MAYBE_UNUSED;
|
||||
* ~~~
|
||||
*/
|
||||
#if defined __GNUC__
|
||||
#define MAYBE_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define MAYBE_UNUSED
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C++ (even C++11) doesn't provide restrict: define away or provide
|
||||
* alternative.
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#ifdef __GNUC__
|
||||
#define restrict __restrict
|
||||
#else
|
||||
#define restrict
|
||||
#endif
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
/**
|
||||
* C++ doesn't allow "static" in function parameter types: ie
|
||||
* ~~~
|
||||
* entry_t *find_entry(const uint8_t address[static 16])
|
||||
* ~~~
|
||||
* If a header file may be included from C++, use this __static define instead.
|
||||
*
|
||||
* (Syntax introduced in C99 - `uint8_t address[16]` in a prototype was always
|
||||
* equivalent to `uint8_t *address`, but the C99 addition of static tells the
|
||||
* compiler that address is never NULL, and always points to at least 16
|
||||
* elements. This adds no new type-checking, but the information could aid
|
||||
* compiler optimisation, and it can serve as documentation).
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define __static
|
||||
#else
|
||||
#define __static static
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define NS_GCC_VERSION (__GNUC__ * 10000 \
|
||||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#endif
|
||||
|
||||
/** \brief Compile-time assertion
|
||||
*
|
||||
* C11 provides _Static_assert, as does GCC even in C99 mode (and
|
||||
* as a freestanding implementation, we can't rely on <assert.h> to get
|
||||
* the static_assert macro).
|
||||
* C++11 provides static_assert as a keyword, as does G++ in C++0x mode.
|
||||
*
|
||||
* The assertion acts as a declaration that can be placed at file scope, in a
|
||||
* code block (except after a label), or as a member of a struct/union. It
|
||||
* produces a compiler error if "test" evaluates to 0.
|
||||
*
|
||||
* Note that this *includes* the required semicolon when defined, else it
|
||||
* is totally empty, permitting use in structs. (If the user provided the `;`,
|
||||
* it would leave an illegal stray `;` if unavailable).
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
# if __cplusplus >= 201103L || __cpp_static_assert >= 200410
|
||||
# define NS_STATIC_ASSERT(test, str) static_assert(test, str);
|
||||
# elif defined __GXX_EXPERIMENTAL_CXX0X__ && NS_GCC_VERSION >= 40300
|
||||
# define NS_STATIC_ASSERT(test, str) __extension__ static_assert(test, str);
|
||||
# else
|
||||
# define NS_STATIC_ASSERT(test, str)
|
||||
# endif
|
||||
#else /* C */
|
||||
# if __STDC_VERSION__ >= 201112L
|
||||
# define NS_STATIC_ASSERT(test, str) _Static_assert(test, str);
|
||||
# elif defined __GNUC__ && NS_GCC_VERSION >= 40600
|
||||
# ifdef _Static_assert
|
||||
/*
|
||||
* Some versions of glibc cdefs.h (which comes in via <stdint.h> above)
|
||||
* attempt to define their own _Static_assert (if GCC < 4.6 or
|
||||
* __STRICT_ANSI__) using an extern declaration, which doesn't work in a
|
||||
* struct/union.
|
||||
*
|
||||
* For GCC >= 4.6 and __STRICT_ANSI__, we can do better - just use
|
||||
* the built-in _Static_assert with __extension__. We have to do this, as
|
||||
* ns_list.h needs to use it in a union. No way to get at it though, without
|
||||
* overriding their define.
|
||||
*/
|
||||
# undef _Static_assert
|
||||
# define _Static_assert(x, y) __extension__ _Static_assert(x, y)
|
||||
# endif
|
||||
# define NS_STATIC_ASSERT(test, str) __extension__ _Static_assert(test, str);
|
||||
# else
|
||||
# define NS_STATIC_ASSERT(test, str)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** \brief Pragma to suppress warnings about unusual pointer values.
|
||||
*
|
||||
* Useful if using "poison" values.
|
||||
*/
|
||||
#ifdef __IAR_SYSTEMS_ICC__
|
||||
#define NS_FUNNY_INTPTR_OK _Pragma("diag_suppress=Pe1053")
|
||||
#define NS_FUNNY_INTPTR_RESTORE _Pragma("diag_default=Pe1053")
|
||||
#else
|
||||
#define NS_FUNNY_INTPTR_OK
|
||||
#define NS_FUNNY_INTPTR_RESTORE
|
||||
#endif
|
||||
|
||||
/** \brief Pragma to suppress warnings about always true/false comparisons
|
||||
*/
|
||||
#if defined __GNUC__ && NS_GCC_VERSION >= 40600
|
||||
#define NS_FUNNY_COMPARE_OK _Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"")
|
||||
#define NS_FUNNY_COMPARE_RESTORE _Pragma("GCC diagnostic pop")
|
||||
#else
|
||||
#define NS_FUNNY_COMPARE_OK
|
||||
#define NS_FUNNY_COMPARE_RESTORE
|
||||
#endif
|
||||
|
||||
/** \brief Pragma to suppress warnings arising from dummy definitions.
|
||||
*
|
||||
* Useful when you have function-like macros that returning constants
|
||||
* in cut-down builds. Can be fairly cavalier about disabling as we
|
||||
* do not expect every build to use this macro. Generic builds of
|
||||
* components should ensure this is not included by only using it in
|
||||
* a ifdef blocks providing dummy definitions.
|
||||
*/
|
||||
#if defined __IAR_SYSTEMS_ICC__
|
||||
// controlling expression is constant
|
||||
#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=Pe236")
|
||||
#else
|
||||
#define NS_DUMMY_DEFINITIONS_OK
|
||||
#endif
|
||||
|
||||
/** \brief Convert pointer to member to pointer to containing structure */
|
||||
#define NS_CONTAINER_OF(ptr, type, member) \
|
||||
((type *) ((char *) (ptr) - offsetof(type, member)))
|
||||
|
||||
/*
|
||||
* Inlining could cause problems when mixing with C++; provide a mechanism to
|
||||
* disable it. This could also be turned off for other reasons (although
|
||||
* this can usually be done through a compiler flag, eg -O0 on gcc).
|
||||
*/
|
||||
#ifndef __cplusplus
|
||||
#define NS_ALLOW_INLINING
|
||||
#endif
|
||||
|
||||
/* There is inlining problem in GCC version 4.1.x and we know it works in 4.6.3 */
|
||||
#if defined __GNUC__ && NS_GCC_VERSION < 40600
|
||||
#undef NS_ALLOW_INLINING
|
||||
#endif
|
||||
|
||||
/** \brief Mark a potentially-inlineable function.
|
||||
*
|
||||
* We follow C99 semantics, which requires precisely one external definition.
|
||||
* To also allow inlining to be totally bypassed under control of
|
||||
* NS_ALLOW_INLINING, code can be structured as per the example of ns_list:
|
||||
*
|
||||
* foo.h
|
||||
* -----
|
||||
* ~~~
|
||||
* NS_INLINE int my_func(int);
|
||||
*
|
||||
* #if defined NS_ALLOW_INLINING || defined FOO_FN
|
||||
* #ifndef FOO_FN
|
||||
* #define FOO_FN NS_INLINE
|
||||
* #endif
|
||||
* FOO_FN int my_func(int a)
|
||||
* {
|
||||
* definition;
|
||||
* }
|
||||
* #endif
|
||||
* ~~~
|
||||
* foo.c
|
||||
* -----
|
||||
* ~~~
|
||||
* #define FOO_FN extern
|
||||
* #include "foo.h"
|
||||
* ~~~
|
||||
* Which generates:
|
||||
* ~~~
|
||||
* NS_ALLOW_INLINING set NS_ALLOW_INLINING unset
|
||||
* ===================== =======================
|
||||
* Include foo.h Include foo.h
|
||||
* ------------- -------------
|
||||
* inline int my_func(int); int my_func(int);
|
||||
*
|
||||
* // inline definition
|
||||
* inline int my_func(int a)
|
||||
* {
|
||||
* definition;
|
||||
* }
|
||||
*
|
||||
* Compile foo.c Compile foo.c
|
||||
* ------------- -------------
|
||||
* (from .h) inline int my_func(int); int my_func(int);
|
||||
*
|
||||
* // external definition
|
||||
* // because of no "inline" // normal external definition
|
||||
* extern int my_func(int a) extern int my_func(int a)
|
||||
* { {
|
||||
* definition; definition;
|
||||
* } }
|
||||
* ~~~
|
||||
*
|
||||
* Note that even with inline keywords, whether the compiler inlines or not is
|
||||
* up to it. For example, gcc at "-O0" will not inline at all, and will always
|
||||
* call the real functions in foo.o, just as if NS_ALLOW_INLINING was unset.
|
||||
* At "-O2", gcc could potentially inline everything, meaning that foo.o is not
|
||||
* referenced at all.
|
||||
*
|
||||
* Alternatively, you could use "static inline", which gives every caller its
|
||||
* own internal definition. This is compatible with C++ inlining (which expects
|
||||
* the linker to eliminate duplicates), but in C it's less efficient if the code
|
||||
* ends up non-inlined, and it's harder to breakpoint. I don't recommend it
|
||||
* except for the most trivial functions (which could then probably be macros).
|
||||
*/
|
||||
#ifdef NS_ALLOW_INLINING
|
||||
#define NS_INLINE inline
|
||||
#else
|
||||
#define NS_INLINE
|
||||
#endif
|
||||
|
||||
#if defined __SDCC_mcs51 || defined __ICC8051__ || defined __C51__
|
||||
|
||||
/* The 8051 environments: SDCC (historic), IAR (current), Keil (future?) */
|
||||
|
||||
#define NS_LARGE __xdata
|
||||
#define NS_LARGE_PTR __xdata
|
||||
#ifdef __ICC8051__
|
||||
#define NS_REENTRANT
|
||||
#define NS_REENTRANT_PREFIX __idata_reentrant
|
||||
#else
|
||||
#define NS_REENTRANT __reentrant
|
||||
#define NS_REENTRANT_PREFIX
|
||||
#endif
|
||||
#define NS_NEAR_FUNC __near_func
|
||||
|
||||
#else
|
||||
|
||||
/* "Normal" systems. Define it all away. */
|
||||
#define NS_LARGE
|
||||
#define NS_LARGE_PTR
|
||||
#define NS_REENTRANT
|
||||
#define NS_REENTRANT_PREFIX
|
||||
#define NS_NEAR_FUNC
|
||||
|
||||
#endif
|
||||
|
||||
/** \brief Scatter-gather descriptor
|
||||
*
|
||||
* Slightly optimised for small platforms - we assume we won't need any
|
||||
* element bigger than 64K.
|
||||
*/
|
||||
typedef struct ns_iovec {
|
||||
void *iov_base;
|
||||
uint_fast16_t iov_len;
|
||||
} ns_iovec_t;
|
||||
|
||||
#endif /* NS_TYPES_H */
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2019 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* \file nsdynmemLIB.h
|
||||
* \brief Dynamical Memory API for library model
|
||||
* nsdynmemlib provides access to one default heap, along with the ability to use extra user heaps.
|
||||
* ns_dyn_mem_alloc/free always access the default heap initialised by ns_dyn_mem_init.
|
||||
* ns_mem_alloc/free access a user heap initialised by ns_mem_init. User heaps are identified by a book-keeping pointer.
|
||||
*/
|
||||
|
||||
#ifndef NSDYNMEMLIB_H_
|
||||
#define NSDYNMEMLIB_H_
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "ns_types.h"
|
||||
|
||||
// Added to maintain backward compatibility with older implementation of ns_dyn_mem APIs
|
||||
#define NSDYNMEMLIB_API_VERSION 3
|
||||
|
||||
typedef size_t ns_mem_block_size_t; //external interface unsigned heap block size type
|
||||
typedef size_t ns_mem_heap_size_t; //total heap size type.
|
||||
|
||||
/*!
|
||||
* \enum heap_fail_t
|
||||
* \brief Dynamically heap system failure call back event types.
|
||||
*/
|
||||
typedef enum {
|
||||
NS_DYN_MEM_NULL_FREE, /**< ns_dyn_mem_free(), NULL pointer free [obsolete - no longer faulted] */
|
||||
NS_DYN_MEM_DOUBLE_FREE, /**< ns_dyn_mem_free(), Possible double pointer free */
|
||||
NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID, /**< Allocate size is 0 or smaller or size is bigger than max heap size */
|
||||
NS_DYN_MEM_POINTER_NOT_VALID, /**< ns_dyn_mem_free(), try to free pointer which not at heap sector */
|
||||
NS_DYN_MEM_HEAP_SECTOR_CORRUPTED, /**< Heap system detect sector corruption */
|
||||
NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED /**< ns_dyn_mem_free(), ns_dyn_mem_temporary_alloc() or ns_dyn_mem_alloc() called before ns_dyn_mem_init() */
|
||||
} heap_fail_t;
|
||||
|
||||
/**
|
||||
* /struct mem_stat_t
|
||||
* /brief Struct for Memory stats Buffer structure
|
||||
*/
|
||||
typedef struct mem_stat_t {
|
||||
/*Heap stats*/
|
||||
ns_mem_heap_size_t heap_sector_size; /**< Heap total Sector len. */
|
||||
ns_mem_heap_size_t heap_sector_alloc_cnt; /**< Reserved Heap sector cnt. */
|
||||
ns_mem_heap_size_t heap_sector_allocated_bytes; /**< Reserved Heap data in bytes. */
|
||||
ns_mem_heap_size_t heap_sector_allocated_bytes_max; /**< Reserved Heap data in bytes max value. */
|
||||
uint32_t heap_alloc_total_bytes; /**< Total Heap allocated bytes. */
|
||||
uint32_t heap_alloc_fail_cnt; /**< Counter for Heap allocation fail. */
|
||||
} mem_stat_t;
|
||||
|
||||
|
||||
typedef struct ns_mem_book ns_mem_book_t;
|
||||
|
||||
/**
|
||||
* \brief Init and set Dynamical heap pointer and length.
|
||||
*
|
||||
* \param heap_ptr Pointer to dynamically heap buffer
|
||||
* \param h_size size of the heap buffer
|
||||
* \param passed_fptr pointer to heap error callback function
|
||||
* \param info_ptr Pointer to mem_stat_t for memory statistics. Can be NULL.
|
||||
*
|
||||
* \return None
|
||||
*/
|
||||
extern void ns_dyn_mem_init(void *heap_ptr, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr);
|
||||
|
||||
/**
|
||||
* \brief Add memory region to initialized heap.
|
||||
*
|
||||
* This method adds memory region to already initialized heap.
|
||||
* Method will reset temporary heap threshold to the default value.
|
||||
*
|
||||
* \param region_ptr Pointer to memory region to be added
|
||||
* \param region_size size of the region buffer
|
||||
* \return 0 on success, <0 in case of errors.
|
||||
*/
|
||||
extern int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size);
|
||||
|
||||
/**
|
||||
* \brief Free allocated memory.
|
||||
*
|
||||
* \param heap_ptr Pointer to allocated memory
|
||||
*
|
||||
* \return 0, Free OK
|
||||
* \return <0, Free Fail
|
||||
*/
|
||||
extern void ns_dyn_mem_free(void *heap_ptr);
|
||||
|
||||
/**
|
||||
* \brief Allocate temporary data.
|
||||
*
|
||||
* Space allocate started from beginning of the heap sector
|
||||
*
|
||||
* \param alloc_size Allocated data size
|
||||
*
|
||||
* \return 0, Allocate Fail
|
||||
* \return >0, Pointer to allocated data sector.
|
||||
*/
|
||||
extern void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size);
|
||||
|
||||
/**
|
||||
* \brief Allocate long period data.
|
||||
*
|
||||
* Space allocate started from end of the heap sector
|
||||
*
|
||||
* \param alloc_size Allocated data size
|
||||
*
|
||||
* \return 0, Allocate Fail
|
||||
* \return >0, Pointer to allocated data sector.
|
||||
*/
|
||||
extern void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size);
|
||||
|
||||
/**
|
||||
* \brief Get pointer to the current mem_stat_t set via ns_dyn_mem_init.
|
||||
*
|
||||
* Get pointer to the statistics information, if one is set during the
|
||||
* initialization. This may be useful for statistics collection purposes.
|
||||
*
|
||||
* Note: the caller may not modify the returned structure.
|
||||
*
|
||||
* \return NULL, no mem_stat_t was given on initialization
|
||||
* \return Pointer to mem_stat_t or NULL.
|
||||
*/
|
||||
extern const mem_stat_t *ns_dyn_mem_get_mem_stat(void);
|
||||
|
||||
/**
|
||||
* \brief Set amount of free heap that must be available for temporary memory allocation to succeed.
|
||||
*
|
||||
* Temporary memory allocation will fail if system does not have defined amount of heap free.
|
||||
*
|
||||
* Note: the caller must set mem_stat_t structure in initialization.
|
||||
*
|
||||
* \param free_heap_percentage percentage of total heap that must be free for temporary memory allocation. Set free_heap_amount to 0 when this percentage value.
|
||||
* \param free_heap_amount Amount of free heap that must be free for temporary memory allocation. This value takes preference over percentage parameter value.
|
||||
*
|
||||
* \return 0 on success, <0 otherwise
|
||||
*/
|
||||
extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount);
|
||||
|
||||
/**
|
||||
* \brief Init and set Dynamical heap pointer and length.
|
||||
*
|
||||
* \param heap_ptr Pointer to dynamically heap buffer.
|
||||
* \param h_size size of the heap buffer.
|
||||
* \param passed_fptr pointer to heap error callback function.
|
||||
* \param info_ptr Pointer to mem_stat_t for memory statistics. Can be NULL.
|
||||
* \return Pointer to ns_mem_book_t.
|
||||
*/
|
||||
extern ns_mem_book_t *ns_mem_init(void *heap_ptr, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr);
|
||||
|
||||
/**
|
||||
* \brief Add memory region to initialized heap.
|
||||
*
|
||||
* This method adds memory region to already initialized heap.
|
||||
* Method will reset temporary heap threshold to the default value.
|
||||
*
|
||||
* \param book Address of book keeping structure.
|
||||
* \param region_ptr Pointer to memory region buffer.
|
||||
* \param region_size size of the memory region to add
|
||||
*
|
||||
* \return 0 on success, <0 in case of errors.
|
||||
*/
|
||||
extern int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size);
|
||||
|
||||
/**
|
||||
* \brief Free allocated memory.
|
||||
*
|
||||
* \param book Address of book keeping structure
|
||||
* \param heap_ptr Pointer to allocated memory
|
||||
*
|
||||
* \return 0, Free OK
|
||||
* \return <0, Free Fail
|
||||
*/
|
||||
extern void ns_mem_free(ns_mem_book_t *book, void *heap_ptr);
|
||||
|
||||
/**
|
||||
* \brief Allocate temporary data.
|
||||
*
|
||||
* Space allocate started from beginning of the heap sector
|
||||
*
|
||||
* \param book Address of book keeping structure
|
||||
* \param alloc_size Allocated data size
|
||||
*
|
||||
* \return 0, Allocate Fail
|
||||
* \return >0, Pointer to allocated data sector.
|
||||
*/
|
||||
extern void *ns_mem_temporary_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size);
|
||||
|
||||
/**
|
||||
* \brief Allocate long period data.
|
||||
*
|
||||
* Space allocate started from end of the heap sector
|
||||
*
|
||||
* \param book Address of book keeping structure
|
||||
* \param alloc_size Allocated data size
|
||||
*
|
||||
* \return 0, Allocate Fail
|
||||
* \return >0, Pointer to allocated data sector.
|
||||
*/
|
||||
extern void *ns_mem_alloc(ns_mem_book_t *book, ns_mem_block_size_t alloc_size);
|
||||
|
||||
/**
|
||||
* \brief Get pointer to the current mem_stat_t set via ns_mem_init.
|
||||
*
|
||||
* Get pointer to the statistics information, if one is set during the
|
||||
* initialization. This may be useful for statistics collection purposes.
|
||||
*
|
||||
* Note: the caller may not modify the returned structure.
|
||||
*
|
||||
* \param book Address of book keeping structure
|
||||
*
|
||||
* \return NULL, no mem_stat_t was given on initialization
|
||||
* \return !=0, Pointer to mem_stat_t.
|
||||
*/
|
||||
extern const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *book);
|
||||
|
||||
/**
|
||||
* \brief Set amount of free heap that must be available for temporary memory allocation to succeed.
|
||||
*
|
||||
* Temporary memory allocation will fail if system does not have defined amount of heap free.
|
||||
*
|
||||
* Note: the caller must set mem_stat_t structure in initialization.
|
||||
*
|
||||
* \param book Address of book keeping structure
|
||||
* \param free_heap_percentage percentage of total heap that must be free for temporary memory allocation. Set free_heap_amount to 0 when using percentage value.
|
||||
* \param free_heap_amount Amount of free heap that must be free for temporary memory allocation. This value takes preference over the percentage parameter value.
|
||||
*
|
||||
* \return 0 on success, <0 otherwise
|
||||
*/
|
||||
extern int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* NSDYNMEMLIB_H_ */
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ARM_HAL_API_H_
|
||||
#define ARM_HAL_API_H_
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \brief This function disable global interrupts.
|
||||
*/
|
||||
extern void platform_enter_critical(void);
|
||||
/**
|
||||
* \brief This function enable global interrupts.
|
||||
*/
|
||||
extern void platform_exit_critical(void);
|
||||
|
||||
/**
|
||||
* \brief This function increments the disable IRQ counter.
|
||||
* The function must be called inside interrupt routines
|
||||
* before any routine that uses platform_enter_critical()
|
||||
* is called.
|
||||
*
|
||||
* This routine may not be need to do anything on some platforms,
|
||||
* but requiring the call to be made before using
|
||||
* platform_enter_critical() in an interrupt can simplify some
|
||||
* implementations of platform_enter/exit_critical().
|
||||
*/
|
||||
extern void platform_interrupts_disabled(void);
|
||||
|
||||
/**
|
||||
* \brief This function decrements the disable IRQ counter.
|
||||
*/
|
||||
extern void platform_interrupts_enabling(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ARM_HAL_API_H_ */
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Nanostack NVM API.
|
||||
*
|
||||
* After NVM initialization (platform_nvm_init(...)) a user can:
|
||||
* -create key to the NVM by using method platform_nvm_key_create(...)
|
||||
* -write data to the NVM by using method platform_nvm_write(...)
|
||||
* -read data from the NVM by using method platform_nvm_read(...)
|
||||
* -delete the created key by using platform_nvm_key_delete(...)
|
||||
* -store changed data to the underlying backing store by using method platform_nvm_flush(...).
|
||||
*
|
||||
* This NVM API is asynchronous. If API function returns PLATFORM_NVM_OK then provided callback function will be
|
||||
* called once operation is completed. Callback function carries status parameter that indicates status of the
|
||||
* operation. If platform API function returns error code then callback will not be called. A new operation can not
|
||||
* be started until the previous operation has completed.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_NVM_H_
|
||||
#define _PLATFORM_NVM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Enumeration for nvm API function return values */
|
||||
typedef enum {
|
||||
PLATFORM_NVM_OK,
|
||||
PLATFORM_NVM_KEY_NOT_FOUND,
|
||||
PLATFORM_NVM_ERROR
|
||||
} platform_nvm_status;
|
||||
|
||||
/** \brief Client registered API callback type.
|
||||
*
|
||||
* \param status operation completion status
|
||||
* \param context client provided context that was used when requesting operation
|
||||
*/
|
||||
typedef void (nvm_callback)(platform_nvm_status status, void *context);
|
||||
|
||||
/** \brief Initialize NVM. Allocates module static resources and initializes underlying NMV.
|
||||
*
|
||||
* \param callback callback function that will be called once initialization is completed.
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called.
|
||||
*
|
||||
* \return NVM_OK if initialization is in progress and callback will be called.
|
||||
* \return NVM_ERROR if initialization failed and callback will not be called.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_init(nvm_callback *callback, void *context);
|
||||
|
||||
/** \brief Free resources reserved by NVM init.
|
||||
*
|
||||
* \param callback callback function that will be called once deinitialization is completed.
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called.
|
||||
*
|
||||
* \return NVM_OK if initialization is in progress and callback will be called.
|
||||
* \return NVM_ERROR if initialization failed and callback will not be called.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_finalize(nvm_callback *callback, void *context);
|
||||
|
||||
/** \brief Create key to the NMV. If the key exists then the key will be recreated with new length.
|
||||
*
|
||||
* \param callback callback function that will be called once key creation is finished
|
||||
* \param key_name name of the key to be created
|
||||
* \param value_len length of data reserved for the key
|
||||
* \param flags reserved for future use
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called
|
||||
*
|
||||
* \return NVM_OK if key creation is in progress and callback will be called.
|
||||
* \return NVM_ERROR if key creation failed and callback will not be called.
|
||||
* \return Provided callback function will be called once operation is completed.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_key_create(nvm_callback *callback, const char *key_name, uint16_t value_len, uint32_t flags, void *context);
|
||||
|
||||
/** \brief Delete key from NMV.
|
||||
*
|
||||
* \param callback callback function that will be called once key creation is finished
|
||||
* \param key_name name of the key to be deleted
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called
|
||||
*
|
||||
* \return NVM_OK if key creation is in progress and callback will be called.
|
||||
* \return NVM_ERROR if key creation failed and callback will not be called.
|
||||
* \return Provided callback function will be called once operation is completed.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_key_delete(nvm_callback *callback, const char *key_name, void *context);
|
||||
|
||||
/** \brief Write data to the NVM. Data will be truncated if the key does not have enough space for the data.
|
||||
*
|
||||
* \param callback callback function that will be called once writing is complete
|
||||
* \param key_name name of the key where data will be written
|
||||
* \param data buffer to data to be write. Data must be valid until callback is called.
|
||||
* \param data_len [IN] length of data in bytes. [OUT] number of bytes written. Argument must be valid until a callback is called.
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called.
|
||||
*
|
||||
* \return NVM_OK if data writing is in progress and callback will be called.
|
||||
* \return NVM_ERROR if data writing failed and callback will not be called.
|
||||
* \return Provided callback function will be called once operation is completed.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_write(nvm_callback *callback, const char *key_name, const void *data, uint16_t *data_len, void *context);
|
||||
|
||||
/** \brief Read key value from the NVM.
|
||||
*
|
||||
* \param callback callback function that will be called once reading is complete
|
||||
* \param key_name name of the key whose data will be read
|
||||
* \param buf buffer where data will be copied. Argument must be valid until a callback is called.
|
||||
* \param buf_len [IN] provided buffer length in bytes. [OUT] bytes read. Argument must be valid until callback is called.
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called.
|
||||
*
|
||||
* \return NVM_OK if data reading is in progress and callback will be called.
|
||||
* \return NVM_ERROR if data reading failed and callback will not be called.
|
||||
* \return Provided callback function will be called once operation is completed.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_read(nvm_callback *callback, const char *key_name, void *buf, uint16_t *buf_len, void *context);
|
||||
|
||||
/** \brief Store changed data to the backing store. This operation will write changed data to SRAM/Flash.
|
||||
*
|
||||
* \param callback callback function that will be called once flushing is complete
|
||||
* \param context A client registered context that will be supplied as an argument to the callback when called.
|
||||
*
|
||||
* \return NVM_OK if data flushing is in progress and callback will be called.
|
||||
* \return NVM_ERROR if data flushing failed and callback will not be called.
|
||||
* \return Provided callback function will be called once operation is completed.
|
||||
*/
|
||||
platform_nvm_status platform_nvm_flush(nvm_callback *callback, void *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* _PLATFORM_NVM_H_ */
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "nanostack-libservice"
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "stdint.h"
|
||||
#include "ip_fsc.h"
|
||||
|
||||
/** \brief Compute IP checksum for arbitary data
|
||||
*
|
||||
* Compute an IP checksum, given a arbitrary gather list.
|
||||
*
|
||||
* See ipv6_fcf for discussion of use.
|
||||
*
|
||||
* This will work for any arbitrary gather list - it can handle odd
|
||||
* alignments. The one limitation is that the 32-bit accumulator limits
|
||||
* it to basically 64K of total data.
|
||||
*/
|
||||
uint16_t ip_fcf_v(uint_fast8_t count, const ns_iovec_t vec[static count])
|
||||
{
|
||||
uint_fast32_t acc32 = 0;
|
||||
bool odd = false;
|
||||
while (count) {
|
||||
const uint8_t *data_ptr = vec->iov_base;
|
||||
uint_fast16_t data_length = vec->iov_len;
|
||||
if (odd && data_length > 0) {
|
||||
acc32 += *data_ptr++;
|
||||
data_length--;
|
||||
odd = false;
|
||||
}
|
||||
while (data_length >= 2) {
|
||||
acc32 += (uint_fast16_t) data_ptr[0] << 8 | data_ptr[1];
|
||||
data_ptr += 2;
|
||||
data_length -= 2;
|
||||
}
|
||||
if (data_length) {
|
||||
acc32 += (uint_fast16_t) data_ptr[0] << 8;
|
||||
odd = true;
|
||||
}
|
||||
vec++;
|
||||
count--;
|
||||
}
|
||||
|
||||
// Fold down up to 0xffff carries in the 32-bit accumulator
|
||||
acc32 = (acc32 >> 16) + (acc32 & 0xffff);
|
||||
|
||||
// Could be one more carry from the previous addition (result <= 0x1fffe)
|
||||
uint16_t sum16 = (uint16_t)((acc32 >> 16) + (acc32 & 0xffff));
|
||||
return ~sum16;
|
||||
}
|
||||
|
||||
/** \brief Compute IPv6 checksum
|
||||
*
|
||||
* Compute an IPv6 checksum, given fields of an IPv6 pseudoheader and payload.
|
||||
*
|
||||
* This returns the 1's-complement of the checksum, as required when
|
||||
* generating the checksum for transmission. The result can be 0x0000;
|
||||
* for UDP (only) this must be transformed to 0xFFFF to distinguish from
|
||||
* a packet with no checksum.
|
||||
*
|
||||
* To check a packet, this function will return 0 when run on a
|
||||
* packet with a valid checksum. Checksums should be checked like this rather
|
||||
* than setting the checksum field to zero and comparing generated checksum with
|
||||
* the original value - this would fail in the case the received packet had
|
||||
* checksum 0xFFFF.
|
||||
*/
|
||||
uint16_t ipv6_fcf(const uint8_t src_address[static 16], const uint8_t dest_address[static 16],
|
||||
uint16_t data_length, const uint8_t data_ptr[static data_length], uint8_t next_protocol)
|
||||
{
|
||||
// Use gather vector to lay out IPv6 pseudo-header (RFC 2460) and data
|
||||
uint8_t hdr_data[] = { data_length >> 8, data_length, 0, next_protocol };
|
||||
ns_iovec_t vec[4] = {
|
||||
{ (void *) src_address, 16 },
|
||||
{ (void *) dest_address, 16 },
|
||||
{ hdr_data, 4 },
|
||||
{ (void *) data_ptr, data_length }
|
||||
};
|
||||
|
||||
return ip_fcf_v(4, vec);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Most functions can be inlined, and definitions are in common_functions.h.
|
||||
* Define COMMON_FUNCTIONS_FN before including it to generate external definitions.
|
||||
*/
|
||||
#define COMMON_FUNCTIONS_FN extern
|
||||
|
||||
#include "common_functions.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* Returns mask for <split_value> (0-8) most-significant bits of a byte */
|
||||
static inline uint8_t context_split_mask(uint_fast8_t split_value)
|
||||
{
|
||||
return (uint8_t) - (0x100u >> split_value);
|
||||
}
|
||||
|
||||
bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits)
|
||||
{
|
||||
uint_fast8_t bytes = bits / 8;
|
||||
bits %= 8;
|
||||
|
||||
if (bytes && memcmp(a, b, bytes)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bits) {
|
||||
uint_fast8_t split_bit = context_split_mask(bits);
|
||||
if ((a[bytes] & split_bit) != (b[bytes] & split_bit)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits)
|
||||
{
|
||||
uint_fast8_t bytes = bits / 8;
|
||||
bits %= 8;
|
||||
|
||||
if (bytes) {
|
||||
dst = (uint8_t *) memcpy(dst, src, bytes) + bytes;
|
||||
src += bytes;
|
||||
}
|
||||
|
||||
if (bits) {
|
||||
uint_fast8_t split_bit = context_split_mask(bits);
|
||||
*dst = (*src & split_bit) | (*dst & ~ split_bit);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits)
|
||||
{
|
||||
uint_fast8_t bytes = bits / 8;
|
||||
bits %= 8;
|
||||
|
||||
if (bytes) {
|
||||
dst = (uint8_t *) memcpy(dst, src, bytes) + bytes;
|
||||
src += bytes;
|
||||
}
|
||||
|
||||
if (bits) {
|
||||
uint_fast8_t split_bit = context_split_mask(bits);
|
||||
*dst = (*src & split_bit);
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
* All functions can be inlined, and definitions are in ns_list.h.
|
||||
* Define NS_LIST_FN before including it to generate external definitions.
|
||||
*/
|
||||
#define NS_LIST_FN extern
|
||||
|
||||
#include "ns_list.h"
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
egrep -hr '^#define' ../../../../ |sed -n 's/\#define\s*TRACE_GROUP_[^\s]*\s*\"\([^\"]*\)\"/\1/p' > groups.txt
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "common_functions.h"
|
||||
#include "ip4string.h"
|
||||
|
||||
static void ipv4_itoa(char *string, uint8_t byte);
|
||||
|
||||
/**
|
||||
* Print binary IPv4 address to a string.
|
||||
* String must contain enough room for full address, 16 bytes exact.
|
||||
* \param addr IPv4 address.
|
||||
* \p buffer to write string to.
|
||||
*/
|
||||
uint_fast8_t ip4tos(const void *ip4addr, char *p)
|
||||
{
|
||||
uint_fast8_t outputPos = 0;
|
||||
const uint8_t *byteArray = ip4addr;
|
||||
|
||||
for (uint_fast8_t component = 0; component < 4; ++component) {
|
||||
//Convert the byte to string
|
||||
ipv4_itoa(&p[outputPos], byteArray[component]);
|
||||
|
||||
//Move outputPos to the end of the string
|
||||
while (p[outputPos] != '\0') {
|
||||
outputPos += 1;
|
||||
}
|
||||
|
||||
//Append a dot if this is not the last digit
|
||||
if (component < 3) {
|
||||
p[outputPos++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
// Return length of generated string, excluding the terminating null character
|
||||
return outputPos;
|
||||
}
|
||||
|
||||
static void ipv4_itoa(char *string, uint8_t byte)
|
||||
{
|
||||
char *baseString = string;
|
||||
|
||||
//Write the digits to the buffer from the least significant to the most
|
||||
// This is the incorrect order but we will swap later
|
||||
do {
|
||||
*string++ = '0' + byte % 10;
|
||||
byte /= 10;
|
||||
} while (byte);
|
||||
|
||||
//We put the final \0, then go back one step on the last digit for the swap
|
||||
*string-- = '\0';
|
||||
|
||||
//We now swap the digits
|
||||
while (baseString < string) {
|
||||
uint8_t tmp = *string;
|
||||
*string-- = *baseString;
|
||||
*baseString++ = tmp;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "common_functions.h"
|
||||
#include "ip4string.h"
|
||||
|
||||
/**
|
||||
* Convert numeric IPv4 address string to a binary.
|
||||
* \param ip4addr IPv4 address in string format.
|
||||
* \param len Length of IPv4 string, maximum of 16..
|
||||
* \param dest buffer for address. MUST be 4 bytes.
|
||||
* \return boolean set to true if conversion succeded, false if it didn't
|
||||
*/
|
||||
bool stoip4(const char *ip4addr, size_t len, void *dest)
|
||||
{
|
||||
uint8_t *addr = dest;
|
||||
|
||||
if (len > 16) { // Too long, not possible
|
||||
return false;
|
||||
}
|
||||
|
||||
uint_fast8_t stringLength = 0, byteCount = 0;
|
||||
|
||||
//Iterate over each component of the IP. The exit condition is in the middle of the loop
|
||||
while (true) {
|
||||
|
||||
//No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z)
|
||||
if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') {
|
||||
return false;
|
||||
}
|
||||
|
||||
//For each component, we convert it to the raw value
|
||||
uint_fast16_t byte = 0;
|
||||
while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') {
|
||||
byte *= 10;
|
||||
byte += ip4addr[stringLength++] - '0';
|
||||
|
||||
//We go over the maximum value for an IPv4 component
|
||||
if (byte > 0xff) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Append the component
|
||||
addr[byteCount++] = (uint8_t) byte;
|
||||
|
||||
//If we're at the end, we leave the loop. It's the only way to reach the `true` output
|
||||
if (byteCount == 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
//If the next character is invalid, we return false
|
||||
if (stringLength == len || ip4addr[stringLength++] != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return stringLength == len || ip4addr[stringLength] == '\0';
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "common_functions.h"
|
||||
#include "ip6string.h"
|
||||
|
||||
/**
|
||||
* Print binary IPv6 address to a string.
|
||||
* String must contain enough room for full address, 40 bytes exact.
|
||||
* IPv4 tunneling addresses are not covered.
|
||||
* \param addr IPv6 address.
|
||||
* \p buffer to write string to.
|
||||
*/
|
||||
uint_fast8_t ip6tos(const void *ip6addr, char *p)
|
||||
{
|
||||
char *p_orig = p;
|
||||
uint_fast8_t zero_start = 255, zero_len = 1;
|
||||
const uint8_t *addr = ip6addr;
|
||||
uint_fast16_t part;
|
||||
|
||||
/* Follow RFC 5952 - pre-scan for longest run of zeros */
|
||||
for (uint_fast8_t n = 0; n < 8; n++) {
|
||||
part = *addr++;
|
||||
part = (part << 8) | *addr++;
|
||||
if (part != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We're at the start of a run of zeros - scan to non-zero (or end) */
|
||||
uint_fast8_t n0 = n;
|
||||
for (n = n0 + 1; n < 8; n++) {
|
||||
part = *addr++;
|
||||
part = (part << 8) | *addr++;
|
||||
if (part != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now n0->initial zero of run, n->after final zero in run. Is this the
|
||||
* longest run yet? If equal, we stick with the previous one - RFC 5952
|
||||
* S4.2.3. Note that zero_len being initialised to 1 stops us
|
||||
* shortening a 1-part run (S4.2.2.)
|
||||
*/
|
||||
if (n - n0 > zero_len) {
|
||||
zero_start = n0;
|
||||
zero_len = n - n0;
|
||||
}
|
||||
|
||||
/* Continue scan for initial zeros from part n+1 - we've already
|
||||
* consumed part n, and know it's non-zero. */
|
||||
}
|
||||
|
||||
/* Now go back and print, jumping over any zero run */
|
||||
addr = ip6addr;
|
||||
for (uint_fast8_t n = 0; n < 8;) {
|
||||
if (n == zero_start) {
|
||||
if (n == 0) {
|
||||
*p++ = ':';
|
||||
}
|
||||
*p++ = ':';
|
||||
addr += 2 * zero_len;
|
||||
n += zero_len;
|
||||
continue;
|
||||
}
|
||||
|
||||
part = *addr++;
|
||||
part = (part << 8) | *addr++;
|
||||
n++;
|
||||
|
||||
p += sprintf(p, "%"PRIxFAST16, part);
|
||||
|
||||
/* One iteration writes "part:" rather than ":part", and has the
|
||||
* explicit check for n == 8 below, to allow easy extension for
|
||||
* IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just
|
||||
* run the same loop for 6 parts, and output would then finish with the
|
||||
* required : or ::, ready for "a.b.c.d" to be tacked on.
|
||||
*/
|
||||
if (n != 8) {
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
// Return length of generated string, excluding the terminating null character
|
||||
return p - p_orig;
|
||||
}
|
||||
|
||||
uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p)
|
||||
{
|
||||
char *wptr = p;
|
||||
uint8_t addr[16] = {0};
|
||||
|
||||
if (prefix_len > 128) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Generate prefix part of the string
|
||||
bitcopy(addr, prefix, prefix_len);
|
||||
wptr += ip6tos(addr, wptr);
|
||||
// Add the prefix length part of the string
|
||||
wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len);
|
||||
|
||||
// Return total length of generated string
|
||||
return wptr - p;
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "common_functions.h"
|
||||
#include "ip6string.h"
|
||||
|
||||
static uint16_t hex(const char *p);
|
||||
static bool is_hex(char c);
|
||||
|
||||
/**
|
||||
* Convert numeric IPv6 address string to a binary.
|
||||
* IPv4 tunnelling addresses are not covered.
|
||||
* \param ip6addr IPv6 address in string format.
|
||||
* \param len Length of ipv6 string.
|
||||
* \param dest buffer for address. MUST be 16 bytes.
|
||||
* \return boolean set to true if conversion succeed, false if it didn't
|
||||
*/
|
||||
bool stoip6(const char *ip6addr, size_t len, void *dest)
|
||||
{
|
||||
uint8_t *addr;
|
||||
const char *p, *q;
|
||||
int_fast8_t field_no, coloncolon = -1;
|
||||
|
||||
addr = dest;
|
||||
|
||||
if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
|
||||
goto error;
|
||||
}
|
||||
|
||||
// First go forward the string, until end, noting :: position if any
|
||||
// We're decrementing `len` as we go forward, and stop when it reaches 0
|
||||
for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
|
||||
|
||||
for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
|
||||
if (!is_hex(*q++)) { // There must only be hex characters besides ':'
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (field_no == 8) { // If the address goes farther than 8 segments
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Convert and write this part, (high-endian AKA network byte order)
|
||||
addr = common_write_16_bit(hex(p), addr);
|
||||
field_no++;
|
||||
|
||||
// We handle the colons
|
||||
if (len) {
|
||||
// Check if we reached "::"
|
||||
if (q[0] == ':' && q[1] == ':') {
|
||||
if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
|
||||
goto error;
|
||||
}
|
||||
coloncolon = field_no;
|
||||
q++;
|
||||
len -= 2;
|
||||
} else {
|
||||
len -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (coloncolon != -1) {
|
||||
/* Insert zeros in the appropriate place */
|
||||
uint_fast8_t head_size = 2 * coloncolon;
|
||||
uint_fast8_t inserted_size = 2 * (8 - field_no);
|
||||
uint_fast8_t tail_size = 16 - head_size - inserted_size;
|
||||
addr = dest;
|
||||
memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
|
||||
memset(addr + head_size, 0, inserted_size);
|
||||
} else if (field_no != 8) { // Report an error if we didn't get 8 fields
|
||||
goto error;
|
||||
}
|
||||
return true;
|
||||
|
||||
error:
|
||||
// Fill the output buffer with 0 so we stick to the old failure behavior.
|
||||
// We are however more agressive and wipe the entire address, and do so more often.
|
||||
memset(dest, 0, 16);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char sipv6_prefixlength(const char *ip6addr)
|
||||
{
|
||||
char *ptr = strchr(ip6addr, '/');
|
||||
if (ptr) {
|
||||
return (unsigned char)strtoul(ptr + 1, 0, 10);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
|
||||
{
|
||||
size_t addr_len, total_len;
|
||||
int_fast16_t prefix_length;
|
||||
|
||||
if (prefix_len_out) {
|
||||
*prefix_len_out = -1;
|
||||
}
|
||||
|
||||
total_len = addr_len = strlen(ip6addr);
|
||||
const char *ptr = strchr(ip6addr, '/');
|
||||
if (ptr) {
|
||||
addr_len = ptr - ip6addr;
|
||||
if (prefix_len_out) {
|
||||
if (total_len - addr_len > 3) {
|
||||
/* too many digits in prefix */
|
||||
return -1;
|
||||
}
|
||||
|
||||
prefix_length = strtoul(ptr + 1, 0, 10);
|
||||
if (prefix_length < 0 || prefix_length > 128) {
|
||||
/* prefix value illegal */
|
||||
return -1;
|
||||
}
|
||||
|
||||
*prefix_len_out = prefix_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stoip6(ip6addr, addr_len, dest)) {
|
||||
/* parser failure */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool is_hex(char c)
|
||||
{
|
||||
// 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
|
||||
if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint16_t hex(const char *p)
|
||||
{
|
||||
uint16_t val = 0;
|
||||
|
||||
for (;;) {
|
||||
char c = *p++;
|
||||
if ((c >= '0') && (c <= '9')) {
|
||||
val = (val << 4) | (c - '0');
|
||||
} else if ((c >= 'A') && (c <= 'F')) {
|
||||
val = (val << 4) | (10 + (c - 'A'));
|
||||
} else if ((c >= 'a') && (c <= 'f')) {
|
||||
val = (val << 4) | (10 + (c - 'a'));
|
||||
} else {
|
||||
break; // Non hex character
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
|
@ -0,0 +1,640 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2019 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "nsdynmemLIB.h"
|
||||
#include "platform/arm_hal_interrupt.h"
|
||||
#include <stdlib.h>
|
||||
#include "ns_list.h"
|
||||
|
||||
#ifndef STANDARD_MALLOC
|
||||
typedef enum mem_stat_update_t {
|
||||
DEV_HEAP_ALLOC_OK,
|
||||
DEV_HEAP_ALLOC_FAIL,
|
||||
DEV_HEAP_FREE,
|
||||
} mem_stat_update_t;
|
||||
|
||||
typedef struct {
|
||||
ns_list_link_t link;
|
||||
} hole_t;
|
||||
|
||||
typedef int ns_mem_word_size_t; // internal signed heap block size type
|
||||
|
||||
// Amount of memory regions
|
||||
#define REGION_COUNT 3
|
||||
|
||||
/* struct for book keeping variables */
|
||||
struct ns_mem_book {
|
||||
ns_mem_word_size_t *heap_main[REGION_COUNT];
|
||||
ns_mem_word_size_t *heap_main_end[REGION_COUNT];
|
||||
mem_stat_t *mem_stat_info_ptr;
|
||||
void (*heap_failure_callback)(heap_fail_t);
|
||||
NS_LIST_HEAD(hole_t, link) holes_list;
|
||||
ns_mem_heap_size_t heap_size;
|
||||
ns_mem_heap_size_t temporary_alloc_heap_limit; /* Amount of reserved heap temporary alloc can't exceed */
|
||||
};
|
||||
|
||||
static ns_mem_book_t *default_book; // heap pointer for original "ns_" API use
|
||||
|
||||
// size of a hole_t in our word units
|
||||
#define HOLE_T_SIZE ((ns_mem_word_size_t) ((sizeof(hole_t) + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t)))
|
||||
|
||||
#define TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD 5 /* temporary allocations must leave 5% of the heap free */
|
||||
|
||||
static NS_INLINE hole_t *hole_from_block_start(ns_mem_word_size_t *start)
|
||||
{
|
||||
return (hole_t *)(start + 1);
|
||||
}
|
||||
|
||||
static NS_INLINE ns_mem_word_size_t *block_start_from_hole(hole_t *start)
|
||||
{
|
||||
return ((ns_mem_word_size_t *)start) - 1;
|
||||
}
|
||||
|
||||
static void heap_failure(ns_mem_book_t *book, heap_fail_t reason)
|
||||
{
|
||||
if (book->heap_failure_callback) {
|
||||
book->heap_failure_callback(reason);
|
||||
}
|
||||
}
|
||||
|
||||
static int ns_dyn_mem_region_find(ns_mem_book_t *book, ns_mem_word_size_t *block_ptr, ns_mem_word_size_t size)
|
||||
{
|
||||
int index;
|
||||
for (index = 0; index < REGION_COUNT; index++) {
|
||||
if (book->heap_main[index] != 0) {
|
||||
if ((block_ptr >= book->heap_main[index]) &&
|
||||
(block_ptr < book->heap_main_end[index]) &&
|
||||
((block_ptr + size) < book->heap_main_end[index])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ns_dyn_mem_region_save(ns_mem_book_t *book, ns_mem_word_size_t *region_start_ptr, ns_mem_word_size_t region_size)
|
||||
{
|
||||
for (int i = 1; i < REGION_COUNT; i++) {
|
||||
if (book->heap_main[i] == 0) {
|
||||
book->heap_main[i] = region_start_ptr;
|
||||
book->heap_main_end[i] = book->heap_main[i] + region_size;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#endif //STANDARD_MALLOC
|
||||
|
||||
void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size,
|
||||
void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
|
||||
{
|
||||
default_book = ns_mem_init(heap, h_size, passed_fptr, info_ptr);
|
||||
}
|
||||
|
||||
int ns_dyn_mem_region_add(void *region_ptr, ns_mem_heap_size_t region_size)
|
||||
{
|
||||
return ns_mem_region_add(default_book, region_ptr, region_size);
|
||||
}
|
||||
|
||||
const mem_stat_t *ns_dyn_mem_get_mem_stat(void)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
return ns_mem_get_mem_stat(default_book);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
ns_mem_book_t *ns_mem_init(void *heap, ns_mem_heap_size_t h_size,
|
||||
void (*passed_fptr)(heap_fail_t),
|
||||
mem_stat_t *info_ptr)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
ns_mem_book_t *book;
|
||||
|
||||
ns_mem_word_size_t *ptr;
|
||||
ns_mem_word_size_t temp_int;
|
||||
/* Do memory alignment */
|
||||
temp_int = ((uintptr_t)heap % sizeof(ns_mem_word_size_t));
|
||||
if (temp_int) {
|
||||
heap = (uint8_t *) heap + (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
}
|
||||
|
||||
/* Make correction for total length also */
|
||||
temp_int = (h_size % sizeof(ns_mem_word_size_t));
|
||||
if (temp_int) {
|
||||
h_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
}
|
||||
|
||||
book = heap;
|
||||
memset(book->heap_main, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *));
|
||||
memset(book->heap_main_end, 0, REGION_COUNT * sizeof(ns_mem_word_size_t *));
|
||||
|
||||
book->heap_main[0] = (ns_mem_word_size_t *) & (book[1]); // SET Heap Pointer
|
||||
book->heap_size = h_size - sizeof(ns_mem_book_t); //Set Heap Size
|
||||
temp_int = (book->heap_size / sizeof(ns_mem_word_size_t));
|
||||
temp_int -= 2;
|
||||
ptr = book->heap_main[0];
|
||||
*ptr = -(temp_int);
|
||||
ptr += (temp_int + 1);
|
||||
*ptr = -(temp_int);
|
||||
book->heap_main_end[0] = ptr;
|
||||
|
||||
ns_list_init(&book->holes_list);
|
||||
ns_list_add_to_start(&book->holes_list, hole_from_block_start(book->heap_main[0]));
|
||||
|
||||
book->mem_stat_info_ptr = info_ptr;
|
||||
//RESET Memory by Hea Len
|
||||
if (info_ptr) {
|
||||
memset(book->mem_stat_info_ptr, 0, sizeof(mem_stat_t));
|
||||
book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
|
||||
}
|
||||
book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
|
||||
#endif
|
||||
//There really is no support to standard malloc in this library anymore
|
||||
book->heap_failure_callback = passed_fptr;
|
||||
|
||||
return book;
|
||||
}
|
||||
|
||||
int ns_mem_region_add(ns_mem_book_t *book, void *region_ptr, ns_mem_heap_size_t region_size)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
if (!book || !region_ptr || region_size < 3 * sizeof(ns_mem_word_size_t)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ns_mem_word_size_t *block_ptr;
|
||||
ns_mem_word_size_t temp_int;
|
||||
|
||||
/* Do memory alignment */
|
||||
temp_int = ((uintptr_t)region_ptr % sizeof(ns_mem_word_size_t));
|
||||
if (temp_int) {
|
||||
region_ptr = (uint8_t *) region_ptr + (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
region_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
}
|
||||
|
||||
/* Make correction for total length */
|
||||
temp_int = (region_size % sizeof(ns_mem_word_size_t));
|
||||
if (temp_int) {
|
||||
region_size -= (sizeof(ns_mem_word_size_t) - temp_int);
|
||||
}
|
||||
|
||||
// Create hole from new heap memory
|
||||
temp_int = (region_size / sizeof(ns_mem_word_size_t));
|
||||
temp_int -= 2;
|
||||
block_ptr = region_ptr;
|
||||
*block_ptr = -(temp_int);
|
||||
block_ptr += (temp_int + 1); // now block_ptr points to end of block
|
||||
*block_ptr = -(temp_int);
|
||||
|
||||
// find place for the new hole from the holes list
|
||||
hole_t *hole_to_add = hole_from_block_start(region_ptr);
|
||||
hole_t *previous_hole = NULL;
|
||||
ns_list_foreach(hole_t, hole_in_list_ptr, &book->holes_list) {
|
||||
if (hole_in_list_ptr < hole_to_add) {
|
||||
previous_hole = hole_in_list_ptr;
|
||||
} else if (hole_in_list_ptr == hole_to_add) {
|
||||
// trying to add memory block that is already in the list!
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
// save region
|
||||
if (ns_dyn_mem_region_save(book, region_ptr, (region_size / (sizeof(ns_mem_word_size_t))) - 1) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Add new hole to the list
|
||||
if (previous_hole) {
|
||||
ns_list_add_after(&book->holes_list, previous_hole, hole_to_add);
|
||||
} else {
|
||||
ns_list_add_to_start(&book->holes_list, hole_to_add);
|
||||
}
|
||||
|
||||
// adjust total heap size with new hole
|
||||
book->heap_size += region_size;
|
||||
|
||||
if (book->mem_stat_info_ptr) {
|
||||
book->mem_stat_info_ptr->heap_sector_size = book->heap_size;
|
||||
}
|
||||
|
||||
// adjust temporary allocation limits to match new heap
|
||||
book->temporary_alloc_heap_limit = book->heap_size / 100 * (100 - TEMPORARY_ALLOC_FREE_HEAP_THRESHOLD);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
(void) book;
|
||||
(void) region_ptr;
|
||||
(void) region_size;
|
||||
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
const mem_stat_t *ns_mem_get_mem_stat(ns_mem_book_t *heap)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
return heap->mem_stat_info_ptr;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ns_mem_set_temporary_alloc_free_heap_threshold(ns_mem_book_t *book, uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
ns_mem_heap_size_t heap_limit = 0;
|
||||
|
||||
if (!book || !book->mem_stat_info_ptr) {
|
||||
// no book or mem_stats
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (free_heap_amount && free_heap_amount < book->heap_size / 2) {
|
||||
heap_limit = book->heap_size - free_heap_amount;
|
||||
}
|
||||
|
||||
if (!free_heap_amount && free_heap_percentage && free_heap_percentage < 50) {
|
||||
heap_limit = book->heap_size / 100 * (100 - free_heap_percentage);
|
||||
}
|
||||
|
||||
if (free_heap_amount == 0 && free_heap_percentage == 0) {
|
||||
// feature disabled, allow whole heap to be reserved by temporary allo
|
||||
heap_limit = book->heap_size;
|
||||
}
|
||||
|
||||
if (heap_limit == 0) {
|
||||
// illegal heap parameters
|
||||
return -2;
|
||||
}
|
||||
|
||||
book->temporary_alloc_heap_limit = heap_limit;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -3;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern int ns_dyn_mem_set_temporary_alloc_free_heap_threshold(uint8_t free_heap_percentage, ns_mem_heap_size_t free_heap_amount)
|
||||
{
|
||||
return ns_mem_set_temporary_alloc_free_heap_threshold(default_book, free_heap_percentage, free_heap_amount);
|
||||
}
|
||||
|
||||
#ifndef STANDARD_MALLOC
|
||||
static void dev_stat_update(mem_stat_t *mem_stat_info_ptr, mem_stat_update_t type, ns_mem_block_size_t size)
|
||||
{
|
||||
if (mem_stat_info_ptr) {
|
||||
switch (type) {
|
||||
case DEV_HEAP_ALLOC_OK:
|
||||
mem_stat_info_ptr->heap_sector_alloc_cnt++;
|
||||
mem_stat_info_ptr->heap_sector_allocated_bytes += size;
|
||||
if (mem_stat_info_ptr->heap_sector_allocated_bytes_max < mem_stat_info_ptr->heap_sector_allocated_bytes) {
|
||||
mem_stat_info_ptr->heap_sector_allocated_bytes_max = mem_stat_info_ptr->heap_sector_allocated_bytes;
|
||||
}
|
||||
mem_stat_info_ptr->heap_alloc_total_bytes += size;
|
||||
break;
|
||||
case DEV_HEAP_ALLOC_FAIL:
|
||||
mem_stat_info_ptr->heap_alloc_fail_cnt++;
|
||||
break;
|
||||
case DEV_HEAP_FREE:
|
||||
mem_stat_info_ptr->heap_sector_alloc_cnt--;
|
||||
mem_stat_info_ptr->heap_sector_allocated_bytes -= size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ns_mem_word_size_t convert_allocation_size(ns_mem_book_t *book, ns_mem_block_size_t requested_bytes)
|
||||
{
|
||||
if (book->heap_main[0] == 0) {
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_UNITIALIZED);
|
||||
} else if (requested_bytes < 1) {
|
||||
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
||||
} else if (requested_bytes > (book->heap_size - 2 * sizeof(ns_mem_word_size_t))) {
|
||||
heap_failure(book, NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID);
|
||||
}
|
||||
return (requested_bytes + sizeof(ns_mem_word_size_t) - 1) / sizeof(ns_mem_word_size_t);
|
||||
}
|
||||
|
||||
// Checks that block length indicators are valid
|
||||
// Block has format: Size of data area [1 word] | data area [abs(size) words]| Size of data area [1 word]
|
||||
// If Size is negative it means area is unallocated
|
||||
static int8_t ns_mem_block_validate(ns_mem_word_size_t *block_start)
|
||||
{
|
||||
int8_t ret_val = -1;
|
||||
ns_mem_word_size_t *end = block_start;
|
||||
ns_mem_word_size_t size_start = *end;
|
||||
end += (1 + abs(size_start));
|
||||
if (size_start != 0 && size_start == *end) {
|
||||
ret_val = 0;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
#endif
|
||||
|
||||
// For direction, use 1 for direction up and -1 for down
|
||||
static void *ns_mem_internal_alloc(ns_mem_book_t *book, const ns_mem_block_size_t alloc_size, int direction)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
if (!book) {
|
||||
/* We can not do anything except return NULL because we can't find book
|
||||
keeping block */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (book->mem_stat_info_ptr && direction == 1) {
|
||||
if (book->mem_stat_info_ptr->heap_sector_allocated_bytes > book->temporary_alloc_heap_limit) {
|
||||
/* Not enough heap for temporary memory allocation */
|
||||
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ns_mem_word_size_t *block_ptr = NULL;
|
||||
|
||||
platform_enter_critical();
|
||||
|
||||
ns_mem_word_size_t data_size = convert_allocation_size(book, alloc_size);
|
||||
if (!data_size) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// ns_list_foreach, either forwards or backwards, result to ptr
|
||||
for (hole_t *cur_hole = direction > 0 ? ns_list_get_first(&book->holes_list)
|
||||
: ns_list_get_last(&book->holes_list);
|
||||
cur_hole;
|
||||
cur_hole = direction > 0 ? ns_list_get_next(&book->holes_list, cur_hole)
|
||||
: ns_list_get_previous(&book->holes_list, cur_hole)
|
||||
) {
|
||||
ns_mem_word_size_t *p = block_start_from_hole(cur_hole);
|
||||
if (ns_mem_block_validate(p) != 0 || *p >= 0) {
|
||||
//Validation failed, or this supposed hole has positive (allocated) size
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||
break;
|
||||
}
|
||||
if (-*p >= data_size) {
|
||||
// Found a big enough block
|
||||
block_ptr = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!block_ptr) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
// Separate declaration from initialization to keep IAR happy as the gotos skip this block.
|
||||
ns_mem_word_size_t block_data_size;
|
||||
block_data_size = -*block_ptr;
|
||||
if (block_data_size >= (data_size + 2 + HOLE_T_SIZE)) {
|
||||
ns_mem_word_size_t hole_size = block_data_size - data_size - 2;
|
||||
ns_mem_word_size_t *hole_ptr;
|
||||
//There is enough room for a new hole so create it first
|
||||
if (direction > 0) {
|
||||
hole_ptr = block_ptr + 1 + data_size + 1;
|
||||
// Hole will be left at end of area.
|
||||
// Would like to just replace this block_ptr with new descriptor, but
|
||||
// they could overlap, so ns_list_replace might fail
|
||||
//ns_list_replace(&holes_list, block_ptr, hole_from_block_start(hole_ptr));
|
||||
hole_t *before = ns_list_get_previous(&book->holes_list, hole_from_block_start(block_ptr));
|
||||
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
|
||||
if (before) {
|
||||
ns_list_add_after(&book->holes_list, before, hole_from_block_start(hole_ptr));
|
||||
} else {
|
||||
ns_list_add_to_start(&book->holes_list, hole_from_block_start(hole_ptr));
|
||||
}
|
||||
} else {
|
||||
hole_ptr = block_ptr;
|
||||
// Hole remains at start of area - keep existing descriptor in place.
|
||||
block_ptr += 1 + hole_size + 1;
|
||||
}
|
||||
|
||||
hole_ptr[0] = -hole_size;
|
||||
hole_ptr[1 + hole_size] = -hole_size;
|
||||
} else {
|
||||
// Not enough room for a left-over hole, so use the whole block
|
||||
data_size = block_data_size;
|
||||
ns_list_remove(&book->holes_list, hole_from_block_start(block_ptr));
|
||||
}
|
||||
block_ptr[0] = data_size;
|
||||
block_ptr[1 + data_size] = data_size;
|
||||
|
||||
done:
|
||||
if (book->mem_stat_info_ptr) {
|
||||
if (block_ptr) {
|
||||
//Update Allocate OK
|
||||
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_OK, (data_size + 2) * sizeof(ns_mem_word_size_t));
|
||||
} else {
|
||||
//Update Allocate Fail, second parameter is used for stats
|
||||
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_ALLOC_FAIL, 0);
|
||||
}
|
||||
}
|
||||
platform_exit_critical();
|
||||
|
||||
return block_ptr ? block_ptr + 1 : NULL;
|
||||
#else
|
||||
void *retval = NULL;
|
||||
if (alloc_size) {
|
||||
platform_enter_critical();
|
||||
retval = malloc(alloc_size);
|
||||
platform_exit_critical();
|
||||
}
|
||||
return retval;
|
||||
#endif
|
||||
}
|
||||
|
||||
void *ns_mem_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
return ns_mem_internal_alloc(heap, alloc_size, -1);
|
||||
}
|
||||
|
||||
void *ns_mem_temporary_alloc(ns_mem_book_t *heap, ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
return ns_mem_internal_alloc(heap, alloc_size, 1);
|
||||
}
|
||||
|
||||
void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
return ns_mem_alloc(default_book, alloc_size);
|
||||
}
|
||||
|
||||
void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
return ns_mem_temporary_alloc(default_book, alloc_size);
|
||||
}
|
||||
|
||||
#ifndef STANDARD_MALLOC
|
||||
static void ns_mem_free_and_merge_with_adjacent_blocks(ns_mem_book_t *book, ns_mem_word_size_t *cur_block, ns_mem_word_size_t data_size)
|
||||
{
|
||||
// Theory of operation: Block is always in form | Len | Data | Len |
|
||||
// So we need to check length of previous (if current not heap start)
|
||||
// and next (if current not heap end) blocks. Negative length means
|
||||
// free memory so we can merge freed block with those.
|
||||
|
||||
hole_t *existing_start = NULL;
|
||||
hole_t *existing_end = NULL;
|
||||
ns_mem_word_size_t *start = cur_block;
|
||||
ns_mem_word_size_t *end = cur_block + data_size + 1;
|
||||
ns_mem_word_size_t *region_start;
|
||||
ns_mem_word_size_t *region_end;
|
||||
|
||||
int region_index = ns_dyn_mem_region_find(book, cur_block, data_size);
|
||||
if (region_index >= 0) {
|
||||
region_start = book->heap_main[region_index];
|
||||
region_end = book->heap_main_end[region_index];
|
||||
} else {
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||
// can't find region for the block, return
|
||||
return;
|
||||
}
|
||||
|
||||
//invalidate current block
|
||||
*start = -data_size;
|
||||
*end = -data_size;
|
||||
ns_mem_word_size_t merged_data_size = data_size;
|
||||
|
||||
if (start != region_start) {
|
||||
if (*(start - 1) < 0) {
|
||||
ns_mem_word_size_t *block_end = start - 1;
|
||||
ns_mem_word_size_t block_size = 1 + (-*block_end) + 1;
|
||||
merged_data_size += block_size;
|
||||
start -= block_size;
|
||||
if (*start != *block_end) {
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||
}
|
||||
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
||||
existing_start = hole_from_block_start(start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (end != region_end) {
|
||||
if (*(end + 1) < 0) {
|
||||
ns_mem_word_size_t *block_start = end + 1;
|
||||
ns_mem_word_size_t block_size = 1 + (-*block_start) + 1;
|
||||
merged_data_size += block_size;
|
||||
end += block_size;
|
||||
if (*end != *block_start) {
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||
}
|
||||
if (block_size >= 1 + HOLE_T_SIZE + 1) {
|
||||
existing_end = hole_from_block_start(block_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hole_t *to_add = hole_from_block_start(start);
|
||||
hole_t *before = NULL;
|
||||
if (existing_end) {
|
||||
// Extending hole described by "existing_end" downwards.
|
||||
// Will replace with descriptor at bottom of merged block.
|
||||
// (Can't use ns_list_replace, because of danger of overlap)
|
||||
// Optimisation - note our position for insertion below.
|
||||
before = ns_list_get_next(&book->holes_list, existing_end);
|
||||
ns_list_remove(&book->holes_list, existing_end);
|
||||
}
|
||||
if (existing_start) {
|
||||
// Extending hole described by "existing_start" upwards.
|
||||
// No need to modify that descriptor - it remains at the bottom
|
||||
// of the merged block to describe it.
|
||||
} else {
|
||||
// Didn't find adjacent descriptors, but may still
|
||||
// be merging with small blocks without descriptors.
|
||||
if (merged_data_size >= HOLE_T_SIZE) {
|
||||
// Locate hole position in list, if we don't already know
|
||||
// from merging with the block above.
|
||||
if (!existing_end) {
|
||||
ns_list_foreach(hole_t, ptr, &book->holes_list) {
|
||||
if (ptr > to_add) {
|
||||
before = ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (before) {
|
||||
ns_list_add_before(&book->holes_list, before, to_add);
|
||||
} else {
|
||||
ns_list_add_to_end(&book->holes_list, to_add);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
*start = -merged_data_size;
|
||||
*end = -merged_data_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool pointer_address_validate(ns_mem_book_t *book, ns_mem_word_size_t *ptr, ns_mem_word_size_t size)
|
||||
{
|
||||
|
||||
if (ns_dyn_mem_region_find(book, ptr, size) >= 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ns_mem_free(ns_mem_book_t *book, void *block)
|
||||
{
|
||||
#ifndef STANDARD_MALLOC
|
||||
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
||||
ns_mem_word_size_t *ptr = block;
|
||||
ns_mem_word_size_t size;
|
||||
|
||||
platform_enter_critical();
|
||||
ptr --;
|
||||
//Read Current Size
|
||||
size = *ptr;
|
||||
if (!pointer_address_validate(book, ptr, size)) {
|
||||
heap_failure(book, NS_DYN_MEM_POINTER_NOT_VALID);
|
||||
} else if (size < 0) {
|
||||
heap_failure(book, NS_DYN_MEM_DOUBLE_FREE);
|
||||
} else {
|
||||
if (ns_mem_block_validate(ptr) != 0) {
|
||||
heap_failure(book, NS_DYN_MEM_HEAP_SECTOR_CORRUPTED);
|
||||
} else {
|
||||
ns_mem_free_and_merge_with_adjacent_blocks(book, ptr, size);
|
||||
if (book->mem_stat_info_ptr) {
|
||||
//Update Free Counter
|
||||
dev_stat_update(book->mem_stat_info_ptr, DEV_HEAP_FREE, (size + 2) * sizeof(ns_mem_word_size_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
platform_exit_critical();
|
||||
#else
|
||||
platform_enter_critical();
|
||||
free(block);
|
||||
platform_exit_critical();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ns_dyn_mem_free(void *block)
|
||||
{
|
||||
ns_mem_free(default_book, block);
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
// ----------------------------------------------------------------------------
|
||||
// Copyright 2016-2017 ARM Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include <ns_types.h>
|
||||
#include <nsdynmemLIB.h>
|
||||
#include "ns_list.h"
|
||||
#include "platform/arm_hal_nvm.h"
|
||||
#include "ns_nvm_helper.h"
|
||||
|
||||
#define TRACE_GROUP "nnvm"
|
||||
|
||||
/* NVM operations */
|
||||
#define NS_NVM_NONE 0x00
|
||||
#define NS_NVM_INIT 0x01
|
||||
#define NS_NVM_KEY_CREATE 0x02
|
||||
#define NS_NVM_KEY_READ 0x03
|
||||
#define NS_NVM_KEY_WRITE 0x04
|
||||
#define NS_NVM_FLUSH 0x05
|
||||
#define NS_NVM_KEY_DELETE 0x06
|
||||
|
||||
typedef struct {
|
||||
ns_nvm_callback *callback;
|
||||
const char *client_key_name;
|
||||
void *client_context;
|
||||
int operation;
|
||||
uint8_t *buffer;
|
||||
uint16_t *buffer_len;
|
||||
void *original_request;
|
||||
ns_list_link_t link;
|
||||
} ns_nvm_request_t;
|
||||
|
||||
static bool ns_nvm_initialized = false;
|
||||
static bool ns_nvm_operation_in_progress = false;
|
||||
|
||||
static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation);
|
||||
static int ns_nvm_operation_start(ns_nvm_request_t *request);
|
||||
static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request);
|
||||
static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval);
|
||||
|
||||
static NS_LIST_DEFINE(ns_nvm_request_list, ns_nvm_request_t, link);
|
||||
|
||||
/*
|
||||
* Callback from platform NVM adaptation
|
||||
*/
|
||||
void ns_nvm_callback_func(platform_nvm_status status, void *args)
|
||||
{
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = (ns_nvm_request_t *)args;
|
||||
int client_retval = NS_NVM_OK;
|
||||
|
||||
if (status == PLATFORM_NVM_ERROR) {
|
||||
client_retval = NS_NVM_ERROR;
|
||||
} else if (status == PLATFORM_NVM_KEY_NOT_FOUND) {
|
||||
client_retval = NS_NVM_DATA_NOT_FOUND;
|
||||
}
|
||||
|
||||
switch (ns_nvm_request_ptr->operation) {
|
||||
case NS_NVM_INIT:
|
||||
ns_nvm_operation_continue(ns_nvm_request_ptr->original_request, true);
|
||||
ns_dyn_mem_free(ns_nvm_request_ptr);
|
||||
break;
|
||||
case NS_NVM_FLUSH:
|
||||
case NS_NVM_KEY_READ:
|
||||
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
|
||||
break;
|
||||
case NS_NVM_KEY_CREATE:
|
||||
if (status == PLATFORM_NVM_OK) {
|
||||
ns_nvm_request_ptr->operation = NS_NVM_KEY_WRITE;
|
||||
platform_nvm_write(ns_nvm_callback_func, ns_nvm_request_ptr->client_key_name, ns_nvm_request_ptr->buffer, ns_nvm_request_ptr->buffer_len, ns_nvm_request_ptr);
|
||||
} else {
|
||||
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
|
||||
}
|
||||
break;
|
||||
case NS_NVM_KEY_DELETE:
|
||||
case NS_NVM_KEY_WRITE:
|
||||
if (status == PLATFORM_NVM_OK) {
|
||||
// write ok, flush the changes
|
||||
ns_nvm_request_ptr->operation = NS_NVM_FLUSH;
|
||||
platform_nvm_flush(ns_nvm_callback_func, ns_nvm_request_ptr);
|
||||
} else {
|
||||
// write failed, inform client
|
||||
ns_nvm_operation_end(ns_nvm_request_ptr, client_retval);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int ns_nvm_key_delete(ns_nvm_callback *callback, const char *key_name, void *context)
|
||||
{
|
||||
if (!callback || !key_name) {
|
||||
return NS_NVM_ERROR;
|
||||
}
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, NULL, NULL, NS_NVM_KEY_DELETE);
|
||||
return ns_nvm_operation_start(ns_nvm_request_ptr);
|
||||
}
|
||||
|
||||
int ns_nvm_data_read(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
|
||||
{
|
||||
if (!callback || !key_name || !buf || !buf_len) {
|
||||
return NS_NVM_ERROR;
|
||||
}
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_READ);
|
||||
return ns_nvm_operation_start(ns_nvm_request_ptr);
|
||||
}
|
||||
|
||||
int ns_nvm_data_write(ns_nvm_callback *callback, const char *key_name, uint8_t *buf, uint16_t *buf_len, void *context)
|
||||
{
|
||||
if (!callback || !key_name || !buf || !buf_len) {
|
||||
return NS_NVM_ERROR;
|
||||
}
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(callback, context, key_name, buf, buf_len, NS_NVM_KEY_WRITE);
|
||||
return ns_nvm_operation_start(ns_nvm_request_ptr);
|
||||
}
|
||||
|
||||
static int ns_nvm_operation_start(ns_nvm_request_t *nvm_request)
|
||||
{
|
||||
int ret = NS_NVM_OK;
|
||||
platform_nvm_status pnvm_status;
|
||||
|
||||
if (!nvm_request) {
|
||||
return NS_NVM_MEMORY;
|
||||
}
|
||||
if (ns_nvm_initialized == true) {
|
||||
// NVM already initialized, continue directly
|
||||
if (!ns_nvm_operation_in_progress) {
|
||||
ret = ns_nvm_operation_continue(nvm_request, true);
|
||||
} else {
|
||||
// add request to list and handle when existing calls has been handled.
|
||||
ns_list_add_to_end(&ns_nvm_request_list, nvm_request);
|
||||
}
|
||||
} else {
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = ns_nvm_create_request(NULL, NULL, NULL, NULL, NULL, NS_NVM_INIT);
|
||||
if (!ns_nvm_request_ptr) {
|
||||
ns_dyn_mem_free(nvm_request);
|
||||
ns_dyn_mem_free(ns_nvm_request_ptr);
|
||||
return NS_NVM_MEMORY;
|
||||
}
|
||||
ns_nvm_request_ptr->original_request = nvm_request;
|
||||
pnvm_status = platform_nvm_init(ns_nvm_callback_func, ns_nvm_request_ptr);
|
||||
if (pnvm_status != PLATFORM_NVM_OK) {
|
||||
ns_dyn_mem_free(nvm_request);
|
||||
ns_dyn_mem_free(ns_nvm_request_ptr);
|
||||
return NS_NVM_ERROR;
|
||||
}
|
||||
ns_list_init(&ns_nvm_request_list);
|
||||
ns_nvm_initialized = true;
|
||||
ns_nvm_operation_in_progress = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ns_nvm_request_t *ns_nvm_create_request(ns_nvm_callback *callback, void *context, const char *key_name, uint8_t *buf, uint16_t *buf_len, uint8_t operation)
|
||||
{
|
||||
ns_nvm_request_t *ns_nvm_request_ptr = ns_dyn_mem_temporary_alloc(sizeof(ns_nvm_request_t));
|
||||
if (!ns_nvm_request_ptr) {
|
||||
return NULL;
|
||||
}
|
||||
ns_nvm_request_ptr->client_context = context;
|
||||
ns_nvm_request_ptr->callback = callback;
|
||||
ns_nvm_request_ptr->client_key_name = key_name;
|
||||
ns_nvm_request_ptr->operation = operation;
|
||||
ns_nvm_request_ptr->buffer = buf;
|
||||
ns_nvm_request_ptr->buffer_len = buf_len;
|
||||
|
||||
return ns_nvm_request_ptr;
|
||||
}
|
||||
|
||||
static int ns_nvm_operation_continue(ns_nvm_request_t *request, bool free_request)
|
||||
{
|
||||
platform_nvm_status ret = PLATFORM_NVM_OK;
|
||||
|
||||
ns_nvm_operation_in_progress = true;
|
||||
switch (request->operation) {
|
||||
case NS_NVM_KEY_WRITE:
|
||||
request->operation = NS_NVM_KEY_CREATE;
|
||||
ret = platform_nvm_key_create(ns_nvm_callback_func, request->client_key_name, *request->buffer_len, 0, request);
|
||||
break;
|
||||
case NS_NVM_KEY_READ:
|
||||
ret = platform_nvm_read(ns_nvm_callback_func, request->client_key_name, request->buffer, request->buffer_len, request);
|
||||
break;
|
||||
case NS_NVM_KEY_DELETE:
|
||||
ret = platform_nvm_key_delete(ns_nvm_callback_func, request->client_key_name, request);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret != PLATFORM_NVM_OK) {
|
||||
if (free_request == true) {
|
||||
// free request if requested
|
||||
ns_dyn_mem_free(request);
|
||||
}
|
||||
ns_nvm_operation_in_progress = false;
|
||||
return NS_NVM_ERROR;
|
||||
}
|
||||
|
||||
return NS_NVM_OK;
|
||||
}
|
||||
|
||||
static void ns_nvm_operation_end(ns_nvm_request_t *ns_nvm_request_ptr, int client_retval)
|
||||
{
|
||||
ns_nvm_request_ptr->callback(client_retval, ns_nvm_request_ptr->client_context);
|
||||
ns_dyn_mem_free(ns_nvm_request_ptr);
|
||||
ns_nvm_operation_in_progress = false;
|
||||
|
||||
ns_list_foreach_safe(ns_nvm_request_t, pending_req, &ns_nvm_request_list) {
|
||||
// there are pending requests to be processed
|
||||
ns_list_remove(&ns_nvm_request_list, pending_req);
|
||||
int ret = ns_nvm_operation_continue(pending_req, false);
|
||||
if (ret != NS_NVM_OK) {
|
||||
ns_nvm_operation_end(pending_req, ret);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
coverages/*
|
||||
*/gcov/*
|
||||
results/*
|
||||
*.xml
|
||||
*/*_unit_tests
|
||||
*/*_unit_tests.txt
|
||||
*/lib
|
||||
*/objs
|
|
@ -0,0 +1,23 @@
|
|||
#scan for folders having "Makefile" in them and remove 'this' to prevent loop
|
||||
ifeq ($(OS),Windows_NT)
|
||||
all:
|
||||
clean:
|
||||
else
|
||||
DIRS := $(filter-out ./, $(sort $(dir $(shell find . -name 'Makefile'))))
|
||||
|
||||
all:
|
||||
for dir in $(DIRS); do \
|
||||
cd $$dir; make gcov; cd ..;\
|
||||
done
|
||||
|
||||
clean:
|
||||
for dir in $(DIRS); do \
|
||||
cd $$dir; make clean; cd ..;\
|
||||
done
|
||||
rm -rf ../source/*gcov ../source/*gcda ../source/*o
|
||||
rm -rf stubs/*gcov stubs/*gcda stubs/*o
|
||||
rm -rf results/*
|
||||
rm -rf coverages/*
|
||||
rm -rf results
|
||||
rm -rf coverages
|
||||
endif
|
|
@ -0,0 +1,562 @@
|
|||
#---------
|
||||
#
|
||||
# MakefileWorker.mk
|
||||
#
|
||||
# Include this helper file in your makefile
|
||||
# It makes
|
||||
# A static library
|
||||
# A test executable
|
||||
#
|
||||
# See this example for parameter settings
|
||||
# examples/Makefile
|
||||
#
|
||||
#----------
|
||||
# Inputs - these variables describe what to build
|
||||
#
|
||||
# INCLUDE_DIRS - Directories used to search for include files.
|
||||
# This generates a -I for each directory
|
||||
# SRC_DIRS - Directories containing source file to built into the library
|
||||
# SRC_FILES - Specific source files to build into library. Helpful when not all code
|
||||
# in a directory can be built for test (hopefully a temporary situation)
|
||||
# TEST_SRC_DIRS - Directories containing unit test code build into the unit test runner
|
||||
# These do not go in a library. They are explicitly included in the test runner
|
||||
# TEST_SRC_FILES - Specific source files to build into the unit test runner
|
||||
# These do not go in a library. They are explicitly included in the test runner
|
||||
# MOCKS_SRC_DIRS - Directories containing mock source files to build into the test runner
|
||||
# These do not go in a library. They are explicitly included in the test runner
|
||||
#----------
|
||||
# You can adjust these variables to influence how to build the test target
|
||||
# and where to put and name outputs
|
||||
# See below to determine defaults
|
||||
# COMPONENT_NAME - the name of the thing being built
|
||||
# TEST_TARGET - name the test executable. By default it is
|
||||
# $(COMPONENT_NAME)_tests
|
||||
# Helpful if you want 1 > make files in the same directory with different
|
||||
# executables as output.
|
||||
# CPPUTEST_HOME - where CppUTest home dir found
|
||||
# TARGET_PLATFORM - Influences how the outputs are generated by modifying the
|
||||
# CPPUTEST_OBJS_DIR and CPPUTEST_LIB_DIR to use a sub-directory under the
|
||||
# normal objs and lib directories. Also modifies where to search for the
|
||||
# CPPUTEST_LIB to link against.
|
||||
# CPPUTEST_OBJS_DIR - a directory where o and d files go
|
||||
# CPPUTEST_LIB_DIR - a directory where libs go
|
||||
# CPPUTEST_ENABLE_DEBUG - build for debug
|
||||
# CPPUTEST_USE_MEM_LEAK_DETECTION - Links with overridden new and delete
|
||||
# CPPUTEST_USE_STD_CPP_LIB - Set to N to keep the standard C++ library out
|
||||
# of the test harness
|
||||
# CPPUTEST_USE_GCOV - Turn on coverage analysis
|
||||
# Clean then build with this flag set to Y, then 'make gcov'
|
||||
# CPPUTEST_MAPFILE - generate a map file
|
||||
# CPPUTEST_WARNINGFLAGS - overly picky by default
|
||||
# OTHER_MAKEFILE_TO_INCLUDE - a hook to use this makefile to make
|
||||
# other targets. Like CSlim, which is part of fitnesse
|
||||
# CPPUTEST_USE_VPATH - Use Make's VPATH functionality to support user
|
||||
# specification of source files and directories that aren't below
|
||||
# the user's Makefile in the directory tree, like:
|
||||
# SRC_DIRS += ../../lib/foo
|
||||
# It defaults to N, and shouldn't be necessary except in the above case.
|
||||
#----------
|
||||
#
|
||||
# Other flags users can initialize to sneak in their settings
|
||||
# CPPUTEST_CXXFLAGS - flags for the C++ compiler
|
||||
# CPPUTEST_CPPFLAGS - flags for the C++ AND C preprocessor
|
||||
# CPPUTEST_CFLAGS - flags for the C complier
|
||||
# CPPUTEST_LDFLAGS - Linker flags
|
||||
#----------
|
||||
|
||||
# Some behavior is weird on some platforms. Need to discover the platform.
|
||||
|
||||
# Platforms
|
||||
UNAME_OUTPUT = "$(shell uname -a)"
|
||||
MACOSX_STR = Darwin
|
||||
MINGW_STR = MINGW
|
||||
CYGWIN_STR = CYGWIN
|
||||
LINUX_STR = Linux
|
||||
SUNOS_STR = SunOS
|
||||
UNKNWOWN_OS_STR = Unknown
|
||||
|
||||
# Compilers
|
||||
CC_VERSION_OUTPUT ="$(shell $(CXX) -v 2>&1)"
|
||||
CLANG_STR = clang
|
||||
SUNSTUDIO_CXX_STR = SunStudio
|
||||
|
||||
UNAME_OS = $(UNKNWOWN_OS_STR)
|
||||
|
||||
ifeq ($(findstring $(MINGW_STR),$(UNAME_OUTPUT)),$(MINGW_STR))
|
||||
UNAME_OS = $(MINGW_STR)
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(CYGWIN_STR),$(UNAME_OUTPUT)),$(CYGWIN_STR))
|
||||
UNAME_OS = $(CYGWIN_STR)
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(LINUX_STR),$(UNAME_OUTPUT)),$(LINUX_STR))
|
||||
UNAME_OS = $(LINUX_STR)
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(MACOSX_STR),$(UNAME_OUTPUT)),$(MACOSX_STR))
|
||||
UNAME_OS = $(MACOSX_STR)
|
||||
#lion has a problem with the 'v' part of -a
|
||||
UNAME_OUTPUT = "$(shell uname -pmnrs)"
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(SUNOS_STR),$(UNAME_OUTPUT)),$(SUNOS_STR))
|
||||
UNAME_OS = $(SUNOS_STR)
|
||||
|
||||
SUNSTUDIO_CXX_ERR_STR = CC -flags
|
||||
ifeq ($(findstring $(SUNSTUDIO_CXX_ERR_STR),$(CC_VERSION_OUTPUT)),$(SUNSTUDIO_CXX_ERR_STR))
|
||||
CC_VERSION_OUTPUT ="$(shell $(CXX) -V 2>&1)"
|
||||
COMPILER_NAME = $(SUNSTUDIO_CXX_STR)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(findstring $(CLANG_STR),$(CC_VERSION_OUTPUT)),$(CLANG_STR))
|
||||
COMPILER_NAME = $(CLANG_STR)
|
||||
endif
|
||||
|
||||
#Kludge for mingw, it does not have cc.exe, but gcc.exe will do
|
||||
ifeq ($(UNAME_OS),$(MINGW_STR))
|
||||
CC := gcc
|
||||
endif
|
||||
|
||||
#And another kludge. Exception handling in gcc 4.6.2 is broken when linking the
|
||||
# Standard C++ library as a shared library. Unbelievable.
|
||||
ifeq ($(UNAME_OS),$(MINGW_STR))
|
||||
CPPUTEST_LDFLAGS += -static
|
||||
endif
|
||||
ifeq ($(UNAME_OS),$(CYGWIN_STR))
|
||||
CPPUTEST_LDFLAGS += -static
|
||||
endif
|
||||
|
||||
|
||||
#Kludge for MacOsX gcc compiler on Darwin9 who can't handle pendantic
|
||||
ifeq ($(UNAME_OS),$(MACOSX_STR))
|
||||
ifeq ($(findstring Version 9,$(UNAME_OUTPUT)),Version 9)
|
||||
CPPUTEST_PEDANTIC_ERRORS = N
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef COMPONENT_NAME
|
||||
COMPONENT_NAME = name_this_in_the_makefile
|
||||
endif
|
||||
|
||||
# Debug on by default
|
||||
ifndef CPPUTEST_ENABLE_DEBUG
|
||||
CPPUTEST_ENABLE_DEBUG = Y
|
||||
endif
|
||||
|
||||
# new and delete for memory leak detection on by default
|
||||
ifndef CPPUTEST_USE_MEM_LEAK_DETECTION
|
||||
CPPUTEST_USE_MEM_LEAK_DETECTION = Y
|
||||
endif
|
||||
|
||||
# Use the standard C library
|
||||
ifndef CPPUTEST_USE_STD_C_LIB
|
||||
CPPUTEST_USE_STD_C_LIB = Y
|
||||
endif
|
||||
|
||||
# Use the standard C++ library
|
||||
ifndef CPPUTEST_USE_STD_CPP_LIB
|
||||
CPPUTEST_USE_STD_CPP_LIB = Y
|
||||
endif
|
||||
|
||||
# Use gcov, off by default
|
||||
ifndef CPPUTEST_USE_GCOV
|
||||
CPPUTEST_USE_GCOV = N
|
||||
endif
|
||||
|
||||
ifndef CPPUTEST_PEDANTIC_ERRORS
|
||||
CPPUTEST_PEDANTIC_ERRORS = Y
|
||||
endif
|
||||
|
||||
# Default warnings
|
||||
ifndef CPPUTEST_WARNINGFLAGS
|
||||
CPPUTEST_WARNINGFLAGS = -Wall -Wextra -Wshadow -Wswitch-default -Wswitch-enum -Wconversion
|
||||
ifeq ($(CPPUTEST_PEDANTIC_ERRORS), Y)
|
||||
# CPPUTEST_WARNINGFLAGS += -pedantic-errors
|
||||
CPPUTEST_WARNINGFLAGS += -pedantic
|
||||
endif
|
||||
ifeq ($(UNAME_OS),$(LINUX_STR))
|
||||
CPPUTEST_WARNINGFLAGS += -Wsign-conversion
|
||||
endif
|
||||
CPPUTEST_CXX_WARNINGFLAGS = -Woverloaded-virtual
|
||||
CPPUTEST_C_WARNINGFLAGS = -Wstrict-prototypes
|
||||
endif
|
||||
|
||||
#Wonderful extra compiler warnings with clang
|
||||
ifeq ($(COMPILER_NAME),$(CLANG_STR))
|
||||
# -Wno-disabled-macro-expansion -> Have to disable the macro expansion warning as the operator new overload warns on that.
|
||||
# -Wno-padded -> I sort-of like this warning but if there is a bool at the end of the class, it seems impossible to remove it! (except by making padding explicit)
|
||||
# -Wno-global-constructors Wno-exit-time-destructors -> Great warnings, but in CppUTest it is impossible to avoid as the automatic test registration depends on the global ctor and dtor
|
||||
# -Wno-weak-vtables -> The TEST_GROUP macro declares a class and will automatically inline its methods. Thats ok as they are only in one translation unit. Unfortunately, the warning can't detect that, so it must be disabled.
|
||||
CPPUTEST_CXX_WARNINGFLAGS += -Weverything -Wno-disabled-macro-expansion -Wno-padded -Wno-global-constructors -Wno-exit-time-destructors -Wno-weak-vtables
|
||||
CPPUTEST_C_WARNINGFLAGS += -Weverything -Wno-padded
|
||||
endif
|
||||
|
||||
# Uhm. Maybe put some warning flags for SunStudio here?
|
||||
ifeq ($(COMPILER_NAME),$(SUNSTUDIO_CXX_STR))
|
||||
CPPUTEST_CXX_WARNINGFLAGS =
|
||||
CPPUTEST_C_WARNINGFLAGS =
|
||||
endif
|
||||
|
||||
# Default dir for temporary files (d, o)
|
||||
ifndef CPPUTEST_OBJS_DIR
|
||||
ifndef TARGET_PLATFORM
|
||||
CPPUTEST_OBJS_DIR = objs
|
||||
else
|
||||
CPPUTEST_OBJS_DIR = objs/$(TARGET_PLATFORM)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Default dir for the outout library
|
||||
ifndef CPPUTEST_LIB_DIR
|
||||
ifndef TARGET_PLATFORM
|
||||
CPPUTEST_LIB_DIR = lib
|
||||
else
|
||||
CPPUTEST_LIB_DIR = lib/$(TARGET_PLATFORM)
|
||||
endif
|
||||
endif
|
||||
|
||||
# No map by default
|
||||
ifndef CPPUTEST_MAP_FILE
|
||||
CPPUTEST_MAP_FILE = N
|
||||
endif
|
||||
|
||||
# No extentions is default
|
||||
ifndef CPPUTEST_USE_EXTENSIONS
|
||||
CPPUTEST_USE_EXTENSIONS = N
|
||||
endif
|
||||
|
||||
# No VPATH is default
|
||||
ifndef CPPUTEST_USE_VPATH
|
||||
CPPUTEST_USE_VPATH := N
|
||||
endif
|
||||
# Make empty, instead of 'N', for usage in $(if ) conditionals
|
||||
ifneq ($(CPPUTEST_USE_VPATH), Y)
|
||||
CPPUTEST_USE_VPATH :=
|
||||
endif
|
||||
|
||||
ifndef TARGET_PLATFORM
|
||||
#CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib
|
||||
CPPUTEST_LIB_LINK_DIR = /usr/lib/x86_64-linux-gnu
|
||||
else
|
||||
CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib/$(TARGET_PLATFORM)
|
||||
endif
|
||||
|
||||
# --------------------------------------
|
||||
# derived flags in the following area
|
||||
# --------------------------------------
|
||||
|
||||
# Without the C library, we'll need to disable the C++ library and ...
|
||||
ifeq ($(CPPUTEST_USE_STD_C_LIB), N)
|
||||
CPPUTEST_USE_STD_CPP_LIB = N
|
||||
CPPUTEST_USE_MEM_LEAK_DETECTION = N
|
||||
CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_C_LIB_DISABLED
|
||||
CPPUTEST_CPPFLAGS += -nostdinc
|
||||
endif
|
||||
|
||||
CPPUTEST_CPPFLAGS += -DCPPUTEST_COMPILATION
|
||||
|
||||
ifeq ($(CPPUTEST_USE_MEM_LEAK_DETECTION), N)
|
||||
CPPUTEST_CPPFLAGS += -DCPPUTEST_MEM_LEAK_DETECTION_DISABLED
|
||||
else
|
||||
ifndef CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE
|
||||
CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h
|
||||
endif
|
||||
ifndef CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE
|
||||
CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CPPUTEST_ENABLE_DEBUG), Y)
|
||||
CPPUTEST_CXXFLAGS += -g
|
||||
CPPUTEST_CFLAGS += -g
|
||||
CPPUTEST_LDFLAGS += -g
|
||||
endif
|
||||
|
||||
ifeq ($(CPPUTEST_USE_STD_CPP_LIB), N)
|
||||
CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_CPP_LIB_DISABLED
|
||||
ifeq ($(CPPUTEST_USE_STD_C_LIB), Y)
|
||||
CPPUTEST_CXXFLAGS += -nostdinc++
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef $(GMOCK_HOME)
|
||||
GTEST_HOME = $(GMOCK_HOME)/gtest
|
||||
CPPUTEST_CPPFLAGS += -I$(GMOCK_HOME)/include
|
||||
GMOCK_LIBRARY = $(GMOCK_HOME)/lib/.libs/libgmock.a
|
||||
LD_LIBRARIES += $(GMOCK_LIBRARY)
|
||||
CPPUTEST_CPPFLAGS += -DINCLUDE_GTEST_TESTS
|
||||
CPPUTEST_WARNINGFLAGS =
|
||||
CPPUTEST_CPPFLAGS += -I$(GTEST_HOME)/include -I$(GTEST_HOME)
|
||||
GTEST_LIBRARY = $(GTEST_HOME)/lib/.libs/libgtest.a
|
||||
LD_LIBRARIES += $(GTEST_LIBRARY)
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CPPUTEST_USE_GCOV), Y)
|
||||
CPPUTEST_CXXFLAGS += -fprofile-arcs -ftest-coverage
|
||||
CPPUTEST_CFLAGS += -fprofile-arcs -ftest-coverage
|
||||
endif
|
||||
|
||||
CPPUTEST_CXXFLAGS += $(CPPUTEST_WARNINGFLAGS) $(CPPUTEST_CXX_WARNINGFLAGS)
|
||||
CPPUTEST_CPPFLAGS += $(CPPUTEST_WARNINGFLAGS)
|
||||
CPPUTEST_CXXFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE)
|
||||
CPPUTEST_CPPFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE)
|
||||
CPPUTEST_CFLAGS += $(CPPUTEST_C_WARNINGFLAGS)
|
||||
|
||||
TARGET_MAP = $(COMPONENT_NAME).map.txt
|
||||
ifeq ($(CPPUTEST_MAP_FILE), Y)
|
||||
CPPUTEST_LDFLAGS += -Wl,-map,$(TARGET_MAP)
|
||||
endif
|
||||
|
||||
# Link with CppUTest lib
|
||||
CPPUTEST_LIB = $(CPPUTEST_LIB_LINK_DIR)/libCppUTest.a
|
||||
|
||||
ifeq ($(CPPUTEST_USE_EXTENSIONS), Y)
|
||||
CPPUTEST_LIB += $(CPPUTEST_LIB_LINK_DIR)/libCppUTestExt.a
|
||||
endif
|
||||
|
||||
ifdef CPPUTEST_STATIC_REALTIME
|
||||
LD_LIBRARIES += -lrt
|
||||
endif
|
||||
|
||||
TARGET_LIB = \
|
||||
$(CPPUTEST_LIB_DIR)/lib$(COMPONENT_NAME).a
|
||||
|
||||
ifndef TEST_TARGET
|
||||
ifndef TARGET_PLATFORM
|
||||
TEST_TARGET = $(COMPONENT_NAME)_tests
|
||||
else
|
||||
TEST_TARGET = $(COMPONENT_NAME)_$(TARGET_PLATFORM)_tests
|
||||
endif
|
||||
endif
|
||||
|
||||
#Helper Functions
|
||||
get_src_from_dir = $(wildcard $1/*.cpp) $(wildcard $1/*.cc) $(wildcard $1/*.c)
|
||||
get_dirs_from_dirspec = $(wildcard $1)
|
||||
get_src_from_dir_list = $(foreach dir, $1, $(call get_src_from_dir,$(dir)))
|
||||
__src_to = $(subst .c,$1, $(subst .cc,$1, $(subst .cpp,$1,$(if $(CPPUTEST_USE_VPATH),$(notdir $2),$2))))
|
||||
src_to = $(addprefix $(CPPUTEST_OBJS_DIR)/,$(call __src_to,$1,$2))
|
||||
src_to_o = $(call src_to,.o,$1)
|
||||
src_to_d = $(call src_to,.d,$1)
|
||||
src_to_gcda = $(call src_to,.gcda,$1)
|
||||
src_to_gcno = $(call src_to,.gcno,$1)
|
||||
time = $(shell date +%s)
|
||||
delta_t = $(eval minus, $1, $2)
|
||||
debug_print_list = $(foreach word,$1,echo " $(word)";) echo;
|
||||
|
||||
#Derived
|
||||
STUFF_TO_CLEAN += $(TEST_TARGET) $(TEST_TARGET).exe $(TARGET_LIB) $(TARGET_MAP)
|
||||
|
||||
SRC += $(call get_src_from_dir_list, $(SRC_DIRS)) $(SRC_FILES)
|
||||
OBJ = $(call src_to_o,$(SRC))
|
||||
|
||||
STUFF_TO_CLEAN += $(OBJ)
|
||||
|
||||
TEST_SRC += $(call get_src_from_dir_list, $(TEST_SRC_DIRS)) $(TEST_SRC_FILES)
|
||||
TEST_OBJS = $(call src_to_o,$(TEST_SRC))
|
||||
STUFF_TO_CLEAN += $(TEST_OBJS)
|
||||
|
||||
|
||||
MOCKS_SRC += $(call get_src_from_dir_list, $(MOCKS_SRC_DIRS))
|
||||
MOCKS_OBJS = $(call src_to_o,$(MOCKS_SRC))
|
||||
STUFF_TO_CLEAN += $(MOCKS_OBJS)
|
||||
|
||||
ALL_SRC = $(SRC) $(TEST_SRC) $(MOCKS_SRC)
|
||||
|
||||
# If we're using VPATH
|
||||
ifeq ($(CPPUTEST_USE_VPATH), Y)
|
||||
# gather all the source directories and add them
|
||||
VPATH += $(sort $(dir $(ALL_SRC)))
|
||||
# Add the component name to the objs dir path, to differentiate between same-name objects
|
||||
CPPUTEST_OBJS_DIR := $(addsuffix /$(COMPONENT_NAME),$(CPPUTEST_OBJS_DIR))
|
||||
endif
|
||||
|
||||
#Test coverage with gcov
|
||||
GCOV_OUTPUT = gcov_output.txt
|
||||
GCOV_REPORT = gcov_report.txt
|
||||
GCOV_ERROR = gcov_error.txt
|
||||
GCOV_GCDA_FILES = $(call src_to_gcda, $(ALL_SRC))
|
||||
GCOV_GCNO_FILES = $(call src_to_gcno, $(ALL_SRC))
|
||||
TEST_OUTPUT = $(TEST_TARGET).txt
|
||||
STUFF_TO_CLEAN += \
|
||||
$(GCOV_OUTPUT)\
|
||||
$(GCOV_REPORT)\
|
||||
$(GCOV_REPORT).html\
|
||||
$(GCOV_ERROR)\
|
||||
$(GCOV_GCDA_FILES)\
|
||||
$(GCOV_GCNO_FILES)\
|
||||
$(TEST_OUTPUT)
|
||||
|
||||
#The gcda files for gcov need to be deleted before each run
|
||||
#To avoid annoying messages.
|
||||
GCOV_CLEAN = $(SILENCE)rm -f $(GCOV_GCDA_FILES) $(GCOV_OUTPUT) $(GCOV_REPORT) $(GCOV_ERROR)
|
||||
RUN_TEST_TARGET = $(SILENCE) $(GCOV_CLEAN) ; echo "Running $(TEST_TARGET)"; ./$(TEST_TARGET) $(CPPUTEST_EXE_FLAGS) -ojunit
|
||||
|
||||
ifeq ($(CPPUTEST_USE_GCOV), Y)
|
||||
|
||||
ifeq ($(COMPILER_NAME),$(CLANG_STR))
|
||||
LD_LIBRARIES += --coverage
|
||||
else
|
||||
LD_LIBRARIES += -lgcov
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
INCLUDES_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(INCLUDE_DIRS))
|
||||
INCLUDES += $(foreach dir, $(INCLUDES_DIRS_EXPANDED), -I$(dir))
|
||||
MOCK_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(MOCKS_SRC_DIRS))
|
||||
INCLUDES += $(foreach dir, $(MOCK_DIRS_EXPANDED), -I$(dir))
|
||||
|
||||
CPPUTEST_CPPFLAGS += $(INCLUDES) $(CPPUTESTFLAGS)
|
||||
|
||||
DEP_FILES = $(call src_to_d, $(ALL_SRC))
|
||||
STUFF_TO_CLEAN += $(DEP_FILES) $(PRODUCTION_CODE_START) $(PRODUCTION_CODE_END)
|
||||
STUFF_TO_CLEAN += $(STDLIB_CODE_START) $(MAP_FILE) cpputest_*.xml junit_run_output
|
||||
|
||||
# We'll use the CPPUTEST_CFLAGS etc so that you can override AND add to the CppUTest flags
|
||||
CFLAGS = $(CPPUTEST_CFLAGS) $(CPPUTEST_ADDITIONAL_CFLAGS)
|
||||
CPPFLAGS = $(CPPUTEST_CPPFLAGS) $(CPPUTEST_ADDITIONAL_CPPFLAGS)
|
||||
CXXFLAGS = $(CPPUTEST_CXXFLAGS) $(CPPUTEST_ADDITIONAL_CXXFLAGS)
|
||||
LDFLAGS = $(CPPUTEST_LDFLAGS) $(CPPUTEST_ADDITIONAL_LDFLAGS)
|
||||
|
||||
# Don't consider creating the archive a warning condition that does STDERR output
|
||||
ARFLAGS := $(ARFLAGS)c
|
||||
|
||||
DEP_FLAGS=-MMD -MP
|
||||
|
||||
# Some macros for programs to be overridden. For some reason, these are not in Make defaults
|
||||
RANLIB = ranlib
|
||||
|
||||
# Targets
|
||||
|
||||
.PHONY: all
|
||||
all: start $(TEST_TARGET)
|
||||
$(RUN_TEST_TARGET)
|
||||
|
||||
.PHONY: start
|
||||
start: $(TEST_TARGET)
|
||||
$(SILENCE)START_TIME=$(call time)
|
||||
|
||||
.PHONY: all_no_tests
|
||||
all_no_tests: $(TEST_TARGET)
|
||||
|
||||
.PHONY: flags
|
||||
flags:
|
||||
@echo
|
||||
@echo "OS ${UNAME_OS}"
|
||||
@echo "Compile C and C++ source with CPPFLAGS:"
|
||||
@$(call debug_print_list,$(CPPFLAGS))
|
||||
@echo "Compile C++ source with CXXFLAGS:"
|
||||
@$(call debug_print_list,$(CXXFLAGS))
|
||||
@echo "Compile C source with CFLAGS:"
|
||||
@$(call debug_print_list,$(CFLAGS))
|
||||
@echo "Link with LDFLAGS:"
|
||||
@$(call debug_print_list,$(LDFLAGS))
|
||||
@echo "Link with LD_LIBRARIES:"
|
||||
@$(call debug_print_list,$(LD_LIBRARIES))
|
||||
@echo "Create libraries with ARFLAGS:"
|
||||
@$(call debug_print_list,$(ARFLAGS))
|
||||
|
||||
TEST_DEPS = $(TEST_OBJS) $(MOCKS_OBJS) $(PRODUCTION_CODE_START) $(TARGET_LIB) $(USER_LIBS) $(PRODUCTION_CODE_END) $(CPPUTEST_LIB) $(STDLIB_CODE_START)
|
||||
test-deps: $(TEST_DEPS)
|
||||
|
||||
$(TEST_TARGET): $(TEST_DEPS)
|
||||
@echo Linking $@
|
||||
$(SILENCE)$(CXX) -o $@ $^ $(LD_LIBRARIES) $(LDFLAGS)
|
||||
|
||||
$(TARGET_LIB): $(OBJ)
|
||||
@echo Building archive $@
|
||||
$(SILENCE)mkdir -p $(dir $@)
|
||||
$(SILENCE)$(AR) $(ARFLAGS) $@ $^
|
||||
$(SILENCE)$(RANLIB) $@
|
||||
|
||||
test: $(TEST_TARGET)
|
||||
$(RUN_TEST_TARGET) | tee $(TEST_OUTPUT)
|
||||
|
||||
vtest: $(TEST_TARGET)
|
||||
$(RUN_TEST_TARGET) -v | tee $(TEST_OUTPUT)
|
||||
|
||||
$(CPPUTEST_OBJS_DIR)/%.o: %.cc
|
||||
@echo compiling $(notdir $<)
|
||||
$(SILENCE)mkdir -p $(dir $@)
|
||||
$(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(CPPUTEST_OBJS_DIR)/%.o: %.cpp
|
||||
@echo compiling $(notdir $<)
|
||||
$(SILENCE)mkdir -p $(dir $@)
|
||||
$(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(CPPUTEST_OBJS_DIR)/%.o: %.c
|
||||
@echo compiling $(notdir $<)
|
||||
$(SILENCE)mkdir -p $(dir $@)
|
||||
$(SILENCE)$(COMPILE.c) $(DEP_FLAGS) $(OUTPUT_OPTION) $<
|
||||
|
||||
ifneq "$(MAKECMDGOALS)" "clean"
|
||||
-include $(DEP_FILES)
|
||||
endif
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo Making clean
|
||||
$(SILENCE)$(RM) $(STUFF_TO_CLEAN)
|
||||
$(SILENCE)rm -rf gcov objs #$(CPPUTEST_OBJS_DIR)
|
||||
$(SILENCE)rm -rf $(CPPUTEST_LIB_DIR)
|
||||
$(SILENCE)find . -name "*.gcno" | xargs rm -f
|
||||
$(SILENCE)find . -name "*.gcda" | xargs rm -f
|
||||
|
||||
#realclean gets rid of all gcov, o and d files in the directory tree
|
||||
#not just the ones made by this makefile
|
||||
.PHONY: realclean
|
||||
realclean: clean
|
||||
$(SILENCE)rm -rf gcov
|
||||
$(SILENCE)find . -name "*.gdcno" | xargs rm -f
|
||||
$(SILENCE)find . -name "*.[do]" | xargs rm -f
|
||||
|
||||
gcov: test
|
||||
ifeq ($(CPPUTEST_USE_VPATH), Y)
|
||||
$(SILENCE)gcov --object-directory $(CPPUTEST_OBJS_DIR) $(SRC) >> $(GCOV_OUTPUT) 2>> $(GCOV_ERROR)
|
||||
else
|
||||
$(SILENCE)for d in $(SRC_DIRS) ; do \
|
||||
gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$d $$d/*.c $$d/*.cpp >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \
|
||||
done
|
||||
$(SILENCE)for f in $(SRC_FILES) ; do \
|
||||
gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$f $$f >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \
|
||||
done
|
||||
endif
|
||||
# $(CPPUTEST_HOME)/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT)
|
||||
/usr/share/cpputest/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT)
|
||||
$(SILENCE)cat $(GCOV_REPORT)
|
||||
$(SILENCE)mkdir -p gcov
|
||||
$(SILENCE)mv *.gcov gcov
|
||||
$(SILENCE)mv gcov_* gcov
|
||||
@echo "See gcov directory for details"
|
||||
|
||||
.PHONEY: format
|
||||
format:
|
||||
$(CPPUTEST_HOME)/scripts/reformat.sh $(PROJECT_HOME_DIR)
|
||||
|
||||
.PHONEY: debug
|
||||
debug:
|
||||
@echo
|
||||
@echo "Target Source files:"
|
||||
@$(call debug_print_list,$(SRC))
|
||||
@echo "Target Object files:"
|
||||
@$(call debug_print_list,$(OBJ))
|
||||
@echo "Test Source files:"
|
||||
@$(call debug_print_list,$(TEST_SRC))
|
||||
@echo "Test Object files:"
|
||||
@$(call debug_print_list,$(TEST_OBJS))
|
||||
@echo "Mock Source files:"
|
||||
@$(call debug_print_list,$(MOCKS_SRC))
|
||||
@echo "Mock Object files:"
|
||||
@$(call debug_print_list,$(MOCKS_OBJS))
|
||||
@echo "All Input Dependency files:"
|
||||
@$(call debug_print_list,$(DEP_FILES))
|
||||
@echo Stuff to clean:
|
||||
@$(call debug_print_list,$(STUFF_TO_CLEAN))
|
||||
@echo Includes:
|
||||
@$(call debug_print_list,$(INCLUDES))
|
||||
|
||||
-include $(OTHER_MAKEFILE_TO_INCLUDE)
|
|
@ -0,0 +1,21 @@
|
|||
include ../makefile_defines.txt
|
||||
|
||||
COMPONENT_NAME = ip6tos_unit
|
||||
SRC_FILES = \
|
||||
../../../../source/libip6string/ip6tos.c
|
||||
|
||||
TEST_SRC_FILES = \
|
||||
main.cpp \
|
||||
ip6tos_test.cpp \
|
||||
../../../../source/libBits/common_functions.c
|
||||
# ../stubs/some_stub.c \
|
||||
|
||||
# XXX: without this, the CppUTest complains for memory leak even without one.
|
||||
# The funny thing is that the CppUTest does not find the memory leak on
|
||||
# this app when there actually is one.
|
||||
CPPUTEST_USE_MEM_LEAK_DETECTION = N
|
||||
|
||||
include ../MakefileWorker.mk
|
||||
|
||||
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "ip6string.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
TEST_GROUP(ip6tos)
|
||||
{
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ip6tos, ip6_prefix_tos_func)
|
||||
{
|
||||
char prefix_str[45] = {0};
|
||||
char str_len = 0;
|
||||
char *expected;
|
||||
|
||||
uint8_t prefix[] = { 0x14, 0x6e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
int prefix_len = 64;
|
||||
expected = "146e:a00::/64";
|
||||
str_len = ip6_prefix_tos(prefix, prefix_len, prefix_str);
|
||||
CHECK(str_len == 13);
|
||||
STRCMP_EQUAL(expected, prefix_str);
|
||||
|
||||
memset(prefix_str, 0, 45);
|
||||
str_len = 0;
|
||||
expected = "::/0";
|
||||
str_len = ip6_prefix_tos(NULL, 0, prefix_str);
|
||||
CHECK(str_len == 4);
|
||||
STRCMP_EQUAL(expected, prefix_str);
|
||||
|
||||
str_len = 0;
|
||||
uint8_t prefix_2[16];
|
||||
memset(prefix_2, 0x88, 16);
|
||||
expected = "8888:8888:8888:8888:8888:8888:8888:8888/128";
|
||||
str_len = ip6_prefix_tos(prefix_2, 128, prefix_str);
|
||||
CHECK(str_len == 43);
|
||||
STRCMP_EQUAL(expected, prefix_str);
|
||||
|
||||
memset(prefix_str, 0, 45);
|
||||
str_len = ip6_prefix_tos(prefix, 130, prefix_str);
|
||||
CHECK(str_len == 0);
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Second test group for the old tests that were once lost */
|
||||
|
||||
const char string_addr[][40] = {
|
||||
"2001:db8::1:0:0:1", // 1
|
||||
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", // 2
|
||||
"2001:db8::1", // 3
|
||||
"2001:db8::2:1", // 4
|
||||
"2001:db8:aaaa:bbbb:cccc:dddd:0:1", // 5
|
||||
"2001:db8::aaaa:0:0:1", // 6
|
||||
"2001:0:0:1::1", // 7
|
||||
"2001:0:0:1::", // 8
|
||||
"2001:db8::", // 9
|
||||
"::aaaa:0:0:1", // 10
|
||||
"::1", // 11
|
||||
"::", // 12
|
||||
};
|
||||
|
||||
|
||||
const uint8_t hex_addr[][16] = {
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0x00, 0x01 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0, 0, 0x00, 0x01 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
char buf[40];
|
||||
int i = 0;
|
||||
|
||||
TEST_GROUP(ip6tos_2)
|
||||
{
|
||||
void setUp(void) {
|
||||
memset(buf, 0, 40);
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
i++;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(ip6tos_2, test_1)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
|
||||
TEST(ip6tos_2, test_2)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_3)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_4)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_5)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_6)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_7)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_8)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_9)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_10)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_11)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
||||
TEST(ip6tos_2, test_12)
|
||||
{
|
||||
CHECK(strlen(string_addr[i]) == ip6tos(hex_addr[i], buf));
|
||||
STRCMP_EQUAL(string_addr[i], buf);
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
#include "CppUTest/TestPlugin.h"
|
||||
#include "CppUTest/TestRegistry.h"
|
||||
#include "CppUTestExt/MockSupportPlugin.h"
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
return CommandLineTestRunner::RunAllTests(ac, av);
|
||||
}
|
||||
|
||||
IMPORT_TEST_GROUP(ip6tos);
|
||||
IMPORT_TEST_GROUP(ip6tos_2);
|
|
@ -0,0 +1,20 @@
|
|||
#--- Inputs ----#
|
||||
MBED_TRACE_HOME = ../../../../../mbed-trace
|
||||
CPPUTEST_HOME = /usr
|
||||
CPPUTEST_USE_EXTENSIONS = Y
|
||||
CPPUTEST_USE_VPATH = Y
|
||||
CPPUTEST_USE_GCOV = Y
|
||||
CPP_PLATFORM = gcc
|
||||
INCLUDE_DIRS =\
|
||||
.\
|
||||
../common\
|
||||
../stubs\
|
||||
../../../..\
|
||||
../../../../source\
|
||||
../../../../mbed-client-libservice\
|
||||
$(MBED_TRACE_HOME)\
|
||||
/usr/include\
|
||||
$(CPPUTEST_HOME)/include\
|
||||
|
||||
CPPUTESTFLAGS = -D__thumb2__ -w
|
||||
CPPUTEST_CFLAGS += -std=gnu99
|
|
@ -0,0 +1,25 @@
|
|||
include ../makefile_defines.txt
|
||||
|
||||
COMPONENT_NAME = dynmem_unit
|
||||
SRC_FILES = \
|
||||
../../../../source/nsdynmemLIB/nsdynmemLIB.c
|
||||
|
||||
TEST_SRC_FILES = \
|
||||
main.cpp \
|
||||
dynmemtest.cpp \
|
||||
error_callback.c \
|
||||
../stubs/platform_critical.c \
|
||||
../stubs/ns_list_stub.c
|
||||
|
||||
# ../../../../source/libBits/common_functions.c
|
||||
# ../stubs/some_stub.c \
|
||||
|
||||
# XXX: without this, the CppUTest complains for memory leak even without one.
|
||||
# The funny thing is that the CppUTest does not find the memory leak on
|
||||
# this app when there actually is one.
|
||||
CPPUTEST_USE_MEM_LEAK_DETECTION = Y
|
||||
|
||||
include ../MakefileWorker.mk
|
||||
|
||||
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
|
||||
|
|
@ -0,0 +1,759 @@
|
|||
/*
|
||||
* Copyright (c) 2015-2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "nsdynmemLIB.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "error_callback.h"
|
||||
|
||||
// hardcoded amount of regions, keep in sync with nsdynmemlib "REGION_COUNT"
|
||||
#define NS_MEM_REGION_CNT (3)
|
||||
// size of nsdynmemlib book keeping data ns_mem_book_t
|
||||
#define NS_MEM_BOOK_SIZE (64 + (NS_MEM_REGION_CNT-1)*2*sizeof(ns_mem_heap_size_t))
|
||||
#define NS_MEM_BOOK_SIZE_WITH_HOLE (NS_MEM_BOOK_SIZE + 2*sizeof(ns_mem_heap_size_t))
|
||||
|
||||
int ret_val;
|
||||
|
||||
TEST_GROUP(dynmem)
|
||||
{
|
||||
void setup() {
|
||||
reset_heap_error();
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(dynmem, init)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
mem_stat_t info;
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE));
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(ns_dyn_mem_get_mem_stat() == &info);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, different_sizes)
|
||||
{
|
||||
reset_heap_error();
|
||||
for (uint16_t size = 1000; size < 32768; size++) {
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size >= (size - NS_MEM_BOOK_SIZE_WITH_HOLE));
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(ns_dyn_mem_alloc(10));
|
||||
free(heap);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(dynmem, diff_alignment)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *ptr = heap;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
for (int i = 0; i < 16; i++) {
|
||||
ptr++;
|
||||
size--;
|
||||
ns_dyn_mem_init(ptr, size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size >= (size - NS_MEM_BOOK_SIZE_WITH_HOLE));
|
||||
CHECK(!heap_have_failed());
|
||||
}
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, heap_add_region_api)
|
||||
{
|
||||
#if (NS_MEM_REGION_CNT > 1)
|
||||
uint16_t size = 1000;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *heap2add = (uint8_t *)malloc(size);
|
||||
uint8_t *heap2add2 = (uint8_t *)malloc(size);
|
||||
|
||||
mem_stat_t info;
|
||||
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
// param error, return <0
|
||||
ret_val = ns_dyn_mem_region_add(NULL, size);
|
||||
CHECK(0 != ret_val);
|
||||
|
||||
// param error, return <0
|
||||
ret_val = ns_dyn_mem_region_add(heap2add, 0);
|
||||
CHECK(0 != ret_val);
|
||||
|
||||
// param error, return <0
|
||||
ret_val = ns_dyn_mem_region_add(heap2add, 8);
|
||||
CHECK(0 != ret_val);
|
||||
|
||||
// All OK - success, 1 reserved for bookkeeping
|
||||
ret_val = ns_dyn_mem_region_add(heap2add, size);
|
||||
CHECK(0 == ret_val);
|
||||
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(ns_dyn_mem_get_mem_stat() == &info);
|
||||
CHECK(info.heap_sector_size == (2 * size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
// All OK - add more memory again success
|
||||
ret_val = ns_dyn_mem_region_add(heap2add2, size);
|
||||
CHECK(0 == ret_val);
|
||||
CHECK(info.heap_sector_size == (3 * size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
free(heap);
|
||||
free(heap2add);
|
||||
free(heap2add2);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(dynmem, heap_add_region)
|
||||
{
|
||||
#if (NS_MEM_REGION_CNT > 1 && NS_MEM_REGION_CNT < 4)
|
||||
uint16_t size = 200;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *heap_add1 = (uint8_t *)malloc(size);
|
||||
uint8_t *heap_add2 = (uint8_t *)malloc(size);
|
||||
uint8_t *heap_add3 = (uint8_t *)malloc(size);
|
||||
void *p[size * 4];
|
||||
|
||||
mem_stat_t info;
|
||||
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
ret_val = ns_dyn_mem_region_add(heap_add1, size);
|
||||
CHECK(0 == ret_val);
|
||||
|
||||
// region already added, therefore fails
|
||||
ret_val = ns_dyn_mem_region_add(heap_add1, size);
|
||||
CHECK(0 != ret_val);
|
||||
|
||||
ret_val = ns_dyn_mem_region_add(heap_add3, size);
|
||||
CHECK(0 == ret_val);
|
||||
|
||||
// There is room for 2 additional regions , therfore fails
|
||||
ret_val = ns_dyn_mem_region_add(heap_add2, size);
|
||||
CHECK(0 != ret_val);
|
||||
|
||||
CHECK(info.heap_sector_size == (3 * size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
CHECK(!heap_have_failed());
|
||||
int block_size = 10;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size * 3; i++) {
|
||||
p[i] = ns_dyn_mem_alloc(block_size);
|
||||
if (p[i]) {
|
||||
memset(p[i], 0xb0, block_size);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
CHECK(info.heap_sector_alloc_cnt == i);
|
||||
CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max);
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
ns_dyn_mem_free(p[i]);
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
|
||||
free(heap);
|
||||
free(heap_add1);
|
||||
free(heap_add2);
|
||||
free(heap_add3);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(dynmem, heap_add_region_randomized)
|
||||
{
|
||||
/**
|
||||
* Test:
|
||||
* - multiple regions
|
||||
* - regions are not from continous
|
||||
* - all memory allocated from heap
|
||||
* - blocks are deallocated in random order
|
||||
*/
|
||||
#if (NS_MEM_REGION_CNT > 1)
|
||||
uint32_t size = 200000;
|
||||
uint8_t *heap_ptr[NS_MEM_REGION_CNT]; // heap memory regions
|
||||
void *ptrs[size * NS_MEM_REGION_CNT / 4] = {0}; // allocated memory pointers
|
||||
mem_stat_t info;
|
||||
uint8_t *gap_between_regions = NULL;
|
||||
|
||||
for (int cnt = 0; cnt < NS_MEM_REGION_CNT; cnt++) {
|
||||
heap_ptr[cnt] = (uint8_t *)malloc(size);
|
||||
if (gap_between_regions) {
|
||||
free(gap_between_regions);
|
||||
}
|
||||
gap_between_regions = (uint8_t *)malloc(size / 3);
|
||||
}
|
||||
free(gap_between_regions);
|
||||
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap_ptr[0], size, &heap_fail_callback, &info);
|
||||
CHECK(info.heap_sector_size == (size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
for (int cnt = NS_MEM_REGION_CNT - 1; cnt > 0; cnt--) {
|
||||
ret_val = ns_dyn_mem_region_add(heap_ptr[cnt], size);
|
||||
CHECK(0 == ret_val);
|
||||
}
|
||||
|
||||
CHECK(info.heap_sector_size == (NS_MEM_REGION_CNT * size - NS_MEM_BOOK_SIZE))
|
||||
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
srand(time(NULL));
|
||||
int block_size;
|
||||
int i;
|
||||
for (i = 0; i < size * NS_MEM_REGION_CNT; i++) {
|
||||
// allocate huge amount of small blocks until allocation fails
|
||||
block_size = (rand() % 4) + 1;
|
||||
ptrs[i] = ns_dyn_mem_alloc(block_size);
|
||||
if (ptrs[i]) {
|
||||
memset(ptrs[i], 0xb0, block_size);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
CHECK(info.heap_sector_alloc_cnt == i);
|
||||
CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max);
|
||||
|
||||
// free allocated memmory blocks in random order
|
||||
int block_id;
|
||||
do {
|
||||
block_id = (rand() % i);
|
||||
if (ptrs[block_id] != NULL) {
|
||||
ns_dyn_mem_free(ptrs[block_id]);
|
||||
ptrs[block_id] = NULL;
|
||||
}
|
||||
} while (info.heap_sector_alloc_cnt != 0);
|
||||
|
||||
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
CHECK(info.heap_sector_allocated_bytes == 0);
|
||||
|
||||
for (int cnt = 0; cnt < NS_MEM_REGION_CNT; cnt++) {
|
||||
free(heap_ptr[cnt]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(dynmem, ns_dyn_mem_alloc)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
void *p[size];
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
int block = 1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
p[i] = ns_dyn_mem_alloc(block);
|
||||
|
||||
if (p[i]) {
|
||||
memset(p[i], 0xb0, block);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
CHECK(info.heap_sector_alloc_cnt == i);
|
||||
CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max);
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
ns_dyn_mem_free(p[i]);
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, ns_dyn_mem_temporary_alloc)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
void *p[size];
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
int block = 1;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < size; i++) {
|
||||
p[i] = ns_dyn_mem_temporary_alloc(block);
|
||||
if (!p[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
CHECK(info.heap_sector_alloc_cnt == i);
|
||||
CHECK(info.heap_sector_allocated_bytes == info.heap_sector_allocated_bytes_max);
|
||||
|
||||
for (; i >= 0; i--) {
|
||||
ns_dyn_mem_free(p[i]);
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, ns_dyn_mem_temporary_alloc_with_heap_threshold)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
void *p1, *p2;
|
||||
int ret_val;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
// test1: temporary alloc will fail if there is less than 5% heap free
|
||||
p1 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.96);
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(p1);
|
||||
p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.02);
|
||||
CHECK(p2 == NULL);
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
|
||||
// Test2, disable threshold feature and try p2 allocation again
|
||||
ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 0);
|
||||
p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.02);
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(p2);
|
||||
ns_dyn_mem_free(p1);
|
||||
ns_dyn_mem_free(p2);
|
||||
CHECK(info.heap_alloc_fail_cnt == 1);
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
|
||||
// Test3, enable feature by free heap percentage
|
||||
ns_dyn_mem_set_temporary_alloc_free_heap_threshold(40, 0);
|
||||
p1 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.65);
|
||||
CHECK(p1);
|
||||
p2 = ns_dyn_mem_temporary_alloc((size - NS_MEM_BOOK_SIZE_WITH_HOLE) * 0.10);
|
||||
CHECK(p2 == NULL);
|
||||
ns_dyn_mem_free(p1);
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 2);
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
|
||||
// Test4, enable feature by free heap amount
|
||||
ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 200);
|
||||
p1 = ns_dyn_mem_temporary_alloc(size - NS_MEM_BOOK_SIZE_WITH_HOLE - 100);
|
||||
CHECK(p1);
|
||||
p2 = ns_dyn_mem_temporary_alloc(1);
|
||||
CHECK(p2 == NULL);
|
||||
ns_dyn_mem_free(p1);
|
||||
|
||||
// Test5, illegal API parameters
|
||||
ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, size / 2);
|
||||
CHECK(ret_val == -2);
|
||||
ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, size * 2);
|
||||
CHECK(ret_val == -2);
|
||||
ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(51, 0);
|
||||
CHECK(ret_val == -2);
|
||||
ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(255, 0);
|
||||
CHECK(ret_val == -2);
|
||||
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_alloc_fail_cnt == 3);
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
free(heap);
|
||||
|
||||
// Test6, feature is disabled if info is not set
|
||||
heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
|
||||
ret_val = ns_dyn_mem_set_temporary_alloc_free_heap_threshold(0, 0);
|
||||
CHECK(ret_val == -1);
|
||||
CHECK(!heap_have_failed());
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, test_both_allocs_with_hole_usage)
|
||||
{
|
||||
uint16_t size = NS_MEM_BOOK_SIZE_WITH_HOLE + 15 + 5;
|
||||
mem_stat_t info;
|
||||
void *p[size];
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
void *ptr = ns_dyn_mem_alloc(15);
|
||||
void *ptr2 = ns_dyn_mem_alloc(4);
|
||||
|
||||
ns_dyn_mem_free(ptr);
|
||||
ns_dyn_mem_free(ptr2);
|
||||
CHECK(info.heap_sector_allocated_bytes == 0);
|
||||
|
||||
void *ptr3 = ns_dyn_mem_temporary_alloc(15);
|
||||
void *ptr4 = ns_dyn_mem_temporary_alloc(5);
|
||||
|
||||
ns_dyn_mem_free(ptr3);
|
||||
ns_dyn_mem_free(ptr4);
|
||||
|
||||
|
||||
CHECK(info.heap_sector_allocated_bytes == 0);
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, test_temp_alloc_with_skipping_hole)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
void *p[size];
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
void *ptr1 = ns_dyn_mem_temporary_alloc(15);
|
||||
void *ptr2 = ns_dyn_mem_temporary_alloc(5);
|
||||
|
||||
ns_dyn_mem_free(ptr1);
|
||||
void *ptr3 = ns_dyn_mem_temporary_alloc(35);
|
||||
ns_dyn_mem_free(ptr2);
|
||||
ns_dyn_mem_free(ptr3);
|
||||
|
||||
|
||||
CHECK(info.heap_sector_allocated_bytes == 0);
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, zero_allocate)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *ptr = heap;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_alloc(0);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, too_big)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *ptr = heap;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_alloc(size);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_ALLOCATE_SIZE_NOT_VALID == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, corrupted_memory)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *ptr = heap;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
int *pt = (int *)ns_dyn_mem_alloc(8);
|
||||
CHECK(!heap_have_failed());
|
||||
pt -= 2;
|
||||
*pt = 0;
|
||||
ns_dyn_mem_alloc(8);
|
||||
CHECK(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, no_big_enough_sector)
|
||||
{
|
||||
uint16_t size = NS_MEM_BOOK_SIZE_WITH_HOLE + (5 * 8);
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *ptr = heap;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
int *pt = (int *)ns_dyn_mem_alloc(8);
|
||||
pt = (int *)ns_dyn_mem_alloc(8);
|
||||
ns_dyn_mem_alloc(8);
|
||||
ns_dyn_mem_temporary_alloc(8);
|
||||
ns_dyn_mem_temporary_alloc(8);
|
||||
|
||||
ns_dyn_mem_free(pt);
|
||||
|
||||
pt = (int *)ns_dyn_mem_temporary_alloc(32);
|
||||
CHECK(NULL == pt);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, diff_sizes)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
void *p;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
int i;
|
||||
for (i = 1; i < (size - NS_MEM_BOOK_SIZE_WITH_HOLE); i++) {
|
||||
p = ns_dyn_mem_temporary_alloc(i);
|
||||
CHECK(p);
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(!heap_have_failed());
|
||||
}
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_alloc_cnt == 0);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, double_free)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
void *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
p = ns_dyn_mem_alloc(100);
|
||||
CHECK(p);
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_DOUBLE_FREE == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, middle_free)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
void *p[3];
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
for (int i = 0; i < 3; i++) {
|
||||
p[i] = ns_dyn_mem_temporary_alloc(100);
|
||||
CHECK(p);
|
||||
}
|
||||
ns_dyn_mem_free(p[1]);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_free(p[0]);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_free(p[2]);
|
||||
CHECK(!heap_have_failed());
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, over_by_one)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
p = (uint8_t *)ns_dyn_mem_alloc(100);
|
||||
CHECK(p);
|
||||
p[100] = 0xff;
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, not_from_this_heap)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
p = (uint8_t *)ns_dyn_mem_alloc(100);
|
||||
CHECK(p);
|
||||
ns_dyn_mem_free(&heap[-1]);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_POINTER_NOT_VALID == current_heap_error);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_free(&heap[1001]);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_POINTER_NOT_VALID == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, free_on_empty_heap)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
ns_dyn_mem_free(&heap[1]);
|
||||
CHECK(heap_have_failed());
|
||||
CHECK(NS_DYN_MEM_POINTER_NOT_VALID == current_heap_error);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, not_negative_stats)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
mem_stat_t info;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
void *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, &info);
|
||||
CHECK(!heap_have_failed());
|
||||
CHECK(info.heap_sector_allocated_bytes == 0);
|
||||
ns_dyn_mem_alloc(8);
|
||||
p = ns_dyn_mem_alloc(8);
|
||||
ns_dyn_mem_alloc(8);
|
||||
CHECK(info.heap_sector_allocated_bytes >= 24);
|
||||
int16_t last_value = info.heap_sector_allocated_bytes;
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(info.heap_sector_allocated_bytes >= 16);
|
||||
CHECK(info.heap_sector_allocated_bytes < last_value);
|
||||
last_value = info.heap_sector_allocated_bytes;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
p = ns_dyn_mem_alloc(1);
|
||||
ns_dyn_mem_free(p);
|
||||
}
|
||||
CHECK(info.heap_sector_allocated_bytes == last_value);
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, test_invalid_pointer_freed)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
|
||||
int *ptr = (int *)ns_dyn_mem_alloc(4);
|
||||
ptr--;
|
||||
*ptr = 16;
|
||||
ptr++;
|
||||
ns_dyn_mem_free(ptr);
|
||||
CHECK(NS_DYN_MEM_POINTER_NOT_VALID == current_heap_error);
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, test_merge_corrupted_previous_block)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
int *ptr = (int *)ns_dyn_mem_alloc(4);
|
||||
int *ptr2 = (int *)ns_dyn_mem_alloc(4);
|
||||
ns_dyn_mem_free(ptr);
|
||||
ptr = ptr2 - 2;
|
||||
*ptr = -2;
|
||||
ns_dyn_mem_free(ptr2);
|
||||
|
||||
CHECK(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED == current_heap_error);
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
TEST(dynmem, test_free_corrupted_next_block)
|
||||
{
|
||||
uint16_t size = 1000;
|
||||
uint8_t *heap = (uint8_t *)malloc(size);
|
||||
uint8_t *p;
|
||||
CHECK(NULL != heap);
|
||||
reset_heap_error();
|
||||
ns_dyn_mem_init(heap, size, &heap_fail_callback, NULL);
|
||||
CHECK(!heap_have_failed());
|
||||
|
||||
int *ptr = (int *)ns_dyn_mem_temporary_alloc(4);
|
||||
int *ptr2 = (int *)ns_dyn_mem_temporary_alloc(4);
|
||||
ns_dyn_mem_free(ptr);
|
||||
ptr = ptr2 + 2;
|
||||
*ptr = -2;
|
||||
ns_dyn_mem_free(ptr2);
|
||||
|
||||
CHECK(NS_DYN_MEM_HEAP_SECTOR_CORRUPTED == current_heap_error);
|
||||
|
||||
free(heap);
|
||||
}
|
||||
|
||||
//NOTE! This test must be last!
|
||||
TEST(dynmem, uninitialized_test)
|
||||
{
|
||||
void *p = ns_dyn_mem_alloc(4);
|
||||
ns_dyn_mem_free(p);
|
||||
CHECK(p == NULL);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "nsdynmemLIB.h"
|
||||
#include <stdint.h>
|
||||
|
||||
heap_fail_t current_heap_error;
|
||||
static bool failed;
|
||||
|
||||
void heap_fail_callback(heap_fail_t err)
|
||||
{
|
||||
current_heap_error = err;
|
||||
failed = true;
|
||||
}
|
||||
|
||||
void reset_heap_error()
|
||||
{
|
||||
failed = false;
|
||||
}
|
||||
|
||||
bool heap_have_failed()
|
||||
{
|
||||
return failed;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef ERROR_CALLBACK_H
|
||||
#define ERROR_CALLBACK_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "nsdynmemLIB.h"
|
||||
#include <stdint.h>
|
||||
|
||||
extern heap_fail_t current_heap_error;
|
||||
|
||||
void heap_fail_callback(heap_fail_t err);
|
||||
void reset_heap_error();
|
||||
bool heap_have_failed();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*ERROR_CALLBACK_H*/
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
#include "CppUTest/TestPlugin.h"
|
||||
#include "CppUTest/TestRegistry.h"
|
||||
#include "CppUTestExt/MockSupportPlugin.h"
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
return CommandLineTestRunner::RunAllTests(ac, av);
|
||||
}
|
||||
|
||||
IMPORT_TEST_GROUP(dynmem);
|
|
@ -0,0 +1,18 @@
|
|||
include ../makefile_defines.txt
|
||||
|
||||
COMPONENT_NAME = ns_nvm_helper_unit
|
||||
|
||||
SRC_FILES = ../../../../source/nvmHelper/ns_nvm_helper.c
|
||||
|
||||
TEST_SRC_FILES = main.cpp \
|
||||
nsnvmhelpertest.cpp \
|
||||
test_ns_nvm_helper.c \
|
||||
../stubs/platform_nvm_stub.c \
|
||||
../stubs/nsdynmemLIB_stub.c \
|
||||
../stubs/mbed_trace_stub.c \
|
||||
../stubs/ns_list_stub.c
|
||||
|
||||
include ../MakefileWorker.mk
|
||||
|
||||
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
#include "CppUTest/TestPlugin.h"
|
||||
#include "CppUTest/TestRegistry.h"
|
||||
#include "CppUTestExt/MockSupportPlugin.h"
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
return CommandLineTestRunner::RunAllTests(ac, av);
|
||||
}
|
||||
|
||||
IMPORT_TEST_GROUP(NS_NVM_HELPER);
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
*/
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "test_ns_nvm_helper.h"
|
||||
|
||||
TEST_GROUP(NS_NVM_HELPER)
|
||||
{
|
||||
void setup() {
|
||||
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_platform_error_in_write)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_platform_error_in_write() == true);
|
||||
}
|
||||
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_platform_error)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_platform_error() == true);
|
||||
}
|
||||
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_concurrent_requests)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_concurrent_requests() == true);
|
||||
}
|
||||
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_read)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_read() == true);
|
||||
}
|
||||
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_delete)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_delete() == true);
|
||||
}
|
||||
|
||||
/* Write must be the last test (executed first) as it initialized the platform NVM */
|
||||
TEST(NS_NVM_HELPER, test_ns_nvm_helper_write)
|
||||
{
|
||||
CHECK(test_ns_nvm_helper_write() == true);
|
||||
}
|
||||
|
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "test_ns_nvm_helper.h"
|
||||
#include "ns_nvm_helper.h"
|
||||
#include "nsdynmemLIB_stub.h"
|
||||
#include "platform/arm_hal_nvm.h"
|
||||
|
||||
#define TEST_NS_NVM_HELPER_CONTEXT1 0x01
|
||||
#define TEST_NS_NVM_HELPER_CONTEXT2 0x02
|
||||
#define TEST_NS_NVM_HELPER_CONTEXT3 0x03
|
||||
|
||||
const char *key1 = "ns_nvm_test_key1";
|
||||
#define BUF_LEN 1000
|
||||
static uint8_t buf[BUF_LEN];
|
||||
uint16_t buf_len = BUF_LEN;
|
||||
|
||||
static int read_callback_status = 0;
|
||||
static void *read_callback_context = NULL;
|
||||
static int write_callback_status = 0;
|
||||
static void *write_callback_context = NULL;
|
||||
static int delete_callback_status = 0;
|
||||
static void *delete_callback_context = NULL;
|
||||
|
||||
extern void test_platform_nvm_api_set_retval(platform_nvm_status return_value);
|
||||
|
||||
void test_ns_nvm_helper_write_callback(int status, void *context)
|
||||
{
|
||||
write_callback_status = status;
|
||||
write_callback_context = context;
|
||||
}
|
||||
|
||||
void test_ns_nvm_helper_read_callback(int status, void *context)
|
||||
{
|
||||
read_callback_status = status;
|
||||
read_callback_context = context;
|
||||
}
|
||||
|
||||
void test_ns_nvm_helper_delete_callback(int status, void *context)
|
||||
{
|
||||
delete_callback_status = status;
|
||||
delete_callback_context = context;
|
||||
}
|
||||
|
||||
bool test_ns_nvm_helper_write()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = 0;
|
||||
|
||||
// test with invalid parameters - callback NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_write(NULL, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - key NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, NULL, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - buf NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, NULL, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - buf_len NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, NULL, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - memory allocation fails 1
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 0;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_MEMORY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - memory allocation fails 2
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_MEMORY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - platform_init fails
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - OK
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make initialize callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make create callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make write callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make flush callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
if (write_callback_status != NS_NVM_OK || write_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_ns_nvm_helper_read()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
read_callback_status = -1;
|
||||
read_callback_context = NULL;
|
||||
|
||||
// test with invalid parameters - callback NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_read(NULL, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - key NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, NULL, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - buf NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, NULL, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - buf_len NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, NULL, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - memory allocation fails 1
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 0;
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val != NS_NVM_MEMORY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - read ok
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make read callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
if (read_callback_status != NS_NVM_OK || read_callback_context != TEST_NS_NVM_HELPER_CONTEXT2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_ns_nvm_helper_delete()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
delete_callback_status = -1;
|
||||
delete_callback_context = NULL;
|
||||
|
||||
// test with invalid parameters - callback NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_key_delete(NULL, key1, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with invalid parameters - key NULL
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
ret_val = ns_nvm_key_delete(test_ns_nvm_helper_delete_callback, NULL, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val == NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - memory allocation fails
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
nsdynmemlib_stub.returnCounter = 0;
|
||||
ret_val = ns_nvm_key_delete(test_ns_nvm_helper_delete_callback, key1, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val != NS_NVM_MEMORY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test with valid parameters - OK
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_key_delete(test_ns_nvm_helper_delete_callback, key1, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make delete callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make flush callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
if (delete_callback_status != NS_NVM_OK || delete_callback_context != TEST_NS_NVM_HELPER_CONTEXT3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_ns_nvm_helper_concurrent_requests()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = NULL;
|
||||
read_callback_status = -1;
|
||||
read_callback_context = NULL;
|
||||
delete_callback_status = -1;
|
||||
delete_callback_context = NULL;
|
||||
|
||||
// read ok
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// write ok
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT2);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete ok
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_key_delete(test_ns_nvm_helper_delete_callback, key1, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read - should complete first, make callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
if (read_callback_status != NS_NVM_OK || read_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write - should complete second, make create callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make write callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make write-flush callback with error status, note also delete will be given same error as pending request is triggered
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
if (write_callback_status != NS_NVM_ERROR || write_callback_context != TEST_NS_NVM_HELPER_CONTEXT2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete callback is called after write because write was failing
|
||||
if (delete_callback_status != NS_NVM_ERROR || delete_callback_context != TEST_NS_NVM_HELPER_CONTEXT3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_ns_nvm_helper_platform_error()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = NULL;
|
||||
read_callback_status = -1;
|
||||
read_callback_context = NULL;
|
||||
delete_callback_status = -1;
|
||||
delete_callback_context = NULL;
|
||||
|
||||
// read request fails directly in platform_nvm_api
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read request fails in platform_nvm_api callback
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_data_read(test_ns_nvm_helper_read_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
// make read callback
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_KEY_NOT_FOUND);
|
||||
test_platform_nvm_api_callback();
|
||||
if (read_callback_status != NS_NVM_DATA_NOT_FOUND || read_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete fails in platform api callback
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 1;
|
||||
ret_val = ns_nvm_key_delete(test_ns_nvm_helper_delete_callback, key1, TEST_NS_NVM_HELPER_CONTEXT3);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
// make delete callback
|
||||
test_platform_nvm_api_callback();
|
||||
if (delete_callback_status != NS_NVM_ERROR || delete_callback_context != TEST_NS_NVM_HELPER_CONTEXT3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool test_ns_nvm_helper_platform_error_in_write()
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = NULL;
|
||||
|
||||
// create callback fails
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
test_platform_nvm_api_callback();
|
||||
if (write_callback_status != NS_NVM_ERROR || write_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = NULL;
|
||||
|
||||
// write calback fails
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make create callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make write callback with error
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
test_platform_nvm_api_callback();
|
||||
if (write_callback_status != NS_NVM_ERROR || write_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
write_callback_status = -1;
|
||||
write_callback_context = NULL;
|
||||
|
||||
// flush calback fails
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_OK);
|
||||
nsdynmemlib_stub.returnCounter = 2;
|
||||
ret_val = ns_nvm_data_write(test_ns_nvm_helper_write_callback, key1, &buf, &buf_len, TEST_NS_NVM_HELPER_CONTEXT1);
|
||||
if (ret_val != NS_NVM_OK) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// make create callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make write callback
|
||||
test_platform_nvm_api_callback();
|
||||
|
||||
// make flush callback with error
|
||||
test_platform_nvm_api_set_retval(PLATFORM_NVM_ERROR);
|
||||
test_platform_nvm_api_callback();
|
||||
if (write_callback_status != NS_NVM_ERROR || write_callback_context != TEST_NS_NVM_HELPER_CONTEXT1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
*/
|
||||
#ifndef TEST_NS_NVM_HELPER_H
|
||||
#define TEST_NS_NVM_HELPER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool test_ns_nvm_helper_write();
|
||||
bool test_ns_nvm_helper_read();
|
||||
bool test_ns_nvm_helper_delete();
|
||||
bool test_ns_nvm_helper_concurrent_requests();
|
||||
bool test_ns_nvm_helper_platform_error();
|
||||
bool test_ns_nvm_helper_platform_error_in_write();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // TEST_NS_NVM_HELPER_H
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
echo
|
||||
echo Build M2M API unit tests
|
||||
echo
|
||||
|
||||
# Remember to add new test folder to Makefile
|
||||
make clean
|
||||
make all
|
||||
|
||||
echo
|
||||
echo Create results
|
||||
echo
|
||||
mkdir results
|
||||
|
||||
find ./ -name '*.xml' | xargs cp -t ./results/
|
||||
|
||||
echo
|
||||
echo Create coverage document
|
||||
echo
|
||||
mkdir coverages
|
||||
cd coverages
|
||||
|
||||
#copy the .gcda & .gcno for all test projects (no need to modify
|
||||
#cp ../../../source/*.gc* .
|
||||
#find ../ -name '*.gcda' | xargs cp -t .
|
||||
#find ../ -name '*.gcno' | xargs cp -t .
|
||||
#find . -name "test*" -type f -delete
|
||||
#find . -name "*test*" -type f -delete
|
||||
#find . -name "*stub*" -type f -delete
|
||||
#rm -rf main.*
|
||||
|
||||
lcov -q -d ../. -c -o app.info
|
||||
lcov -q -r app.info "/test*" -o app.info
|
||||
lcov -q -r app.info "/usr*" -o app.info
|
||||
genhtml --no-branch-coverage app.info
|
||||
cd ..
|
||||
echo
|
||||
echo
|
||||
echo
|
||||
echo Have a nice bug hunt!
|
||||
echo
|
||||
echo
|
||||
echo
|
|
@ -0,0 +1,21 @@
|
|||
include ../makefile_defines.txt
|
||||
|
||||
COMPONENT_NAME = stoip6_unit
|
||||
SRC_FILES = \
|
||||
../../../../source/libip6string/stoip6.c
|
||||
|
||||
TEST_SRC_FILES = \
|
||||
main.cpp \
|
||||
stoip6test.cpp \
|
||||
../../../../source/libBits/common_functions.c
|
||||
# ../stubs/some_stub.c \
|
||||
|
||||
# XXX: without this, the CppUTest complains for memory leak even without one.
|
||||
# The funny thing is that the CppUTest does not find the memory leak on
|
||||
# this app when there actually is one.
|
||||
CPPUTEST_USE_MEM_LEAK_DETECTION = N
|
||||
|
||||
include ../MakefileWorker.mk
|
||||
|
||||
CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "CppUTest/CommandLineTestRunner.h"
|
||||
#include "CppUTest/TestPlugin.h"
|
||||
#include "CppUTest/TestRegistry.h"
|
||||
#include "CppUTestExt/MockSupportPlugin.h"
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
return CommandLineTestRunner::RunAllTests(ac, av);
|
||||
}
|
||||
|
||||
IMPORT_TEST_GROUP(stoip6);
|
||||
IMPORT_TEST_GROUP(stoip6_2);
|
||||
IMPORT_TEST_GROUP(stoip6_3);
|
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "CppUTest/TestHarness.h"
|
||||
#include "ip6string.h"
|
||||
#include "ipv6_test_values.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
TEST_GROUP(stoip6)
|
||||
{
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(stoip6, ZeroAddress)
|
||||
{
|
||||
for (int i = 0; ipv6_test_values[i].addr; i++) {
|
||||
uint8_t ip[16];
|
||||
char *addr = ipv6_test_values[i].addr;
|
||||
stoip6(addr, strlen(addr), ip);
|
||||
CHECK(0 == memcmp(ip, ipv6_test_values[i].bin, 16));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(stoip6, TooShort)
|
||||
{
|
||||
char *addr = "FFFF:FFFF:";
|
||||
uint8_t ip[16];
|
||||
uint8_t correct[16] = {0};
|
||||
// This should stop parsing when too short address given.
|
||||
// Despite partial parsing, the entire buffer should be filled with zeroes
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
TEST(stoip6, TooLongString)
|
||||
{
|
||||
// String len must be less than 40, otherwise not valid
|
||||
char *addr = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:";
|
||||
uint8_t ip[16] = {0};
|
||||
uint8_t correct[16] = {0};
|
||||
// This should not fill anything, too long string.
|
||||
// This is basically only validation we do
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
TEST(stoip6, TooManyFields)
|
||||
{
|
||||
// String len must be less than 40
|
||||
char *addr = "FF:FF:FF:FF:FF:FF:FFFF:FFFF:FFFF:FFFF:";
|
||||
uint8_t ip[16] = {0};
|
||||
uint8_t correct[16] = {0};
|
||||
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
TEST(stoip6, Prefixlen)
|
||||
{
|
||||
CHECK(0 == sipv6_prefixlength("::"));
|
||||
CHECK(64 == sipv6_prefixlength("::/64"));
|
||||
}
|
||||
|
||||
// This test revealed a off-by-one error in stoip6() when the code was ran under valgrind.
|
||||
// The IP address is copied from the test_2duts_ping -test, where the valgrind message
|
||||
// was originally spotted.
|
||||
TEST(stoip6, RegressionTestForOffByOne)
|
||||
{
|
||||
const char *sourceAddr = "fd00:db8::643f:f54a:ec29:cdbb";
|
||||
|
||||
// Use heap based test string to make valgrind spot the problem.
|
||||
char *sourceTemp = (char *)strdup(sourceAddr);
|
||||
size_t sourceTempLen = strlen(sourceTemp);
|
||||
|
||||
uint8_t ip[16];
|
||||
const uint8_t correct[16] = { 0xfd, 0x00, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00,
|
||||
0x64, 0x3f, 0xf5, 0x4a, 0xec, 0x29, 0xcd, 0xbb
|
||||
};
|
||||
|
||||
CHECK(true == stoip6(sourceTemp, sourceTempLen, ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
|
||||
free(sourceTemp);
|
||||
}
|
||||
|
||||
// Test various illegal formats to ensure proper rejection
|
||||
TEST(stoip6, InvalidAddresses)
|
||||
{
|
||||
uint8_t ip[16];
|
||||
uint8_t correct[16] = {0};
|
||||
|
||||
const char *invalidArray[] = {
|
||||
"FFFF:FFFF::FFFF::FFFF", // Two ::
|
||||
"F:F:F:FqF:F:F:F:F", // Non-hex character
|
||||
"F:F:F:FFFFF:F:F:F:F" // >4 hex characters in a segment
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
CHECK(false == stoip6(invalidArray[i], strlen(invalidArray[i]), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Second test group for the old tests that were once lost */
|
||||
|
||||
const char string_addr[][40] = {
|
||||
"2001:db8::1:0:0:1", // 1
|
||||
"2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", // 2
|
||||
"2001:db8::1", // 3
|
||||
"2001:db8::2:1", // 4
|
||||
"2001:db8:aaaa:bbbb:cccc:dddd:0:1", // 5
|
||||
"2001:db8::aaaa:0:0:1", // 6
|
||||
"2001:0:0:1::1", // 7
|
||||
"2001:0:0:1::", // 8
|
||||
"2001:db8::", // 9
|
||||
"::aaaa:0:0:1", // 10
|
||||
"::1", // 11
|
||||
"::", // 12
|
||||
};
|
||||
|
||||
|
||||
const uint8_t hex_addr[][16] = {
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0x00, 0x01 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0, 0, 0x00, 0x01 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
{ 0x20, 0x01, 0xd, 0xb8 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
char buf[40];
|
||||
int i = 0;
|
||||
|
||||
TEST_GROUP(stoip6_2)
|
||||
{
|
||||
void setUp(void) {
|
||||
memset(buf, 0, 40);
|
||||
}
|
||||
|
||||
void tearDown(void) {
|
||||
i++;
|
||||
}
|
||||
};
|
||||
|
||||
/* Unity test code starts */
|
||||
|
||||
|
||||
TEST(stoip6_2, test_2_1)
|
||||
{
|
||||
i = 0;
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
|
||||
TEST(stoip6_2, test_2_2)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_3)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_4)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_5)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_6)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_7)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_8)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_9)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_10)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
TEST(stoip6_2, test_2_11)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
TEST(stoip6_2, test_2_12)
|
||||
{
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Third test group for stoip6_prefix */
|
||||
|
||||
const char string_prefix_addr[][40] = {
|
||||
"2001:db8::1:0:0:1/64", // 1
|
||||
"2001::/60", // 2
|
||||
"::1/48", // 3
|
||||
"::/00", // 4
|
||||
"2002::02/99", // 5
|
||||
"2003::03/", // 6
|
||||
"2004::04", // 7
|
||||
"2005::05/2000", // 8
|
||||
"2005::05/-1", // 9
|
||||
};
|
||||
|
||||
|
||||
const uint8_t hex_prefix_addr[][16] = {
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, // 1
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 2
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, // 3
|
||||
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 4
|
||||
{ 0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, // 5
|
||||
{ 0x20, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, // 6
|
||||
{ 0x20, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 }, // 7
|
||||
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 8
|
||||
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 9
|
||||
};
|
||||
|
||||
const int_fast16_t prefix_len_tbl[] = {64, 60, 48, 0, 99, 0, -1, -1, -1};
|
||||
const int prefix_status_tbl[] = {0, 0, 0, 0, 0, 0, 0, -1, -1};
|
||||
|
||||
TEST_GROUP(stoip6_3)
|
||||
{
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(stoip6_3, stoip6_prefix_test)
|
||||
{
|
||||
for (int i = 0; i < 9; i++) {
|
||||
uint8_t ip[16];
|
||||
int_fast16_t prefix_len;
|
||||
int result;
|
||||
const char *addr = &string_prefix_addr[i][0];
|
||||
|
||||
result = stoip6_prefix(addr, ip, &prefix_len);
|
||||
CHECK(result == prefix_status_tbl[i]);
|
||||
if (result == 0) {
|
||||
CHECK(0 == memcmp(ip, &hex_prefix_addr[i][0], 16));
|
||||
CHECK(prefix_len == prefix_len_tbl[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common_functions.h"
|
||||
|
||||
//TODO: create uint8 value to return
|
||||
|
||||
uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits)
|
||||
{
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ip6string.h"
|
||||
#include "ip6tos_stub.h"
|
||||
|
||||
ip6tos_def ip6tos_stub;
|
||||
|
||||
void ip6tos(const void *ip6addr, char *p)
|
||||
{
|
||||
if (ip6tos_stub.h) {
|
||||
p[0] = ip6tos_stub.c;
|
||||
p[1] = '\0';
|
||||
} else {
|
||||
p[0] = '\0';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef __IP6TOS_STUB_H__
|
||||
#define __IP6TOS_STUB_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct ip6tos {
|
||||
char c;
|
||||
bool h;
|
||||
} ip6tos_def;
|
||||
|
||||
extern ip6tos_def ip6tos_stub;
|
||||
#endif
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef IPV6_TEST_VALUES_H
|
||||
#define IPV6_TEST_VALUES_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct ip6_addresses_and_its_binary_form_t {
|
||||
char *addr;
|
||||
uint8_t bin[16];
|
||||
} ipv6_test_values[] = {
|
||||
{ "2001:db8::1:0:0:1", { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "2001:db8:aaaa:bbbb:cccc:dddd:eeee:1", { 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0xee, 0xee, 0x00, 0x01 }},
|
||||
{ "2001:db8::1", { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "2001:db8::2:1", { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1 }},
|
||||
{ "2001:db8:aaaa:bbbb:cccc:dddd:0:1", { 0x20, 0x01, 0xd, 0xb8, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0xdd, 0xdd, 0, 0, 0x00, 0x01 }},
|
||||
{ "2001:db8::aaaa:0:0:1", { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "2001:0:0:1::1", { 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "2001:0:0:1::", { 0x20, 0x01, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 }},
|
||||
{ "2001:db8::", { 0x20, 0x01, 0xd, 0xb8 }},
|
||||
{ "::aaaa:0:0:1", { 0, 0, 0, 0, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "::1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "fe80::1", { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
{ "::", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
|
||||
{ "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
|
||||
{NULL, {0}}
|
||||
};
|
||||
|
||||
#endif /* IPV6_TEST_VALUES_H */
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef MBED_CONF_MBED_TRACE_ENABLE
|
||||
#define MBED_CONF_MBED_TRACE_ENABLE 1
|
||||
#define MBED_CONF_MBED_TRACE_FEA_IPV6 1
|
||||
#endif
|
||||
|
||||
#include "mbed-trace/mbed_trace.h"
|
||||
#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1
|
||||
#include "mbed-client-libservice/ip6string.h"
|
||||
#include "mbed-client-libservice/common_functions.h"
|
||||
#endif
|
||||
|
||||
|
||||
int mbed_trace_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
void mbed_trace_free(void)
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_buffer_sizes(int lineLength, int tmpLength)
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_config_set(uint8_t config)
|
||||
{
|
||||
}
|
||||
|
||||
uint8_t mbed_trace_config_get(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mbed_trace_prefix_function_set(char *(*pref_f)(size_t))
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_suffix_function_set(char *(*suffix_f)(void))
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_print_function_set(void (*printf)(const char *))
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_cmdprint_function_set(void (*printf)(const char *))
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_trace_exclude_filters_set(char *filters)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
const char *mbed_trace_exclude_filters_get(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *mbed_trace_include_filters_get(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mbed_trace_include_filters_set(char *filters)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void mbed_tracef(uint8_t dlevel, const char *grp, const char *fmt, ...)
|
||||
{
|
||||
}
|
||||
|
||||
void mbed_vtracef(uint8_t dlevel, const char *grp, const char *fmt, va_list ap)
|
||||
{
|
||||
}
|
||||
|
||||
const char *mbed_trace_last(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Helping functions */
|
||||
#if MBED_CONF_MBED_TRACE_FEA_IPV6 == 1
|
||||
char *mbed_trace_ipv6(const void *addr_ptr)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *mbed_trace_ipv6_prefix(const uint8_t *prefix, uint8_t prefix_len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif //MBED_CONF_MBED_TRACE_FEA_IPV6
|
||||
|
||||
char *mbed_trace_array(const uint8_t *buf, uint16_t len)
|
||||
{
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define NS_LIST_FN extern
|
||||
|
||||
#include "ns_list.h"
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "nsdynmemLIB_stub.h"
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <nsdynmemLIB.h>
|
||||
#include "platform/arm_hal_interrupt.h"
|
||||
#ifdef STANDARD_MALLOC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
nsdynmemlib_stub_data_t nsdynmemlib_stub;
|
||||
|
||||
void ns_dyn_mem_init(void *heap, ns_mem_heap_size_t h_size, void (*passed_fptr)(heap_fail_t), mem_stat_t *info_ptr)
|
||||
{
|
||||
}
|
||||
|
||||
void *ns_dyn_mem_alloc(ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
if (nsdynmemlib_stub.returnCounter > 0) {
|
||||
nsdynmemlib_stub.returnCounter--;
|
||||
return malloc(alloc_size);
|
||||
} else {
|
||||
return (nsdynmemlib_stub.expectedPointer);
|
||||
}
|
||||
}
|
||||
|
||||
void *ns_dyn_mem_temporary_alloc(ns_mem_block_size_t alloc_size)
|
||||
{
|
||||
if (nsdynmemlib_stub.returnCounter > 0) {
|
||||
nsdynmemlib_stub.returnCounter--;
|
||||
return malloc(alloc_size);
|
||||
} else {
|
||||
return (nsdynmemlib_stub.expectedPointer);
|
||||
}
|
||||
}
|
||||
|
||||
void ns_dyn_mem_free(void *block)
|
||||
{
|
||||
free(block);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2018 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef __NSDYNMEMLIB_STUB_H__
|
||||
#define __NSDYNMEMLIB_STUB_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t returnCounter;
|
||||
void *expectedPointer;
|
||||
} nsdynmemlib_stub_data_t;
|
||||
|
||||
extern nsdynmemlib_stub_data_t nsdynmemlib_stub;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Copyright (c) 2015 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
void platform_enter_critical() {};
|
||||
void platform_exit_critical() {};
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright (c) 2016 ARM Limited. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
* Licensed under the Apache License, Version 2.0 (the License); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ns_types.h"
|
||||
#include "platform/arm_hal_nvm.h"
|
||||
|
||||
typedef struct {
|
||||
platform_nvm_status status;
|
||||
nvm_callback *saved_callback;
|
||||
void *saved_context;
|
||||
} test_platform_nvm_api_data;
|
||||
|
||||
test_platform_nvm_api_data test_data = {0, NULL, NULL};
|
||||
|
||||
|
||||
void test_platform_nvm_api_set_retval(platform_nvm_status return_value)
|
||||
{
|
||||
test_data.status = return_value;
|
||||
}
|
||||
|
||||
void test_platform_nvm_api_callback()
|
||||
{
|
||||
test_data.saved_callback(test_data.status, test_data.saved_context);
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_init(nvm_callback *callback, void *context)
|
||||
{
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_finalize(nvm_callback *callback, void *context)
|
||||
{
|
||||
(void) callback;
|
||||
(void) context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_key_create(nvm_callback *callback, const char *key_name, uint16_t value_len, uint32_t flags, void *context)
|
||||
{
|
||||
(void) key_name;
|
||||
(void) value_len;
|
||||
(void) flags;
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_key_delete(nvm_callback *callback, const char *key_name, void *context)
|
||||
{
|
||||
(void) callback;
|
||||
(void) key_name;
|
||||
(void) context;
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_write(nvm_callback *callback, const char *key_name, const void *data, uint16_t *data_len, void *context)
|
||||
{
|
||||
(void) key_name;
|
||||
(void) data;
|
||||
(void) data_len;
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_read(nvm_callback *callback, const char *key_name, void *buf, uint16_t *buf_len, void *context)
|
||||
{
|
||||
(void) key_name;
|
||||
(void) buf;
|
||||
(void) buf_len;
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
||||
platform_nvm_status platform_nvm_flush(nvm_callback *callback, void *context)
|
||||
{
|
||||
(void) callback;
|
||||
(void) context;
|
||||
test_data.saved_callback = callback;
|
||||
test_data.saved_context = context;
|
||||
return test_data.status;
|
||||
}
|
||||
|
Loading…
Reference in New Issue