mem_manager.c 33.7 KB
Newer Older
X
xieyangrun 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
/**
 * Copyright (c) 2014 - 2017, Nordic Semiconductor ASA
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 * 
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 * 
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 * 
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 * 
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 */
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(MEM_MANAGER)
#include "mem_manager.h"
#include "nrf_assert.h"
#define NRF_LOG_MODULE_NAME "MEM_MNGR"
#include "nrf_log.h"

/**
 * @defgroup memory_manager_mutex_lock_unlock Module's Mutex Lock/Unlock Macros.
 *
 * @details Macros used to lock and unlock modules. Currently the SDK does not use mutexes but
 *          framework is provided in case need arises to use an alternative architecture.
 * @{
 */
#define MM_MUTEX_LOCK()   SDK_MUTEX_LOCK(m_mm_mutex)                                                /**< Lock module using mutex. */
#define MM_MUTEX_UNLOCK() SDK_MUTEX_UNLOCK(m_mm_mutex)                                              /**< Unlock module using mutex. */
/** @} */

#undef NULL_PARAM_CHECK
#undef NULL_PARAM_CHECK_VOID
#undef VERIFY_MODULE_INITIALIZED
#undef VERIFY_MODULE_INITIALIZED_VOID
#undef VERIFY_REQUESTED_SIZE
#undef VERIFY_REQUESTED_SIZE_VOID

#if (MEM_MANAGER_DISABLE_API_PARAM_CHECK == 0)

/**
 * @brief Macro for verifying NULL parameters.
 *        Returning with an appropriate error code on failure.
 *
 * @param[in] PARAM Parameter checked for NULL.
 *
 * @retval (NRF_ERROR_NULL | NRF_ERROR_MEMORY_MANAGER_ERR_BASE) when @ref PARAM is NULL.
 */
#define NULL_PARAM_CHECK(PARAM)                            \
    if ((PARAM) == NULL)                                   \
    {                                                      \
        return (NRF_ERROR_NULL | NRF_ERROR_MEMORY_MANAGER_ERR_BASE); \
    }

/**
 * @brief Macro for verifying NULL parameters are not passed to API and returning on failure.
 *
 * @param[in] PARAM Parameter checked for NULL.
 */
#define NULL_PARAM_CHECK_VOID(PARAM)                       \
    if ((PARAM) == NULL)                                   \
    {                                                      \
        return;                                            \
    }


/**
 * @brief Macro for verifying module's initialization status.
 *        Returning with an appropriate error code on failure.
 *
 * @retval (NRF_ERROR_INVALID_STATE | NRF_ERROR_MEMORY_MANAGER_ERR_BASE) module is uninitialized.
 */
#define VERIFY_MODULE_INITIALIZED()                                     \
    do                                                                  \
    {                                                                   \
        if (!m_module_initialized)                                      \
        {                                                               \
            return (NRF_ERROR_INVALID_STATE | NRF_ERROR_MEMORY_MANAGER_ERR_BASE); \
        }                                                               \
    } while (0)

/**
 * @brief Macro for verifying module's initialization status and returning on failure.
 */
#define VERIFY_MODULE_INITIALIZED_VOID()                                \
    do                                                                  \
    {                                                                   \
        if (!m_module_initialized)                                      \
        {                                                               \
            return;                                                     \
        }                                                               \
    } while (0)


/**
 * @brief Macro for verifying requested size of memory does not exceed maximum block
 *       size supported by the module. Returning with appropriate error code on failure.
 *
 * @param[in] SIZE Requested size to be allocated.
 *
 * @retval (NRF_ERROR_INVALID_PARAM | NRF_ERROR_MEMORY_MANAGER_ERR_BASE) if requested size is greater
 *         than the largest block size managed by the module.
 */
#define VERIFY_REQUESTED_SIZE(SIZE)                                     \
    do                                                                  \
    {                                                                   \
        if (((SIZE) == 0) ||((SIZE) >  MAX_MEM_SIZE))                   \
        {                                                               \
            return (NRF_ERROR_INVALID_PARAM | NRF_ERROR_MEMORY_MANAGER_ERR_BASE); \
        }                                                               \
    } while (0)


/**
 * @brief Macro for verifying requested size of memory does not exceed maximum block
 *       size supported by the module. Returnson failure.
 *
 * @param[in] SIZE Requested size to be allocated.
 */
#define VERIFY_REQUESTED_SIZE_VOID(SIZE)                                \
    do                                                                  \
    {                                                                   \
        if (((SIZE) == 0) ||((SIZE) >  MAX_MEM_SIZE))                   \
        {                                                               \
            return;                                                     \
        }                                                               \
    } while (0)


/**@} */
#else  //MEM_MANAGER_DISABLE_API_PARAM_CHECK

#define NULL_PARAM_CHECK(PARAM)
#define VERIFY_MODULE_INITIALIZED()
#define VERIFY_REQUESTED_SIZE(SIZE)

#endif //MEM_MANAGER_DISABLE_API_PARAM_CHECK


/**@brief Setting defualts in case XXSmall block not used by application. */
#ifndef MEMORY_MANAGER_XXSMALL_BLOCK_COUNT
    #define MEMORY_MANAGER_XXSMALL_BLOCK_COUNT 0
    #define MEMORY_MANAGER_XXSMALL_BLOCK_SIZE  0
    #define XXSMALL_BLOCK_START                0
    #define XXSMALL_BLOCK_END                  0
    #define XXSMALL_MEMORY_START               0
#endif // MEMORY_MANAGER_XXSMALL_BLOCK_SIZE


/**@brief Setting defualts in case XSmall block not used by application. */
#ifndef MEMORY_MANAGER_XSMALL_BLOCK_COUNT
   #define MEMORY_MANAGER_XSMALL_BLOCK_COUNT   0
   #define MEMORY_MANAGER_XSMALL_BLOCK_SIZE    0
   #define XSMALL_BLOCK_START                  0
   #define XSMALL_BLOCK_END                    0
   #define XSMALL_MEMORY_START                 0
#endif // MEMORY_MANAGER_XSMALL_BLOCK_SIZE


/**@brief Setting defualts in case Small block not used by application. */
#ifndef MEMORY_MANAGER_SMALL_BLOCK_COUNT
   #define MEMORY_MANAGER_SMALL_BLOCK_COUNT    0
   #define MEMORY_MANAGER_SMALL_BLOCK_SIZE     0
   #define SMALL_BLOCK_START                   0
   #define SMALL_BLOCK_END                     0
   #define SMALL_MEMORY_START                  0
#endif // MEMORY_MANAGER_SMALL_BLOCK_COUNT


/**@brief Setting defualts in case Medium block not used by application. */
#ifndef MEMORY_MANAGER_MEDIUM_BLOCK_COUNT
   #define MEMORY_MANAGER_MEDIUM_BLOCK_COUNT   0
   #define MEMORY_MANAGER_MEDIUM_BLOCK_SIZE    0
   #define MEDIUM_BLOCK_START                  0
   #define MEDIUM_BLOCK_END                    0
   #define MEDIUM_MEMORY_START                 0
#endif // MEMORY_MANAGER_MEDIUM_BLOCK_COUNT


/**@brief Setting defualts in case Large block not used by application. */
#ifndef MEMORY_MANAGER_LARGE_BLOCK_COUNT
   #define MEMORY_MANAGER_LARGE_BLOCK_COUNT    0
   #define MEMORY_MANAGER_LARGE_BLOCK_SIZE     0
   #define LARGE_BLOCK_START                   0
   #define LARGE_BLOCK_END                     0
   #define LARGE_MEMORY_START                  0
#endif // MEMORY_MANAGER_LARGE_BLOCK_COUNT


/**@brief Setting defualts in case XLarge block not used by application. */
#ifndef MEMORY_MANAGER_XLARGE_BLOCK_COUNT
   #define MEMORY_MANAGER_XLARGE_BLOCK_COUNT   0
   #define MEMORY_MANAGER_XLARGE_BLOCK_SIZE    0
   #define XLARGE_BLOCK_START                  0
   #define XLARGE_BLOCK_END                    0
   #define XLARGE_MEMORY_START                 0
#endif // MEMORY_MANAGER_XLARGE_BLOCK_COUNT


/**@brief Setting defualts in case XXLarge block not used by application. */
#ifndef MEMORY_MANAGER_XXLARGE_BLOCK_COUNT
   #define MEMORY_MANAGER_XXLARGE_BLOCK_COUNT  0
   #define MEMORY_MANAGER_XXLARGE_BLOCK_SIZE   0
   #define XXLARGE_BLOCK_START                 0
   #define XXLARGE_BLOCK_END                   0
   #define XXLARGE_MEMORY_START                0
#endif // MEMORY_MANAGER_XXLARGE_BLOCK_COUNT


/**@brief  Based on which blocks are defined, MAX_MEM_SIZE is determined.
 *
 * @note   Also, in case none of these are defined, a compile time error is indicated.
 */
#if (MEMORY_MANAGER_XXLARGE_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_XXLARGE_BLOCK_SIZE
#elif (MEMORY_MANAGER_XLARGE_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_XLARGE_BLOCK_SIZE
#elif (MEMORY_MANAGER_LARGE_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_LARGE_BLOCK_SIZE
#elif (MEMORY_MANAGER_MEDIUM_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_MEDIUM_BLOCK_SIZE
#elif (MEMORY_MANAGER_SMALL_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_SMALL_BLOCK_SIZE
#elif (MEMORY_MANAGER_XSMALL_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_XSMALL_BLOCK_SIZE
#elif (MEMORY_MANAGER_XXSMALL_BLOCK_COUNT != 0)
    #define MAX_MEM_SIZE MEMORY_MANAGER_XXSMALL_BLOCK_SIZE
#else
    #err "One of MEMORY_MANAGER_SMALL_BLOCK_COUNT, MEMORY_MANAGER_MEDIUM_BLOCK_COUNT or \
         or MEMORY_MANAGER_LARGE_BLOCK_COUNT should be defined."
#endif

/**@brief XXSmall block start index in case XXSmall Block is defined. */
#ifndef XXSMALL_BLOCK_START
#define XXSMALL_BLOCK_START   0
#endif // XXSMALL_BLOCK_START


/**@brief XSmall block start index in case XSmall Block is defined. */
#ifndef XSMALL_BLOCK_START
#define XSMALL_BLOCK_START    (XXSMALL_BLOCK_START + MEMORY_MANAGER_XXSMALL_BLOCK_COUNT)
#endif // XSMALL_BLOCK_START


/**@brief Small block start index in case Small Block is defined. */
#ifndef SMALL_BLOCK_START
#define SMALL_BLOCK_START     (XSMALL_BLOCK_START  + MEMORY_MANAGER_XSMALL_BLOCK_COUNT)
#endif // SMALL_BLOCK_START


/**@brief Medium block start index in case Medium Block is defined. */
#ifndef MEDIUM_BLOCK_START
#define MEDIUM_BLOCK_START    (SMALL_BLOCK_START   + MEMORY_MANAGER_SMALL_BLOCK_COUNT)
#endif // MEDIUM_BLOCK_START


/**@brief Large block start index in case Large Block is defined. */
#ifndef LARGE_BLOCK_START
#define LARGE_BLOCK_START     (MEDIUM_BLOCK_START  + MEMORY_MANAGER_MEDIUM_BLOCK_COUNT)
#endif // LARGE_BLOCK_START


/**@brief XLarge block start index in case XLarge Block is defined. */
#ifndef XLARGE_BLOCK_START
#define XLARGE_BLOCK_START    (LARGE_BLOCK_START   + MEMORY_MANAGER_LARGE_BLOCK_COUNT)
#endif // XLARGE_BLOCK_START

/**@brief XXLarge block start index in case XXLarge Block is defined. */
#ifndef XXLARGE_BLOCK_START
#define XXLARGE_BLOCK_START   (XLARGE_BLOCK_START  + MEMORY_MANAGER_XLARGE_BLOCK_COUNT)
#endif //XXLARGE_BLOCK_START


/**@brief XXSmall block end index in case XXSmall Block is defined. */
#ifndef XXSMALL_BLOCK_END
#define XXSMALL_BLOCK_END   (XXSMALL_BLOCK_START   + MEMORY_MANAGER_XXSMALL_BLOCK_COUNT)
#endif // XXSMALL_BLOCK_END

/**@brief XSmall block end index in case XSmall Block is defined. */
#ifndef XSMALL_BLOCK_END
#define XSMALL_BLOCK_END    (XSMALL_BLOCK_START    + MEMORY_MANAGER_XSMALL_BLOCK_COUNT)
#endif // XSMALL_BLOCK_END


/**@brief Small block end index in case Small Block is defined. */
#ifndef SMALL_BLOCK_END
#define SMALL_BLOCK_END     (SMALL_BLOCK_START     + MEMORY_MANAGER_SMALL_BLOCK_COUNT)
#endif // SMALL_BLOCK_END


/**@brief Medium block end index in case Medium Block is defined. */
#ifndef MEDIUM_BLOCK_END
#define MEDIUM_BLOCK_END    (MEDIUM_BLOCK_START    + MEMORY_MANAGER_MEDIUM_BLOCK_COUNT)
#endif // MEDIUM_BLOCK_END


/**@brief Large block end index in case Large Block is defined. */
#ifndef LARGE_BLOCK_END
#define LARGE_BLOCK_END     (LARGE_BLOCK_START    + MEMORY_MANAGER_LARGE_BLOCK_COUNT)
#endif // LARGE_BLOCK_END


/**@brief XLarge block end index in case XLarge Block is defined. */
#ifndef XLARGE_BLOCK_END
#define XLARGE_BLOCK_END    (XLARGE_BLOCK_START   + MEMORY_MANAGER_XLARGE_BLOCK_COUNT)
#endif // XLARGE_BLOCK_END


/**@brief XXLarge block end index in case XXLarge Block is defined. */
#ifndef XXLARGE_BLOCK_END
#define XXLARGE_BLOCK_END   (XXLARGE_BLOCK_START  + MEMORY_MANAGER_XXLARGE_BLOCK_COUNT)
#endif //XXLARGE_BLOCK_END


#define XXSMALL_MEMORY_SIZE (MEMORY_MANAGER_XXSMALL_BLOCK_COUNT * MEMORY_MANAGER_XXSMALL_BLOCK_SIZE)
#define XSMALL_MEMORY_SIZE  (MEMORY_MANAGER_XSMALL_BLOCK_COUNT  * MEMORY_MANAGER_XSMALL_BLOCK_SIZE)
#define SMALL_MEMORY_SIZE   (MEMORY_MANAGER_SMALL_BLOCK_COUNT   * MEMORY_MANAGER_SMALL_BLOCK_SIZE)
#define MEDIUM_MEMORY_SIZE  (MEMORY_MANAGER_MEDIUM_BLOCK_COUNT  * MEMORY_MANAGER_MEDIUM_BLOCK_SIZE)
#define LARGE_MEMORY_SIZE   (MEMORY_MANAGER_LARGE_BLOCK_COUNT   * MEMORY_MANAGER_LARGE_BLOCK_SIZE)
#define XLARGE_MEMORY_SIZE  (MEMORY_MANAGER_XLARGE_BLOCK_COUNT  * MEMORY_MANAGER_XLARGE_BLOCK_SIZE)
#define XXLARGE_MEMORY_SIZE (MEMORY_MANAGER_XXLARGE_BLOCK_COUNT * MEMORY_MANAGER_XXLARGE_BLOCK_SIZE)


/**@brief XXSmall memory start index in case XXSmall Block is defined. */
#ifndef XXSMALL_MEMORY_START
#define XXSMALL_MEMORY_START  0
#endif // XXSMALL_MEMORY_START


/**@brief XSmall memory start index in case XSmall Block is defined. */
#ifndef XSMALL_MEMORY_START
#define XSMALL_MEMORY_START  (XXSMALL_MEMORY_START + XXSMALL_MEMORY_SIZE)
#endif // XSMALL_MEMORY_START


/**@brief Small memory start index in case Small Block is defined. */
#ifndef SMALL_MEMORY_START
#define SMALL_MEMORY_START  (XSMALL_MEMORY_START + XSMALL_MEMORY_SIZE)
#endif // SMALL_MEMORY_START


/**@brief Medium memory start index in case Medium Block is defined. */
#ifndef MEDIUM_MEMORY_START
#define MEDIUM_MEMORY_START  (SMALL_MEMORY_START + SMALL_MEMORY_SIZE)
#endif // MEDIUM_MEMORY_START


/**@brief Large memory start index in case Large Block is defined. */
#ifndef LARGE_MEMORY_START
#define LARGE_MEMORY_START  (MEDIUM_MEMORY_START + MEDIUM_MEMORY_SIZE)
#endif // LARGE_MEMORY_START


/**@brief XLarge memory start index in case XLarge Block is defined. */
#ifndef XLARGE_MEMORY_START
#define XLARGE_MEMORY_START  (LARGE_MEMORY_START + LARGE_MEMORY_SIZE)
#endif // XLARGE_MEMORY_START


/**@brief XXLarge memory start index in case XXLarge Block is defined. */
#ifndef XXLARGE_MEMORY_START
#define XXLARGE_MEMORY_START  (XLARGE_MEMORY_START + XLARGE_MEMORY_SIZE)
#endif // XLARGE_MEMORY_START


/**@brief Total count of block managed by the module. */
#define TOTAL_BLOCK_COUNT (MEMORY_MANAGER_XXSMALL_BLOCK_COUNT +                                     \
                           MEMORY_MANAGER_XSMALL_BLOCK_COUNT  +                                     \
                           MEMORY_MANAGER_SMALL_BLOCK_COUNT   +                                     \
                           MEMORY_MANAGER_MEDIUM_BLOCK_COUNT  +                                     \
                           MEMORY_MANAGER_LARGE_BLOCK_COUNT   +                                     \
                           MEMORY_MANAGER_XLARGE_BLOCK_COUNT  +                                     \
                           MEMORY_MANAGER_XLARGE_BLOCK_COUNT)


/**@brief Total memory managed by the module. */
#define TOTAL_MEMORY_SIZE (XXSMALL_MEMORY_SIZE +                                                    \
                           XSMALL_MEMORY_SIZE  +                                                    \
                           SMALL_MEMORY_SIZE   +                                                    \
                           MEDIUM_MEMORY_SIZE  +                                                    \
                           LARGE_MEMORY_SIZE   +                                                    \
                           XLARGE_MEMORY_SIZE  +                                                    \
                           XXLARGE_MEMORY_SIZE)


#define BLOCK_CAT_COUNT                7                                                            /**< Block category count is 7 (xxsmall, xsmall, small, medium, large, xlarge, xxlarge). Having one of the block count to zero has no impact on this count. */
#define BLOCK_CAT_XXS                  0                                                            /**< Extra Extra Small category identifier. */
#define BLOCK_CAT_XS                   1                                                            /**< Extra Small category identifier. */
#define BLOCK_CAT_SMALL                2                                                            /**< Small category identifier. */
#define BLOCK_CAT_MEDIUM               3                                                            /**< Medium category identifier. */
#define BLOCK_CAT_LARGE                4                                                            /**< Large category identifier. */
#define BLOCK_CAT_XL                   5                                                            /**< Extra Large category identifier. */
#define BLOCK_CAT_XXL                  6                                                            /**< Extra Extra Large category identifier. */

#define BITMAP_SIZE                    32                                                           /**< Bitmap size for each word used to contain block information. */
#define BLOCK_BITMAP_ARRAY_SIZE        CEIL_DIV(TOTAL_BLOCK_COUNT, BITMAP_SIZE)                     /**< Determines number of blocks needed for book keeping availability status of all blocks. */


/**@brief Lookup table for maximum memory size per block category. */
static const uint32_t m_block_size[BLOCK_CAT_COUNT] =
{
    MEMORY_MANAGER_XXSMALL_BLOCK_SIZE,
    MEMORY_MANAGER_XSMALL_BLOCK_SIZE,
    MEMORY_MANAGER_SMALL_BLOCK_SIZE,
    MEMORY_MANAGER_MEDIUM_BLOCK_SIZE,
    MEMORY_MANAGER_LARGE_BLOCK_SIZE,
    MEMORY_MANAGER_XLARGE_BLOCK_SIZE,
    MEMORY_MANAGER_XXLARGE_BLOCK_SIZE
};

/**@brief Lookup table for block start index for each block caetgory. */
static const uint32_t m_block_start[BLOCK_CAT_COUNT] =
{
    XXSMALL_BLOCK_START,
    XSMALL_BLOCK_START,
    SMALL_BLOCK_START,
    MEDIUM_BLOCK_START,
    LARGE_BLOCK_START,
    XLARGE_BLOCK_START,
    XXLARGE_BLOCK_START
};

/**@brief Lookup table for last block index for each block category. */
static const uint32_t m_block_end[BLOCK_CAT_COUNT] =
{
    XXSMALL_BLOCK_END,
    XSMALL_BLOCK_END,
    SMALL_BLOCK_END,
    MEDIUM_BLOCK_END,
    LARGE_BLOCK_END,
    XLARGE_BLOCK_END,
    XXLARGE_BLOCK_END
};

/**@brief Lookup table for memory start range for each block category. */
static const uint32_t m_block_mem_start[BLOCK_CAT_COUNT] =
{
    XXSMALL_MEMORY_START,
    XSMALL_MEMORY_START,
    SMALL_MEMORY_START,
    MEDIUM_MEMORY_START,
    LARGE_MEMORY_START,
    XLARGE_MEMORY_START,
    XXLARGE_MEMORY_START
};

static uint8_t  m_memory[TOTAL_MEMORY_SIZE];                                                        /**< Memory managed by the module. */
static uint32_t m_mem_pool[BLOCK_BITMAP_ARRAY_SIZE];                                                /**< Bitmap used for book-keeping availability of all blocks managed by the module.  */

#ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS

/**@brief Lookup table for descriptive strings for each block category. */
static const char * m_block_desc_str[BLOCK_CAT_COUNT] =
{
    "XXSmall",
    "XSmall",
    "Small",
    "Medium",
    "Large",
    "XLarge",
    "XXLarge"
};

/**@brief Table for book keeping smallest size allocated in each block range. */
static uint32_t m_min_size[BLOCK_CAT_COUNT]  =
{
    MEMORY_MANAGER_XXSMALL_BLOCK_SIZE,
    MEMORY_MANAGER_XSMALL_BLOCK_SIZE,
    MEMORY_MANAGER_SMALL_BLOCK_SIZE,
    MEMORY_MANAGER_MEDIUM_BLOCK_SIZE,
    MEMORY_MANAGER_LARGE_BLOCK_SIZE,
    MEMORY_MANAGER_XLARGE_BLOCK_SIZE,
    MEMORY_MANAGER_XXLARGE_BLOCK_SIZE
};

/**@brief Table for book keeping largest size allocated in each block range. */
static uint32_t m_max_size[BLOCK_CAT_COUNT];

/**@brief Global pointing to minimum size holder for block type being allocated. */
static uint32_t * p_min_size;

/**@brief Global pointing to maximum size holder for block type being allocated. */
static uint32_t * p_max_size;

/**@brief Lookup table for count of block available in each block category. */
static uint32_t m_block_count[BLOCK_CAT_COUNT] =
{
    MEMORY_MANAGER_XXSMALL_BLOCK_COUNT,
    MEMORY_MANAGER_XSMALL_BLOCK_COUNT,
    MEMORY_MANAGER_SMALL_BLOCK_COUNT,
    MEMORY_MANAGER_MEDIUM_BLOCK_COUNT,
    MEMORY_MANAGER_LARGE_BLOCK_COUNT,
    MEMORY_MANAGER_XLARGE_BLOCK_COUNT,
    MEMORY_MANAGER_XXLARGE_BLOCK_COUNT
};

#endif // MEM_MANAGER_ENABLE_DIAGNOSTICS

SDK_MUTEX_DEFINE(m_mm_mutex)                                                                        /**< Mutex variable. Currently unused, this declaration does not occupy any space in RAM. */
#if (MEM_MANAGER_DISABLE_API_PARAM_CHECK == 0)
static bool     m_module_initialized = false;                                                       /**< State indicating if module is initialized or not. */
#endif // MEM_MANAGER_DISABLE_API_PARAM_CHECK


/**@brief Function to get X and Y coordinates.
 *
 * @details Function to get X and Y co-ordinates for the block identified by index.
 *          Here, X determines relevant word for the block. Y determines the actual bit in the word.
 *
 * @param[in]  index Identifies the block.
 * @param[out] p_x   Points to the word that contains the bit representing the block.
 * @param[out] p_y   Contains the bitnumber in the the word 'X' relevant to the block.
 */
static __INLINE void get_block_coordinates(uint32_t block_index, uint32_t * p_x, uint32_t * p_y)
{
    // Determine position of the block in the bitmap.
    // X determines relevant word for the block. Y determines the actual bit in the word.
    const uint32_t x = block_index / BITMAP_SIZE;
    const uint32_t y = (block_index - x * BITMAP_SIZE);

    (*p_x) = x;
    (*p_y) = y;
}


/**@brief Initializes the block by setting it to be free. */
static void block_init (uint32_t block_index)
{
    uint32_t x;
    uint32_t y;

    // Determine position of the block in the bitmap.
    // X determines relevant word for the block. Y determines the actual bit in the word.
    get_block_coordinates(block_index, &x, &y);

    // Set bit related to the block to indicate that the block is free.
    SET_BIT(m_mem_pool[x], y);
}


/**@brief Function to get the category of the block of size 'size' or block number 'block_index'.*/
static __INLINE uint32_t get_block_cat(uint32_t size, uint32_t block_index)
{
    for (uint32_t block_cat = 0; block_cat < BLOCK_CAT_COUNT; block_cat++)
    {
        if (((size != 0) && (size <= m_block_size[block_cat]) &&
            (m_block_end[block_cat] != m_block_start[block_cat])) ||
            (block_index < m_block_end[block_cat]))
        {
            return block_cat;
        }
    }

    return 0;
}


/**@brief Function to get the size of the block number 'block_index'. */
static __INLINE uint32_t get_block_size(uint32_t block_index)
{
    const uint32_t block_cat = get_block_cat(0, block_index);

    #ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS
        p_min_size = &m_min_size[block_cat];
        p_max_size = &m_max_size[block_cat];
    #endif // MEM_MANAGER_ENABLE_DIAGNOSTICS

    return m_block_size[block_cat];
}


/**@brief Function to free the block identified by block number 'block_index'. */
static bool is_block_free(uint32_t block_index)
{
    uint32_t x;
    uint32_t y;

    // Determine position of the block in the bitmap.
    // X determines relevant word for the block. Y determines the actual bit in the word.
    get_block_coordinates(block_index, &x, &y);

    return IS_SET(m_mem_pool[x], y);
}


/**@brief Function to allocate the block identified by block number 'block_index'. */
static void block_allocate(uint32_t block_index)
{
    uint32_t x;
    uint32_t y;

    // Determine position of the block in the bitmap.
    // X determines relevant word for the block. Y determines the actual bit in the word.
    get_block_coordinates(block_index, &x, &y);

    CLR_BIT(m_mem_pool[x], y);
}


uint32_t nrf_mem_init(void)
{
    NRF_LOG_DEBUG("[MM]: >> nrf_mem_init.\r\n");

    SDK_MUTEX_INIT(m_mm_mutex);

    MM_MUTEX_LOCK();

    uint32_t block_index = 0;

    for (block_index = 0; block_index < TOTAL_BLOCK_COUNT; block_index++)
    {
        block_init(block_index);
    }

#if (MEM_MANAGER_DISABLE_API_PARAM_CHECK == 0)
    m_module_initialized = true;
#endif // MEM_MANAGER_DISABLE_API_PARAM_CHECK

#ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS
        nrf_mem_diagnose();
#endif // MEM_MANAGER_ENABLE_DIAGNOSTICS

    MM_MUTEX_UNLOCK();

    NRF_LOG_DEBUG("[MM]: << nrf_mem_init.\r\n");

    return NRF_SUCCESS;
}


uint32_t nrf_mem_reserve(uint8_t ** pp_buffer, uint32_t * p_size)
{
    VERIFY_MODULE_INITIALIZED();
    NULL_PARAM_CHECK(pp_buffer);
    NULL_PARAM_CHECK(p_size);

    const uint32_t requested_size = (*p_size);

    VERIFY_REQUESTED_SIZE(requested_size);

    NRF_LOG_DEBUG("[MM]: >> nrf_mem_reserve, size 0x%04lX.\r\n", requested_size);

    MM_MUTEX_LOCK();

    const uint32_t block_cat    = get_block_cat(requested_size, TOTAL_BLOCK_COUNT);
    uint32_t       block_index  = m_block_start[block_cat];
    uint32_t       memory_index = m_block_mem_start[block_cat];
    uint32_t       err_code     = (NRF_ERROR_NO_MEM | NRF_ERROR_MEMORY_MANAGER_ERR_BASE);

    NRF_LOG_DEBUG("[MM]: Start index for the pool = 0x%08lX, total block count 0x%08X\r\n",
           block_index,
           TOTAL_BLOCK_COUNT);

    for (; block_index < TOTAL_BLOCK_COUNT; block_index++)
    {
        uint32_t block_size = get_block_size(block_index);

        if (is_block_free(block_index) == true)
        {
            NRF_LOG_DEBUG("[MM]: Reserving block 0x%08lX\r\n", block_index);

            // Search succeeded, found free block.
            err_code     = NRF_SUCCESS;

            // Allocate block.
            block_allocate(block_index);

            (*pp_buffer) = &m_memory[memory_index];
            (*p_size)    = block_size;

            #ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS
                (*p_min_size) = MIN((*p_min_size), requested_size);
                (*p_max_size) = MAX((*p_max_size), requested_size);
            #endif // MEM_MANAGER_ENABLE_DIAGNOSTICS

            break;
        }
        memory_index += block_size;
    }
    if (err_code != NRF_SUCCESS)
    {
        NRF_LOG_DEBUG ("[MM]: Memory reservation result %d, memory %p, size %d!",
                err_code,
                (uint32_t)(*pp_buffer),
                (*p_size));

        #ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS
        nrf_mem_diagnose();
        #endif // MEM_MANAGER_ENABLE_DIAGNOSTICS
    }

    MM_MUTEX_UNLOCK();

    NRF_LOG_DEBUG("[MM]: << nrf_mem_reserve %p, result 0x%08lX.\r\n",
                 (uint32_t)(*pp_buffer), err_code);

    return err_code;
}


void * nrf_malloc(uint32_t size)
{
    uint8_t * buffer = NULL;
    uint32_t allocated_size = size;

    uint32_t retval = nrf_mem_reserve(&buffer, &allocated_size);

    if (retval != NRF_SUCCESS)
    {
        buffer = NULL;
    }

    return buffer;
}


void * nrf_calloc(uint32_t count, uint32_t size)
{
    uint8_t * buffer = NULL;
    uint32_t allocated_size = (size * count);

    NRF_LOG_DEBUG ("[nrf_calloc]: Requested size %d, count %d\r\n", allocated_size, count);

    uint32_t retval = nrf_mem_reserve(&buffer,&allocated_size);
    if (retval == NRF_SUCCESS)
    {
        NRF_LOG_DEBUG ("[nrf_calloc]: buffer %p, total size %d\r\n", (uint32_t)buffer, allocated_size);
        memset(buffer,0, allocated_size);
    }
    else
    {
        NRF_LOG_DEBUG("[nrf_calloc]: Failed to allocate memory %d\r\n", allocated_size);
        buffer = NULL;
    }

    return buffer;
}


void nrf_free(void * p_mem)
{
    VERIFY_MODULE_INITIALIZED_VOID();
    NULL_PARAM_CHECK_VOID(p_mem);

    NRF_LOG_DEBUG("[MM]: >> nrf_free %p.\r\n", (uint32_t)p_mem);

    MM_MUTEX_LOCK();

    uint32_t index;
    uint32_t memory_index = 0;

    for (index = 0; index < TOTAL_BLOCK_COUNT; index++)
    {
        if (&m_memory[memory_index] == p_mem)
        {
            // Found a free block of memory, assign.
            NRF_LOG_DEBUG("[MM]: << Freeing block %d.\r\n", index);
            block_init(index);
            break;
        }
        memory_index += get_block_size(index);
    }

    MM_MUTEX_UNLOCK();

    NRF_LOG_DEBUG("[MM]: << nrf_free.\r\n");
    return;
}


void * nrf_realloc(void * p_mem, uint32_t size)
{
    return p_mem;
}


#ifdef MEM_MANAGER_ENABLE_DIAGNOSTICS

/**@brief Function to format and print information with respect to each block.
 *
 * @details Internal function that formats and prints information related to the block category
 *          identified by 'block_cat'. This function also appends the number of bytes in use to
 *          p_mem_in_use based on current count of block in the category.
 *
 * @param[in]  block_cat    Identifies the category of block.
 * @param[out] p_mem_in_use Updates the memory in use based on count in use.
 */
void print_block_info(uint32_t block_cat, uint32_t * p_mem_in_use)
{
    #define PRINT_COLUMN_WIDTH      13
    #define PRINT_BUFFER_SIZE       80
    #define ASCII_VALUE_FOR_SPACE   32

    char           print_buffer[PRINT_BUFFER_SIZE];
    const uint32_t total_count   = (m_block_start[block_cat] + m_block_count[block_cat]);
    uint32_t       in_use        = 0;
    uint32_t       num_of_blocks = 0;
    uint32_t       index         = m_block_start[block_cat];
    uint32_t       column_number;

    // No statistic provided in case block category is not included.
    if (m_block_count[block_cat] != 0)
    {
        memset(print_buffer, ASCII_VALUE_FOR_SPACE, PRINT_BUFFER_SIZE);

        for (; index < total_count; index++)
        {
            if (is_block_free(index) == false)
            {
                num_of_blocks++;
                in_use += m_block_size[block_cat];
            }
        }

        column_number = 0;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %s",
                 m_block_desc_str[block_cat]);

        column_number++;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %d",
                 m_block_size[block_cat]);

        column_number++;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %d",
                 m_block_count[block_cat]);

        column_number++;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %d",
                 num_of_blocks);

        column_number++;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %d",
                 m_min_size[block_cat]);

        column_number++;
        snprintf(&print_buffer[column_number * PRINT_COLUMN_WIDTH],
                 PRINT_COLUMN_WIDTH,
                 "| %d",
                 m_max_size[block_cat]);

        column_number++;
        const uint32_t column_end = (column_number * PRINT_COLUMN_WIDTH);

        for (int j = 0; j < column_end; j ++)
        {
            if (print_buffer[j] == 0)
            {
                print_buffer[j] = 0x20;
            }
        }
        snprintf(&print_buffer[column_end], 2, "|");

        NRF_LOG_BYTES_DEBUG(print_buffer, strlen(print_buffer));

        (*p_mem_in_use) += in_use;
    }
}


void nrf_mem_diagnose(void)
{
    uint32_t in_use = 0;

    NRF_LOG_DEBUG ("\r\n");
    NRF_LOG_DEBUG ("+------------+------------+------------+------------+------------+------------+\r\n");
    NRF_LOG_DEBUG ("| Block      | Size       | Total      | In Use     | Min Alloc  | Max Alloc  |\r\n");
    NRF_LOG_DEBUG ("+------------+------------+------------+------------+------------+------------+\r\n");

    print_block_info(BLOCK_CAT_XXS, &in_use);
    print_block_info(BLOCK_CAT_XS, &in_use);
    print_block_info(BLOCK_CAT_SMALL, &in_use);
    print_block_info(BLOCK_CAT_MEDIUM, &in_use);
    print_block_info(BLOCK_CAT_LARGE, &in_use);
    print_block_info(BLOCK_CAT_XL, &in_use);
    print_block_info(BLOCK_CAT_XXL, &in_use);

    NRF_LOG_DEBUG ("+------------+------------+------------+------------+------------+------------+\r\n");
    NRF_LOG_DEBUG ("| Total      | %d      | %d        | %d\r\n",
            TOTAL_MEMORY_SIZE, TOTAL_BLOCK_COUNT,in_use);
    NRF_LOG_DEBUG ("+------------+------------+------------+------------+------------+------------+\r\n");
}

#endif // MEM_MANAGER_ENABLE_DIAGNOSTICS
/** @} */
#endif //NRF_MODULE_ENABLED(MEM_MANAGER)