1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2017 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include "fsl_notifier.h"
10
11 /*******************************************************************************
12 * Definitions
13 ******************************************************************************/
14
15 /*******************************************************************************
16 * Prototypes
17 ******************************************************************************/
18
19 /*******************************************************************************
20 * Variables
21 ******************************************************************************/
22
23 /*******************************************************************************
24 * Code
25 ******************************************************************************/
26
27 /*!
28 * brief Creates a Notifier handle.
29 *
30 * param notifierHandle A pointer to the notifier handle.
31 * param configs A pointer to an array with references to all configurations which is handled by the Notifier.
32 * param configsNumber Number of configurations. Size of the configuration array.
33 * param callbacks A pointer to an array of callback configurations.
34 * If there are no callbacks to register during Notifier initialization, use NULL value.
35 * param callbacksNumber Number of registered callbacks. Size of the callbacks array.
36 * param userFunction User function.
37 * param userData User data passed to user function.
38 * return An error Code or kStatus_Success.
39 */
NOTIFIER_CreateHandle(notifier_handle_t * notifierHandle,notifier_user_config_t ** configs,uint8_t configsNumber,notifier_callback_config_t * callbacks,uint8_t callbacksNumber,notifier_user_function_t userFunction,void * userData)40 status_t NOTIFIER_CreateHandle(notifier_handle_t *notifierHandle,
41 notifier_user_config_t **configs,
42 uint8_t configsNumber,
43 notifier_callback_config_t *callbacks,
44 uint8_t callbacksNumber,
45 notifier_user_function_t userFunction,
46 void *userData)
47 {
48 /* Check input parameter - at least one configuration is required and userFunction must exist */
49 if ((configs == NULL) || (configsNumber == 0U) || (userFunction == NULL))
50 {
51 return kStatus_Fail;
52 }
53 /* Initialize handle structure */
54 (void)memset(notifierHandle, 0, sizeof(notifier_handle_t));
55 /* Store references to user-defined configurations */
56 notifierHandle->configsTable = configs;
57 notifierHandle->configsNumber = configsNumber;
58 /* Store references to user-defined callback configurations */
59 if (callbacks != NULL)
60 {
61 notifierHandle->callbacksTable = callbacks;
62 notifierHandle->callbacksNumber = callbacksNumber;
63 /* If all callbacks return success, then the errorCallbackIndex is callbacksNumber */
64 notifierHandle->errorCallbackIndex = callbacksNumber;
65 }
66 notifierHandle->userFunction = userFunction;
67 notifierHandle->userData = userData;
68
69 return kStatus_Success;
70 }
71
72 /*!
73 * brief Switches the configuration according to a pre-defined structure.
74 *
75 * This function sets the system to the target configuration. Before transition,
76 * the Notifier sends notifications to all callbacks registered to the callback table.
77 * Callbacks are invoked in the following order: All registered callbacks are notified
78 * ordered by index in the callbacks array. The same order is used for before and after switch notifications.
79 * The notifications before the configuration switch can be used to obtain confirmation about
80 * the change from registered callbacks. If any registered callback denies the
81 * configuration change, further execution of this function depends on the notifier policy: the
82 * configuration change is either forced (kNOTIFIER_PolicyForcible) or exited (kNOTIFIER_PolicyAgreement).
83 * When configuration change is forced, the result of the before switch notifications are ignored. If an
84 * agreement is required, if any callback returns an error code, further notifications
85 * before switch notifications are cancelled and all already notified callbacks are re-invoked.
86 * The index of the callback which returned error code during pre-switch notifications is stored
87 * (any error codes during callbacks re-invocation are ignored) and NOTIFIER_GetErrorCallback() can be used to get it.
88 * Regardless of the policies, if any callback returns an error code, an error code indicating in which phase
89 * the error occurred is returned when NOTIFIER_SwitchConfig() exits.
90 * param notifierHandle pointer to notifier handle
91 * param configIndex Index of the target configuration.
92 * param policy Transaction policy, kNOTIFIER_PolicyAgreement or kNOTIFIER_PolicyForcible.
93 *
94 * return An error code or kStatus_Success.
95 *
96 */
NOTIFIER_SwitchConfig(notifier_handle_t * notifierHandle,uint8_t configIndex,notifier_policy_t policy)97 status_t NOTIFIER_SwitchConfig(notifier_handle_t *notifierHandle, uint8_t configIndex, notifier_policy_t policy)
98 {
99 uint8_t currentStaticCallback = 0U; /* Index to array of statically registered call-backs */
100 status_t returnCode = kStatus_Success; /* Function return */
101
102 notifier_notification_block_t notifyBlock; /* Callback notification block */
103 notifier_callback_config_t *callbackConfig; /* Pointer to callback configuration */
104
105 /* Set errorcallbackindex as callbacksNumber, which means no callback error now */
106 notifierHandle->errorCallbackIndex = notifierHandle->callbacksNumber;
107
108 /* Requested configuration availability check */
109 if (configIndex >= notifierHandle->configsNumber)
110 {
111 return kStatus_OutOfRange;
112 }
113
114 /* Initialization of local variables from the Notifier handle structure */
115
116 notifyBlock.policy = policy;
117 notifyBlock.targetConfig = notifierHandle->configsTable[configIndex];
118 notifyBlock.notifyType = kNOTIFIER_NotifyBefore;
119
120 /* From all statically registered call-backs... */
121 for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber; currentStaticCallback++)
122 {
123 callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]);
124 /* ...notify only those which asked to be called before the configuration switch */
125 if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackBefore) != 0U)
126 {
127 /* In case that call-back returned error code mark it, store the call-back handle and eventually cancel
128 * the configuration switch */
129 if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success)
130 {
131 returnCode = (status_t)kStatus_NOTIFIER_ErrorNotificationBefore;
132 notifierHandle->errorCallbackIndex = currentStaticCallback;
133 /* If not forcing configuration switch, call all already notified call-backs to revert their state
134 * as the switch is canceled */
135 if (policy != kNOTIFIER_PolicyForcible)
136 {
137 break;
138 }
139 }
140 }
141 }
142
143 /* Set configuration */
144
145 /* In case that any call-back returned error code and policy doesn't force the configuration set, go to after
146 * switch call-backs */
147 if ((policy == kNOTIFIER_PolicyForcible) || (returnCode == kStatus_Success))
148 {
149 returnCode = notifierHandle->userFunction(notifierHandle->configsTable[configIndex], notifierHandle->userData);
150 if (returnCode != kStatus_Success)
151 {
152 return returnCode;
153 }
154 /* Update current configuration index */
155 notifierHandle->currentConfigIndex = configIndex;
156 notifyBlock.notifyType = kNOTIFIER_NotifyAfter;
157 /* From all statically registered call-backs... */
158 for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber;
159 currentStaticCallback++)
160 {
161 callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]);
162 /* ...notify only those which asked to be called after the configuration switch */
163 if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackAfter) != 0U)
164 {
165 /* In case that call-back returned error code mark it and store the call-back handle */
166 if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success)
167 {
168 returnCode = (status_t)kStatus_NOTIFIER_ErrorNotificationAfter;
169 notifierHandle->errorCallbackIndex = currentStaticCallback;
170 if (policy != kNOTIFIER_PolicyForcible)
171 {
172 break;
173 }
174 }
175 }
176 }
177 }
178 else
179 {
180 /* End of unsuccessful switch */
181 notifyBlock.notifyType = kNOTIFIER_NotifyRecover;
182 while (currentStaticCallback-- > 0U)
183 {
184 callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]);
185 if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackBefore) != 0U)
186 {
187 (void)callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData);
188 }
189 }
190 }
191
192 return returnCode;
193 }
194
195 /*!
196 * brief This function returns the last failed notification callback.
197 *
198 * This function returns an index of the last callback that failed during the configuration switch while
199 * the last NOTIFIER_SwitchConfig() was called. If the last NOTIFIER_SwitchConfig() call ended successfully
200 * value equal to callbacks number is returned. The returned value represents an index in the array of
201 * static call-backs.
202 *
203 * param notifierHandle Pointer to the notifier handle
204 * return Callback Index of the last failed callback or value equal to callbacks count.
205 */
NOTIFIER_GetErrorCallbackIndex(notifier_handle_t * notifierHandle)206 uint8_t NOTIFIER_GetErrorCallbackIndex(notifier_handle_t *notifierHandle)
207 {
208 return notifierHandle->errorCallbackIndex;
209 }
210