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(&notifyBlock, 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(&notifyBlock, 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(&notifyBlock, 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