Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers cn-context.c Source File

cn-context.c

00001 #ifdef USE_CBOR_CONTEXT
00002 #include "cn-cbor.h"
00003 #include "cbor.h"
00004 #include <stdlib.h>
00005 #include <string.h>
00006 
00007 cn_cbor_context context_obj;
00008 cn_cbor_context *cbor_context = &context_obj;
00009 cbor_mem_pool mem_pool_internal;
00010 
00011 #ifdef USE_CBOR_CONTEXT_STATS
00012 uint32_t calloc_heap_cntr = 0;
00013 uint32_t free_heap_cntr = 0;
00014 uint32_t calloc_pool_cntr = 0;
00015 uint32_t free_pool_cntr = 0;
00016 uint32_t bytes_heap_allocated = 0;
00017 uint32_t total_bytes_heap_allocated = 0;
00018 uint32_t max_bytes_heap_allocated = 0;
00019 uint32_t bytes_pool_allocated = 0;
00020 uint32_t total_bytes_pool_allocated = 0;
00021 uint32_t max_bytes_pool_allocated = 0;
00022 uint32_t number_of_pools_allocated = 0;
00023 uint32_t total_bytes_allocated_for_pools = 0;
00024 #endif // USE_CBOR_CONTEXT_STATS
00025 
00026 //#include <strings.h>
00027 
00028 #define BITMAP_ENTRY_SIZE_IN_BITS ( sizeof(mem_pool->bitmap[0]) * 8 )
00029 #define BITMAP_FULL (-1)
00030 
00031 #ifdef USE_CBOR_CONTEXT_STATS
00032 #define CBOR_STATS_FREE(mem) do { \
00033                                         free_##mem##_cntr++; \
00034                                         bytes_##mem##_allocated -= sizeof(cn_cbor); \
00035                                       } while(0) 
00036 
00037 #define CBOR_STATS_CALLOC(mem, size, count) do { \
00038                                         calloc_##mem##_cntr++; \
00039                                         bytes_##mem##_allocated += size * count; \
00040                                         total_bytes_##mem##_allocated += size * count; \
00041                                         if (bytes_##mem##_allocated > max_bytes_##mem##_allocated) { \
00042                                             max_bytes_##mem##_allocated = bytes_##mem##_allocated; \
00043                                         } \
00044                                         } while (0)
00045 #else
00046 #define CBOR_STATS_FREE(mem) 
00047 #define CBOR_STATS_CALLOC(mem, size, count) 
00048 #endif //USE_CBOR_CONTEXT_STATS
00049 
00050 // Count leading zeros in pure C (https://stackoverflow.com/questions/23856596/counting-leading-zeros-in-a-32-bit-unsigned-integer-with-best-algorithm-in-c-pro) 
00051 static int clz_pure_c(uint32_t a)
00052 {
00053     static const char debruijn32[32] = {
00054         0, 31, 9, 30, 3, 8, 13, 29, 2, 5, 7, 21, 12, 24, 28, 19,
00055         1, 10, 4, 14, 6, 22, 25, 20, 11, 15, 23, 26, 16, 27, 17, 18
00056     };
00057 
00058     // This algorithm does work correctly for input 0, so we handle it independently
00059     if (a == 0) {
00060         return 32;
00061     }
00062 
00063     a |= a >> 1;
00064     a |= a >> 2;
00065     a |= a >> 4;
00066     a |= a >> 8;
00067     a |= a >> 16;
00068     a++;
00069 
00070     return debruijn32[a * 0x076be629 >> 27];
00071 }
00072 
00073 // Count leading zeros. Use compiler functions that use direct machine instructions if possible
00074 static int count_leading_zeros(uint32_t a)
00075 {
00076     // If GCC
00077 #if defined(__GNUC__)
00078     return __builtin_clz(a);
00079 #elif defined(__arm__)
00080     return __clz(a);
00081 
00082 #else // If not GCC or ARMCC, use pure C implementation
00083     return clz_pure_c();
00084 
00085 #endif
00086 }
00087 
00088 // Count trailing zeros using using the count leading zeros command (https://community.arm.com/community-help/f/discussions/2114/count-trailing-zeros)
00089 static int ctz(uint32_t a)
00090 {
00091     int c = count_leading_zeros(a & -a);
00092     return a ? 31 - c : c;
00093 }
00094 
00095 // Get the index of the first 0 bit in bitmap_entry
00096 static int find_first_open_slot(int32_t bitmap_entry)
00097 {
00098     int pos = ctz(~bitmap_entry);
00099 
00100     return (pos < 32) ? pos : -1;
00101 }
00102 
00103 // NOTE: CBOR library uses only calloc(1, sizeof(cn_cbor)). Currently only calloc(1,sizeof(cn_cbor)) is supported by the allocator
00104 /**
00105 * Allocate space for count (currently must be 1) CBOR elements.
00106 *
00107 * NOTE: CBOR library uses only calloc(1, sizeof(cn_cbor)). Currently only calloc(1,sizeof(cn_cbor)) currently supported by allocator.
00108 * @param[in] count             Count of number of elements in allocated array. Currently must be 1.
00109 * @param[in]  size             Size of each element in the allocated array. Must be sizeof(cn_cbor)
00110 * @param[in]  context          Pointer to the CBOR context.
00111 * @return                      The address of the allocated memory.
00112 */
00113 void *cbor_calloc(size_t count, size_t size, void *context)
00114 {
00115     void *ret_mem;
00116     int bitmap_idx, pos, bit_pos, max_bitmap_idx;
00117     cbor_mem_pool *mem_pool = (cbor_mem_pool *)(context);
00118 
00119     // Currently supports only allocations of 1 slot. CBOR lib never allocates more than that.
00120     if (count != 1 || size != sizeof(cn_cbor)) {
00121         return NULL;
00122     }
00123 
00124     // Get the index of the last entry in the bitmap array
00125     max_bitmap_idx = mem_pool->pool_size_in_cbors / BITMAP_ENTRY_SIZE_IN_BITS;
00126 
00127     // If number of CBOR objects in pool is not divisible by 8, there is an additional entry to the bitmap for the residue
00128     if (mem_pool->pool_size_in_cbors % BITMAP_ENTRY_SIZE_IN_BITS != 0) {
00129         max_bitmap_idx++;
00130     }
00131 
00132     for (bitmap_idx = 0; bitmap_idx < max_bitmap_idx; bitmap_idx++) {
00133         // If bitmap entry is full, try next
00134         if (mem_pool->bitmap[bitmap_idx] == BITMAP_FULL) {
00135             continue;
00136         }
00137         // Find first open slot in bitmap[bitmap_idx]
00138         bit_pos = find_first_open_slot(mem_pool->bitmap[bitmap_idx]);
00139         // If found open slot
00140         if (bit_pos >= 0) {
00141 
00142             // Adjust position for CBOR pool
00143             pos = bit_pos + (bitmap_idx * BITMAP_ENTRY_SIZE_IN_BITS);
00144 
00145             // If position not in pool (since the size is not divisible by the size of each entry in the bitmap array in bits)
00146             if (pos >= mem_pool->pool_size_in_cbors) {
00147                 break;
00148             }
00149 
00150             ret_mem = &(mem_pool->pool[pos]);
00151 
00152             // Zero the returned memory (CBOR lib demands this)
00153             memset(ret_mem, 0, sizeof(mem_pool->pool[pos]));
00154 
00155             // Set the bit in index pos
00156             mem_pool->bitmap[bitmap_idx] = mem_pool->bitmap[bitmap_idx] | (1ULL << bit_pos);
00157 
00158             CBOR_STATS_CALLOC(pool, size, count);
00159             return ret_mem;
00160         }
00161     }
00162 
00163     // If no space in pool, use LIBC calloc
00164     CBOR_STATS_CALLOC(heap, size, count);
00165     return calloc(count, size);
00166 }
00167 
00168 // Return whether a given address resides within the allocated CBOR pool
00169 #define IS_IN_POOL(cbor_ptr, mem_pool) (( (uint8_t*)cbor_ptr >= ((uint8_t*) &(mem_pool->pool[0]))) && ( (uint8_t*)cbor_ptr <= ((uint8_t*) &(mem_pool->pool[mem_pool->pool_size_in_cbors - 1]))))
00170 
00171 // Assuming cbor_ptr points to a cn_cbor object in the pool, return its index in the pool. Use this macro ONLY after asserting that cbor_ptr is in pool using IS_IN_POOL().
00172 #define POS_IN_POOL(cbor_ptr, mem_pool) ( ((uint8_t*)cbor_ptr - ((uint8_t*) &(mem_pool->pool[0]))) / sizeof(mem_pool->pool[0]) )
00173 
00174 // Get the index of the bitmap array, in which the bit corresponding to mem_pool->pool[position_in_pool] resides.
00175 #define INDEX_IN_BITMAP(position_in_pool, mem_pool) ( position_in_pool / (sizeof(mem_pool->bitmap[0]) * 8 ) )
00176 
00177 // Get the position of the bit in the bitmap, corresponding to mem_pool->pool[position_in_pool].
00178 #define POS_IN_INDEX(position_in_pool) ( position_in_pool % (sizeof(mem_pool->bitmap[0]) * 8 ) )
00179 
00180 /**
00181 * Free a cn_cbor object.
00182 * If the cn_cbor pointed to by ptr is in the pool, simply unset the corresponding bit in the bitmap.
00183 * If the cn_cbor pointed to by ptr is not in the pool, assume it was allocated with LIBC calloc (since pool was full), and free it using LIBC free.
00184 *
00185 * @param[in]  ptr              Pointer to a cn_cbor object we wish to free
00186 * @param[in]  context          Pointer to the CBOR context.
00187 * @return                      The address of the allocated memory.
00188 */
00189 
00190 void cbor_free(void *ptr, void *context)
00191 {
00192     int pos, bitmap_idx;
00193     cbor_mem_pool *mem_pool = (cbor_mem_pool *)(context);
00194 
00195     // If ptr is in internal pool simply unset its bit in the bitmap
00196     if (IS_IN_POOL(ptr, mem_pool)) {
00197         // Get position of the bit
00198         pos = POS_IN_POOL(ptr, mem_pool);
00199 
00200         bitmap_idx = INDEX_IN_BITMAP(pos, mem_pool);
00201         int pos_in_index = POS_IN_INDEX(pos);
00202         // Set the bit in the corresponding offset in the correct index of the bitmap
00203         mem_pool->bitmap[bitmap_idx] = mem_pool->bitmap[bitmap_idx] & ~(1ULL << pos_in_index);
00204 
00205         CBOR_STATS_FREE(pool);
00206     } else { // If not in pool - allocated with libc calloc(), so we use libc free()
00207         free(ptr);
00208 
00209         CBOR_STATS_FREE(heap);
00210     }
00211 }
00212 
00213 cn_cbor_context *cn_cbor_init_context(size_t num_of_cbors_in_pool)
00214 {
00215     if (num_of_cbors_in_pool > MAX_SIZE_POOL_IN_CBORS) {
00216         return NULL;
00217     }
00218 
00219     memset(&mem_pool_internal, 0, sizeof(mem_pool_internal));
00220 
00221     cbor_context->calloc_func = cbor_calloc;
00222     cbor_context->free_func = cbor_free;
00223 
00224     mem_pool_internal.pool = calloc(num_of_cbors_in_pool, sizeof(cn_cbor));
00225     mem_pool_internal.pool_size_in_cbors = num_of_cbors_in_pool;
00226 
00227     cbor_context->context = &mem_pool_internal;
00228 
00229 #ifdef USE_CBOR_CONTEXT_STATS
00230     number_of_pools_allocated++;
00231     total_bytes_allocated_for_pools += (num_of_cbors_in_pool * sizeof(cn_cbor));
00232 #endif // USE_CBOR_CONTEXT_STATS
00233 
00234     return cbor_context;
00235 }
00236 
00237 void cn_cbor_free_context(cn_cbor_context *ctx)
00238 {
00239     if (ctx && ctx->context) {
00240         free(((cbor_mem_pool *)(ctx->context))->pool);
00241     }
00242 }
00243 
00244 #ifdef USE_CBOR_CONTEXT_STATS
00245 #include <inttypes.h>
00246 void cn_cbor_context_print_stats()
00247 {
00248     printf("  ***************** CBOR Memory Statistics *****************\n");
00249     printf("  * Total bytes allocated on heap:                       %" PRIu32 "\n", total_bytes_heap_allocated);
00250     printf("  * Number of heap allocations:                          %" PRIu32 "\n", calloc_heap_cntr);
00251     printf("  * Number of heap frees:                                %" PRIu32 "\n", free_heap_cntr);
00252     printf("  * Max peak ever allocated (heap):                      %" PRIu32 "\n", max_bytes_heap_allocated);
00253     printf("  *\n");
00254     printf("  * Total bytes allocated in pool:                       %" PRIu32 "\n", total_bytes_pool_allocated);
00255     printf("  * Number of pool allocations:                          %" PRIu32 "\n", calloc_pool_cntr);
00256     printf("  * Number of pool frees:                                %" PRIu32 "\n", free_pool_cntr);
00257     printf("  * Max peak ever allocated (pool):                      %" PRIu32 "\n", max_bytes_pool_allocated);
00258     printf("  *\n");
00259     printf("  * Total size of All CBOR pools ever allocated (bytes): %" PRIu32 "\n", total_bytes_allocated_for_pools);
00260     printf("  * Number of pools allocated:                           %" PRIu32 "\n", number_of_pools_allocated);
00261     printf("  ***********************************************************\n");
00262 }
00263 
00264 void cn_cbor_context_reset_stats()
00265 {
00266     calloc_heap_cntr = 0;
00267     free_heap_cntr = 0;
00268     calloc_pool_cntr = 0;
00269     free_pool_cntr = 0;
00270     bytes_heap_allocated = 0;
00271     total_bytes_heap_allocated = 0;
00272     max_bytes_heap_allocated = 0;
00273     bytes_pool_allocated = 0;
00274     total_bytes_pool_allocated = 0;
00275     max_bytes_pool_allocated = 0;
00276     number_of_pools_allocated = 0;
00277     total_bytes_allocated_for_pools = 0;
00278 }
00279 
00280 #endif // USE_CBOR_CONTEXT_STATS
00281 
00282 #endif // USE_CBOR_CONTEXT