RDK Documentation (Open Sourced RDK Components)
librmh_wrap.h
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 #ifndef LIB_RMH_API_WRAP_H
21 #define LIB_RMH_API_WRAP_H
22 
23 /**********************************************************************************************************************
24 This API wrap uses a bit of preprocessor abuse but in the end I think it's worth it. These macros allow us to:
25 
26 1. Wrap every RMH API to allow for
27  A. Dynamically check SoC library for existance of the API and return UNIMPLEMENTED if it's not found
28  B. Enter/Exit/Return code logging
29  C. Timing APIs
30 2. Generate a struct containing all APIs so when a new one is added it need only be added to the header file and it
31  will automatically appears in the rmh test app
32 3. Time the API to discover where it might be running slow
33 **********************************************************************************************************************/
34 
35 
36 
37 /**********************************************************************************************************************
38 These are the basic parameter macros.
39  1) PARAMETERS() just returns everything it was passed. It's used for grouping only.'
40  2) INPUT_PARAM() and OUTPUT_PARAM() simply add RMH_INPUT_PARAM and RMH_OUTPUT_PARAM, respectively, to the parameter
41  list.
42  3) __GET_ARGS() is stripping outter parentheses via __GET_ARGS_UNWRAP
43 **********************************************************************************************************************/
44 #define __GET_ARGS_UNWRAP(...) __VA_ARGS__
45 #define __GET_ARGS(X) __GET_ARGS_UNWRAP X
46 #define INPUT_PARAM(VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR) (RMH_INPUT_PARAM, VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR)
47 #define OUTPUT_PARAM(VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR) (RMH_OUTPUT_PARAM, VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR)
48 #define PARAMETERS(...) (__VA_ARGS__)
49 
50 
51 /**********************************************************************************************************************
52 This group of macros operates on the parameter list of the API.
53 
54 The entry point to this set of macros is __EXE_NUM_PARAMS_X(). It takes one of the COMMAND macros as the first
55 argument. The remaining arguments are the list of parameters for the API in the format:
56 
57  (direction, name, type, "description")
58 
59 For example, you might call:
60 
61  __EXE_NUM_PARAMS_X(__COMMAND_MAKE_VARIABLE_LIST, \
62  (RMH_INPUT_PARAM, handle, const RMH_Handle, "The RMH handle"), \
63  (RMH_OUTPUT_PARAM, value, uint32_t*, "My output"))
64 
65 The first thing __EXE_NUM_PARAMS_X() will do is determine the number of arguments it has been passed (excluding the
66 command). It uses __GET_EXE_MACRO() to do this. In this cases the number of arguments is two. It then calls COMMAND()
67 for each parameter. In our example this would be:
68 
69  __COMMAND_MAKE_VARIABLE_LIST(RMH_INPUT_PARAM, handle, const RMH_Handle, "The RMH handle")
70  __COMMAND_MAKE_VARIABLE_LIST(RMH_OUTPUT_PARAM, value, uint32_t*, "My output")
71 
72 Finally, the output of each COMMAND() is placed in a comma seperated list. This is what will be returned as the final
73 result of __EXE_NUM_PARAMS_X(). In our example, the final output would be:
74 
75  handle, value
76 **********************************************************************************************************************/
77 #define __COMMAND_MAKE_VARIABLE_LIST(VARIABLE_DIRECTION, VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR) VARIABLE_NAME /* Goal is to create a comma seperated list of all parameter variables */
78 #define __COMMAND_MAKE_API_STRUCT(VARIABLE_DIRECTION, VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR) { VARIABLE_DIRECTION, #VARIABLE_NAME, #VARIABLE_TYPE, DESCRIPTION_STR } /* Goal is to create structure entry which describes this parameter */
79 #define __COMMAND_MAKE_TYPE_LIST(VARIABLE_DIRECTION, VARIABLE_NAME, VARIABLE_TYPE, DESCRIPTION_STR) VARIABLE_TYPE VARIABLE_NAME /* Goal is to create a comma seperated list of all variables and types */
80 
81 #define __EXE_NUM_PARAMS_0(COMMAND)
82 #define __EXE_NUM_PARAMS_1(COMMAND, PARAM) COMMAND PARAM
83 #define __EXE_NUM_PARAMS_2(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_1(COMMAND, __VA_ARGS__)
84 #define __EXE_NUM_PARAMS_3(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_2(COMMAND, __VA_ARGS__)
85 #define __EXE_NUM_PARAMS_4(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_3(COMMAND, __VA_ARGS__)
86 #define __EXE_NUM_PARAMS_5(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_4(COMMAND, __VA_ARGS__)
87 #define __EXE_NUM_PARAMS_6(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_5(COMMAND, __VA_ARGS__)
88 #define __EXE_NUM_PARAMS_7(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_6(COMMAND, __VA_ARGS__)
89 #define __EXE_NUM_PARAMS_8(COMMAND, PARAM, ...) COMMAND PARAM, __EXE_NUM_PARAMS_7(COMMAND, __VA_ARGS__)
90 #define __GET_EXE_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, NAME, ...) NAME
91 #define __EXE_NUM_PARAMS_X(COMMAND, ...) __GET_EXE_MACRO(__VA_ARGS__, __EXE_NUM_PARAMS_8, __EXE_NUM_PARAMS_7, __EXE_NUM_PARAMS_6, __EXE_NUM_PARAMS_5, __EXE_NUM_PARAMS_4, __EXE_NUM_PARAMS_3, __EXE_NUM_PARAMS_2, __EXE_NUM_PARAMS_1)(COMMAND, __VA_ARGS__)
92 
93 
94 /**********************************************************************************************************************
95 This macro "wraps" an API. It will:
96 1. Define a function specific to wrapping this API
97 2. The while(0) code is dead code and simply a compiler check to verify all the parameters have been added to the API
98  DECLARATION in the header file. Note, there is no checking of 'type' here. It could be done but it gets much more
99  complicated and probably not worth the complexity.
100 3. The function will execute the generic and SoC versions of the API in order of depending on the values of
101  GENERIC_API_NAME, SOC_API_ENABLED, and SOC_BEFORE_GENERIC. If an api fails, further api calls will not be made.
102 4. We use pRMH_APIWRAP_PreAPIExecute(), pRMH_APIWRAP_GetSoCAPI() and pRMH_APIWRAP_PostAPIExecute() to do as much basic
103  possibile outside of the macro. The param lists prevent us from doing everything in functions.
104 ******************************************/
105 #define __RMH_API_WRAP_TRUE(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, GENERIC_ENABLED, SOC_ENABLED, SOC_BEFORE_GENERIC) \
106  RMH_Result GENERIC_IMPL__##API_NAME (__EXE_NUM_PARAMS_X(__COMMAND_MAKE_TYPE_LIST, __GET_ARGS(PARAMS_LIST))); \
107  RMH_Result SoC_IMPL__##API_NAME (__EXE_NUM_PARAMS_X(__COMMAND_MAKE_TYPE_LIST, __GET_ARGS(PARAMS_LIST))); \
108  DECLARATION { \
109  RMH_Result socRet = RMH_SUCCESS; \
110  RMH_Result genRet = RMH_SUCCESS; \
111  RMH_Result (*socAPI)() = NULL; \
112  while(0) { API_NAME( __EXE_NUM_PARAMS_X(__COMMAND_MAKE_VARIABLE_LIST, __GET_ARGS(PARAMS_LIST)) ); } \
113  pRMH_APIWRAP_PreAPIExecute(handle, #API_NAME, SOC_ENABLED, SOC_BEFORE_GENERIC); \
114  if (SOC_ENABLED) { \
115  socRet = pRMH_APIWRAP_GetSoCAPI(handle, "SoC_IMPL__"#API_NAME, &socAPI); \
116  } \
117  if (socRet == RMH_SUCCESS && SOC_ENABLED && SOC_BEFORE_GENERIC) { \
118  socRet = socAPI(handle-> __EXE_NUM_PARAMS_X(__COMMAND_MAKE_VARIABLE_LIST, __GET_ARGS(PARAMS_LIST))); \
119  } \
120  if (GENERIC_ENABLED && (!SOC_BEFORE_GENERIC || (SOC_BEFORE_GENERIC && socRet == RMH_SUCCESS))) { \
121  genRet = (!SOC_ENABLED || socAPI) ? GENERIC_IMPL__##API_NAME(__EXE_NUM_PARAMS_X(__COMMAND_MAKE_VARIABLE_LIST, __GET_ARGS(PARAMS_LIST))) : RMH_UNIMPLEMENTED; \
122  } \
123  if (socRet == RMH_SUCCESS && SOC_ENABLED && !SOC_BEFORE_GENERIC && genRet == RMH_SUCCESS) { \
124  socRet = socAPI(handle-> __EXE_NUM_PARAMS_X(__COMMAND_MAKE_VARIABLE_LIST, __GET_ARGS(PARAMS_LIST))); \
125  } \
126  return pRMH_APIWRAP_PostAPIExecute(handle, #API_NAME, genRet, socRet); \
127  } \
128  __RMH_REGISTER_API(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, GENERIC_ENABLED, SOC_ENABLED, SOC_BEFORE_GENERIC, SoC_IMPL__##API_NAME, GENERIC_IMPL__##API_NAME);
129 
130 #define __RMH_API_WRAP_FALSE(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, GENERIC_ENABLED, SOC_ENABLED, SOC_BEFORE_GENERIC) \
131  __RMH_REGISTER_API(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, GENERIC_ENABLED, false, SOC_BEFORE_GENERIC, SoC_IMPL__##API_NAME, GENERIC_IMPL__##API_NAME);
132 
133 
134 #define __RM_DEFINE_API_WRAP_TRUE(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, DECLARE_NAME) \
135  RMH_Result DECLARE_NAME (__EXE_NUM_PARAMS_X(__COMMAND_MAKE_TYPE_LIST, __GET_ARGS(PARAMS_LIST)));
136 
137 #define __RM_DEFINE_API_WRAP_FALSE(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, DECLARE_NAME) \
138  DECLARATION;
139 
140 
141 /**********************************************************************************************************************
142 This macro "registers" an API which allows anyone who links this library to get a list of APIs and descriptions.
143 
144 1. Create a structure describing the parameters. It uses __EXE_NUM_PARAMS_X() macro to construct this. This is
145  pRMH_PARAMS_##API_NAME
146 2. Create a structure describing the API itself. This is pRMH_API_##API_NAME
147 3. Register the API in the global context by creating a constructor function. This is
148  pRMH_APIWRAP_RegisterAPI_##API_NAME
149 **********************************************************************************************************************/
150 #define __RMH_REGISTER_API(DECLARATION, API_NAME, DESCRIPTION_STR, PARAMS_LIST, TAGS_STR, GENERIC_ENABLED, SOC_ENABLED, SOC_BEFORE_GENERIC, SOC_API_NAME, GEN_API_NAME) \
151  static RMHGeneric_Param pRMH_PARAMS_##API_NAME[] = { __EXE_NUM_PARAMS_X(__COMMAND_MAKE_API_STRUCT, __GET_ARGS(PARAMS_LIST)) }; \
152  static RMH_API pRMH_API_##API_NAME = { #API_NAME, SOC_ENABLED, GENERIC_ENABLED, #SOC_API_NAME, #DECLARATION, DESCRIPTION_STR, TAGS_STR, sizeof(pRMH_PARAMS_##API_NAME)/sizeof(pRMH_PARAMS_##API_NAME[0]), pRMH_PARAMS_##API_NAME }; \
153  __attribute__((constructor(300))) static void pRMH_APIWRAP_RegisterAPI_##API_NAME() { pRMH_APIWRAP_RegisterAPI(&pRMH_API_##API_NAME); } \
154 
155 #endif /* LIB_RMH_API_WRAP_H */