/* * Copyright (c) 2015, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "fsl_notifier.h" /******************************************************************************* * Definitions ******************************************************************************/ /******************************************************************************* * Prototypes ******************************************************************************/ /******************************************************************************* * Variables ******************************************************************************/ /******************************************************************************* * Code ******************************************************************************/ /*! * brief Creates a Notifier handle. * * param notifierHandle A pointer to the notifier handle. * param configs A pointer to an array with references to all configurations which is handled by the Notifier. * param configsNumber Number of configurations. Size of the configuration array. * param callbacks A pointer to an array of callback configurations. * If there are no callbacks to register during Notifier initialization, use NULL value. * param callbacksNumber Number of registered callbacks. Size of the callbacks array. * param userFunction User function. * param userData User data passed to user function. * return An error Code or kStatus_Success. */ status_t 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) { /* Check input parameter - at least one configuration is required and userFunction must exist */ if ((configs == NULL) || (configsNumber == 0U) || (userFunction == NULL)) { return kStatus_Fail; } /* Initialize handle structure */ (void)memset(notifierHandle, 0, sizeof(notifier_handle_t)); /* Store references to user-defined configurations */ notifierHandle->configsTable = configs; notifierHandle->configsNumber = configsNumber; /* Store references to user-defined callback configurations */ if (callbacks != NULL) { notifierHandle->callbacksTable = callbacks; notifierHandle->callbacksNumber = callbacksNumber; /* If all callbacks return success, then the errorCallbackIndex is callbacksNumber */ notifierHandle->errorCallbackIndex = callbacksNumber; } notifierHandle->userFunction = userFunction; notifierHandle->userData = userData; return kStatus_Success; } /*! * brief Switches the configuration according to a pre-defined structure. * * This function sets the system to the target configuration. Before transition, * the Notifier sends notifications to all callbacks registered to the callback table. * Callbacks are invoked in the following order: All registered callbacks are notified * ordered by index in the callbacks array. The same order is used for before and after switch notifications. * The notifications before the configuration switch can be used to obtain confirmation about * the change from registered callbacks. If any registered callback denies the * configuration change, further execution of this function depends on the notifier policy: the * configuration change is either forced (kNOTIFIER_PolicyForcible) or exited (kNOTIFIER_PolicyAgreement). * When configuration change is forced, the result of the before switch notifications are ignored. If an * agreement is required, if any callback returns an error code, further notifications * before switch notifications are cancelled and all already notified callbacks are re-invoked. * The index of the callback which returned error code during pre-switch notifications is stored * (any error codes during callbacks re-invocation are ignored) and NOTIFIER_GetErrorCallback() can be used to get it. * Regardless of the policies, if any callback returns an error code, an error code indicating in which phase * the error occurred is returned when NOTIFIER_SwitchConfig() exits. * param notifierHandle pointer to notifier handle * param configIndex Index of the target configuration. * param policy Transaction policy, kNOTIFIER_PolicyAgreement or kNOTIFIER_PolicyForcible. * * return An error code or kStatus_Success. * */ status_t NOTIFIER_SwitchConfig(notifier_handle_t *notifierHandle, uint8_t configIndex, notifier_policy_t policy) { uint8_t currentStaticCallback = 0U; /* Index to array of statically registered call-backs */ status_t returnCode = kStatus_Success; /* Function return */ notifier_notification_block_t notifyBlock; /* Callback notification block */ notifier_callback_config_t *callbackConfig; /* Pointer to callback configuration */ /* Set errorcallbackindex as callbacksNumber, which means no callback error now */ notifierHandle->errorCallbackIndex = notifierHandle->callbacksNumber; /* Requested configuration availability check */ if (configIndex >= notifierHandle->configsNumber) { return kStatus_OutOfRange; } /* Initialization of local variables from the Notifier handle structure */ notifyBlock.policy = policy; notifyBlock.targetConfig = notifierHandle->configsTable[configIndex]; notifyBlock.notifyType = kNOTIFIER_NotifyBefore; /* From all statically registered call-backs... */ for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber; currentStaticCallback++) { callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); /* ...notify only those which asked to be called before the configuration switch */ if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackBefore) != 0U) { /* In case that call-back returned error code mark it, store the call-back handle and eventually cancel * the configuration switch */ if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success) { returnCode = (status_t)kStatus_NOTIFIER_ErrorNotificationBefore; notifierHandle->errorCallbackIndex = currentStaticCallback; /* If not forcing configuration switch, call all already notified call-backs to revert their state * as the switch is canceled */ if (policy != kNOTIFIER_PolicyForcible) { break; } } } } /* Set configuration */ /* In case that any call-back returned error code and policy doesn't force the configuration set, go to after * switch call-backs */ if ((policy == kNOTIFIER_PolicyForcible) || (returnCode == kStatus_Success)) { returnCode = notifierHandle->userFunction(notifierHandle->configsTable[configIndex], notifierHandle->userData); if (returnCode != kStatus_Success) { return returnCode; } /* Update current configuration index */ notifierHandle->currentConfigIndex = configIndex; notifyBlock.notifyType = kNOTIFIER_NotifyAfter; /* From all statically registered call-backs... */ for (currentStaticCallback = 0U; currentStaticCallback < notifierHandle->callbacksNumber; currentStaticCallback++) { callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); /* ...notify only those which asked to be called after the configuration switch */ if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackAfter) != 0U) { /* In case that call-back returned error code mark it and store the call-back handle */ if (callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData) != kStatus_Success) { returnCode = (status_t)kStatus_NOTIFIER_ErrorNotificationAfter; notifierHandle->errorCallbackIndex = currentStaticCallback; if (policy != kNOTIFIER_PolicyForcible) { break; } } } } } else { /* End of unsuccessful switch */ notifyBlock.notifyType = kNOTIFIER_NotifyRecover; while (currentStaticCallback-- > 0U) { callbackConfig = &(notifierHandle->callbacksTable[currentStaticCallback]); if (((uint32_t)callbackConfig->callbackType & (uint32_t)kNOTIFIER_CallbackBefore) != 0U) { (void)callbackConfig->callback(¬ifyBlock, callbackConfig->callbackData); } } } return returnCode; } /*! * brief This function returns the last failed notification callback. * * This function returns an index of the last callback that failed during the configuration switch while * the last NOTIFIER_SwitchConfig() was called. If the last NOTIFIER_SwitchConfig() call ended successfully * value equal to callbacks number is returned. The returned value represents an index in the array of * static call-backs. * * param notifierHandle Pointer to the notifier handle * return Callback Index of the last failed callback or value equal to callbacks count. */ uint8_t NOTIFIER_GetErrorCallbackIndex(notifier_handle_t *notifierHandle) { return notifierHandle->errorCallbackIndex; }