Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of nRF51822 by
app_util.h
00001 /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 00002 * 00003 * The information contained herein is property of Nordic Semiconductor ASA. 00004 * Terms and conditions of usage are described in detail in NORDIC 00005 * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 00006 * 00007 * Licensees are granted free, non-transferable use of the information. NO 00008 * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 00009 * the file. 00010 * 00011 */ 00012 00013 /** @file 00014 * 00015 * @defgroup app_util Utility Functions and Definitions 00016 * @{ 00017 * @ingroup app_common 00018 * 00019 * @brief Various types and definitions available to all applications. 00020 */ 00021 00022 #ifndef APP_UTIL_H__ 00023 #define APP_UTIL_H__ 00024 00025 #include <stdint.h> 00026 #include "nordic_global.h" 00027 #include "compiler_abstraction.h" 00028 #include "nrf51.h" 00029 #include "app_error.h " 00030 00031 /**@brief The interrupt priorities available to the application while the softdevice is active. */ 00032 typedef enum 00033 { 00034 APP_IRQ_PRIORITY_HIGH = 1, 00035 APP_IRQ_PRIORITY_LOW = 3 00036 } app_irq_priority_t; 00037 00038 enum 00039 { 00040 UNIT_0_625_MS = 625, /**< Number of microseconds in 0.625 milliseconds. */ 00041 UNIT_1_25_MS = 1250, /**< Number of microseconds in 1.25 milliseconds. */ 00042 UNIT_10_MS = 10000 /**< Number of microseconds in 10 milliseconds. */ 00043 }; 00044 00045 #define NRF_APP_PRIORITY_THREAD 4 /**< "Interrupt level" when running in Thread Mode. */ 00046 00047 /**@cond NO_DOXYGEN */ 00048 #define EXTERNAL_INT_VECTOR_OFFSET 16 00049 /**@endcond */ 00050 00051 /**@brief Macro for doing static (i.e. compile time) assertion. 00052 * 00053 * @note If the assertion fails when compiling using Keil, the compiler will report error message 00054 * "error: #94: the size of an array must be greater than zero" (while gcc will list the 00055 * symbol static_assert_failed, making the error message more readable). 00056 * If the supplied expression can not be evaluated at compile time, Keil will report 00057 * "error: #28: expression must have a constant value". 00058 * 00059 * @note The macro is intentionally implemented not using do while(0), allowing it to be used 00060 * outside function blocks (e.g. close to global type- and variable declarations). 00061 * If used in a code block, it must be used before any executable code in this block. 00062 * 00063 * @param[in] EXPR Constant expression to be verified. 00064 */ 00065 00066 #define STATIC_ASSERT(EXPR) typedef char static_assert_failed[(EXPR) ? 1 : -1] 00067 00068 /**@brief type for holding an encoded (i.e. little endian) 16 bit unsigned integer. */ 00069 typedef uint8_t uint16_le_t[2]; 00070 00071 /**@brief type for holding an encoded (i.e. little endian) 32 bit unsigned integer. */ 00072 typedef uint8_t uint32_le_t[4]; 00073 00074 /**@brief Byte array type. */ 00075 typedef struct 00076 { 00077 uint16_t size; /**< Number of array entries. */ 00078 uint8_t * p_data; /**< Pointer to array entries. */ 00079 } uint8_array_t; 00080 00081 /**@brief Macro for entering a critical region. 00082 * 00083 * @note Due to implementation details, there must exist one and only one call to 00084 * CRITICAL_REGION_EXIT() for each call to CRITICAL_REGION_ENTER(), and they must be located 00085 * in the same scope. 00086 */ 00087 #define CRITICAL_REGION_ENTER() \ 00088 { \ 00089 uint8_t IS_NESTED_CRITICAL_REGION = 0; \ 00090 uint32_t CURRENT_INT_PRI = current_int_priority_get(); \ 00091 if (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH) \ 00092 { \ 00093 uint32_t ERR_CODE = sd_nvic_critical_region_enter(&IS_NESTED_CRITICAL_REGION); \ 00094 if (ERR_CODE == NRF_ERROR_SOFTDEVICE_NOT_ENABLED) \ 00095 { \ 00096 __disable_irq(); \ 00097 } \ 00098 else \ 00099 { \ 00100 APP_ERROR_CHECK(ERR_CODE); \ 00101 } \ 00102 } 00103 00104 /**@brief Macro for leaving a critical region. 00105 * 00106 * @note Due to implementation details, there must exist one and only one call to 00107 * CRITICAL_REGION_EXIT() for each call to CRITICAL_REGION_ENTER(), and they must be located 00108 * in the same scope. 00109 */ 00110 #define CRITICAL_REGION_EXIT() \ 00111 if (CURRENT_INT_PRI != APP_IRQ_PRIORITY_HIGH) \ 00112 { \ 00113 uint32_t ERR_CODE; \ 00114 __enable_irq(); \ 00115 ERR_CODE = sd_nvic_critical_region_exit(IS_NESTED_CRITICAL_REGION); \ 00116 if (ERR_CODE != NRF_ERROR_SOFTDEVICE_NOT_ENABLED) \ 00117 { \ 00118 APP_ERROR_CHECK(ERR_CODE); \ 00119 } \ 00120 } \ 00121 } 00122 00123 /**@brief Perform rounded integer division (as opposed to truncating the result). 00124 * 00125 * @param[in] A Numerator. 00126 * @param[in] B Denominator. 00127 * 00128 * @return Rounded (integer) result of dividing A by B. 00129 */ 00130 #define ROUNDED_DIV(A, B) (((A) + ((B) / 2)) / (B)) 00131 00132 /**@brief Check if the integer provided is a power of two. 00133 * 00134 * @param[in] A Number to be tested. 00135 * 00136 * @return true if value is power of two. 00137 * @return false if value not power of two. 00138 */ 00139 #define IS_POWER_OF_TWO(A) ( ((A) != 0) && ((((A) - 1) & (A)) == 0) ) 00140 00141 /**@brief To convert ticks to millisecond 00142 * @param[in] time Number of millseconds that needs to be converted. 00143 * @param[in] resolution Units to be converted. 00144 */ 00145 #define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) 00146 00147 00148 /**@brief Perform integer division, making sure the result is rounded up. 00149 * 00150 * @details One typical use for this is to compute the number of objects with size B is needed to 00151 * hold A number of bytes. 00152 * 00153 * @param[in] A Numerator. 00154 * @param[in] B Denominator. 00155 * 00156 * @return Integer result of dividing A by B, rounded up. 00157 */ 00158 #define CEIL_DIV(A, B) \ 00159 /*lint -save -e573 */ \ 00160 ((((A) - 1) / (B)) + 1) \ 00161 /*lint -restore */ 00162 00163 /**@brief Function for encoding a uint16 value. 00164 * 00165 * @param[in] value Value to be encoded. 00166 * @param[out] p_encoded_data Buffer where the encoded data is to be written. 00167 * 00168 * @return Number of bytes written. 00169 */ 00170 static __INLINE uint8_t uint16_encode(uint16_t value, uint8_t * p_encoded_data) 00171 { 00172 p_encoded_data[0] = (uint8_t) ((value & 0x00FF) >> 0); 00173 p_encoded_data[1] = (uint8_t) ((value & 0xFF00) >> 8); 00174 return sizeof(uint16_t); 00175 } 00176 00177 /**@brief Function for encoding a uint32 value. 00178 * 00179 * @param[in] value Value to be encoded. 00180 * @param[out] p_encoded_data Buffer where the encoded data is to be written. 00181 * 00182 * @return Number of bytes written. 00183 */ 00184 static __INLINE uint8_t uint32_encode(uint32_t value, uint8_t * p_encoded_data) 00185 { 00186 p_encoded_data[0] = (uint8_t) ((value & 0x000000FF) >> 0); 00187 p_encoded_data[1] = (uint8_t) ((value & 0x0000FF00) >> 8); 00188 p_encoded_data[2] = (uint8_t) ((value & 0x00FF0000) >> 16); 00189 p_encoded_data[3] = (uint8_t) ((value & 0xFF000000) >> 24); 00190 return sizeof(uint32_t); 00191 } 00192 00193 /**@brief Function for decoding a uint16 value. 00194 * 00195 * @param[in] p_encoded_data Buffer where the encoded data is stored. 00196 * 00197 * @return Decoded value. 00198 */ 00199 static __INLINE uint16_t uint16_decode(const uint8_t * p_encoded_data) 00200 { 00201 return ( (((uint16_t)((uint8_t *)p_encoded_data)[0])) | 00202 (((uint16_t)((uint8_t *)p_encoded_data)[1]) << 8 )); 00203 } 00204 00205 /**@brief Function for decoding a uint32 value. 00206 * 00207 * @param[in] p_encoded_data Buffer where the encoded data is stored. 00208 * 00209 * @return Decoded value. 00210 */ 00211 static __INLINE uint32_t uint32_decode(const uint8_t * p_encoded_data) 00212 { 00213 return ( (((uint32_t)((uint8_t *)p_encoded_data)[0]) << 0) | 00214 (((uint32_t)((uint8_t *)p_encoded_data)[1]) << 8) | 00215 (((uint32_t)((uint8_t *)p_encoded_data)[2]) << 16) | 00216 (((uint32_t)((uint8_t *)p_encoded_data)[3]) << 24 )); 00217 } 00218 00219 00220 /**@brief Function for finding the current interrupt level. 00221 * 00222 * @return Current interrupt level. 00223 * @retval APP_IRQ_PRIORITY_HIGH We are running in Application High interrupt level. 00224 * @retval APP_IRQ_PRIORITY_LOW We are running in Application Low interrupt level. 00225 * @retval APP_IRQ_PRIORITY_THREAD We are running in Thread Mode. 00226 */ 00227 static __INLINE uint8_t current_int_priority_get(void) 00228 { 00229 uint32_t isr_vector_num = (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk); 00230 if (isr_vector_num > 0) 00231 { 00232 int32_t irq_type = ((int32_t)isr_vector_num - EXTERNAL_INT_VECTOR_OFFSET); 00233 return (NVIC_GetPriority((IRQn_Type)irq_type) & 0xFF); 00234 } 00235 else 00236 { 00237 return NRF_APP_PRIORITY_THREAD; 00238 } 00239 } 00240 00241 /** @brief Function for converting the input voltage (in milli volts) into percentage of 3.0 Volts. 00242 * 00243 * @details The calculation is based on a linearized version of the battery's discharge 00244 * curve. 3.0V returns 100% battery level. The limit for power failure is 2.1V and 00245 * is considered to be the lower boundary. 00246 * 00247 * The discharge curve for CR2032 is non-linear. In this model it is split into 00248 * 4 linear sections: 00249 * - Section 1: 3.0V - 2.9V = 100% - 42% (58% drop on 100 mV) 00250 * - Section 2: 2.9V - 2.74V = 42% - 18% (24% drop on 160 mV) 00251 * - Section 3: 2.74V - 2.44V = 18% - 6% (12% drop on 300 mV) 00252 * - Section 4: 2.44V - 2.1V = 6% - 0% (6% drop on 340 mV) 00253 * 00254 * These numbers are by no means accurate. Temperature and 00255 * load in the actual application is not accounted for! 00256 * 00257 * @param[in] mvolts The voltage in mV 00258 * 00259 * @return Battery level in percent. 00260 */ 00261 static __INLINE uint8_t battery_level_in_percent(const uint16_t mvolts) 00262 { 00263 uint8_t battery_level; 00264 00265 if (mvolts >= 3000) 00266 { 00267 battery_level = 100; 00268 } 00269 else if (mvolts > 2900) 00270 { 00271 battery_level = 100 - ((3000 - mvolts) * 58) / 100; 00272 } 00273 else if (mvolts > 2740) 00274 { 00275 battery_level = 42 - ((2900 - mvolts) * 24) / 160; 00276 } 00277 else if (mvolts > 2440) 00278 { 00279 battery_level = 18 - ((2740 - mvolts) * 12) / 300; 00280 } 00281 else if (mvolts > 2100) 00282 { 00283 battery_level = 6 - ((2440 - mvolts) * 6) / 340; 00284 } 00285 else 00286 { 00287 battery_level = 0; 00288 } 00289 00290 return battery_level; 00291 } 00292 00293 /**@brief Function for checking if a pointer value is aligned to a 4 byte boundary. 00294 * 00295 * @param[in] p Pointer value to be checked. 00296 * 00297 * @return TRUE if pointer is aligned to a 4 byte boundary, FALSE otherwise. 00298 */ 00299 static __INLINE bool is_word_aligned(void * p) 00300 { 00301 return (((uint32_t)p & 0x00000003) == 0); 00302 } 00303 00304 #endif // APP_UTIL_H__ 00305 00306 /** @} */
Generated on Tue Jul 12 2022 19:00:51 by
