/****************************************************************************/
/*
 * MODULE              JN-AN-1162 JenNet-IP Smart Home
 *
 * DESCRIPTION         ColourControl MIB Implementation
 */
/****************************************************************************/
/*
 * This software is owned by NXP B.V. and/or its supplier and is protected
 * under applicable copyright laws. All rights are reserved. We grant You,
 * and any third parties, a license to use this software solely and
 * exclusively on NXP products [NXP Microcontrollers such as JN5168, JN5164].
 * You, and any third parties must reproduce the copyright and warranty notice
 * and any other legend of ownership on each copy or partial copy of the
 * software.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * Copyright NXP B.V. 2014. All rights reserved
 */
/****************************************************************************/

/****************************************************************************/
/***        Include files                                                 ***/
/****************************************************************************/
/* Standard includes */
#include <string.h>
#include <stdlib.h>
#include <math.h>
/* SDK includes */
#include <jendefs.h>
/* Hardware includes */
#include <AppHardwareApi.h>
#include <PeripheralRegs.h>
/* Stack includes */
#include <Api.h>
#include <AppApi.h>
#include <JIP.h>
#include <6LP.h>
#include <AccessFunctions.h>
/* JenOS includes */
#include <dbg.h>
#include <dbg_uart.h>
#include <os.h>
#include <pdm.h>
/* Application common includes */
#include "DeviceDefs.h"
#include "Node.h"
#include "Address.h"
#include "MibCommon.h"
#include "MibGroup.h"
#include "MibColour.h"
#include "MibNwkStatus.h"
/* Application device includes */
#include "DriverBulb.h"
#include "MibColourConfig.h"
#include "MibColourControl.h"
#include "MibBulbConfig.h"
#include "MibBulbControl.h"
#include "MibDeviceScene.h"
/* Application colour conversion includes */
#include "ColourConversion.h"

/****************************************************************************/
/***        Macro Definitions                                             ***/
/****************************************************************************/
#define MIB_COLOUR_CONTROL_HUE_DOWN_RANGE -1200
#define MIB_COLOUR_CONTROL_HUE_UP_RANGE    1200

#define MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN 16

/****************************************************************************/
/***        Type Definitions                                              ***/
/****************************************************************************/

/****************************************************************************/
/***        Local Function Prototypes                                     ***/
/****************************************************************************/
PRIVATE void   MibColourControl_vInitTransition(uint16 u16TransitionTime);
PRIVATE bool_t MibColourControl_bNewXYTarget(bool_t bNotifyChanged, uint16 u16TransitionTime);
PRIVATE bool_t MibColourControl_bNewHueChange(bool_t bNotifyChanged, uint16 u16TransitionTime);
PRIVATE bool_t MibColourControl_bNewHueSatTarget(bool_t bNotifyChanged, uint16 u16TransitionTime, bool_t bOptimise);
PRIVATE bool_t MibColourControl_bNewCctChange(bool_t bNotifyChanged, uint16 u16TransitionTime);
PRIVATE bool_t MibColourControl_bNewCctTarget(bool_t bNotifyChanged, uint16 u16TransitionTime);
PRIVATE bool_t MibColourControl_bModeTestHueSatNext(void);
PRIVATE bool_t MibColourControl_bModeTestCctNext(void);

/****************************************************************************/
/***        Exported Variables                                            ***/
/****************************************************************************/

/****************************************************************************/
/***        External Variables                                            ***/
/****************************************************************************/
/* MIB structures */
extern tsMibColourControl sMibColourControl;
extern thJIP_Mib 	      hMibColourControl;

extern tsMibColourConfig  sMibColourConfig;
extern tsMibBulbControl   sMibBulbControl;
extern tsMibBulbConfig    sMibBulbConfig;

/****************************************************************************/
/***        Local Variables                                               ***/
/****************************************************************************/

/****************************************************************************/
/***        Exported Functions                                            ***/
/****************************************************************************/
/****************************************************************************
 *
 * NAME: MibColourControl_vInit
 *
 * DESCRIPTION:
 * Initialises data
 *
 ****************************************************************************/
PUBLIC void MibColourControl_vInit(void)
{
	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_vInit() {%d}", acDebugIndent, sizeof(tsMibColourConfig));
	Node_vDebugIndent(DEBUG_MIB_COLOUR_CONTROL);

	/* Load ColourControl mib data */
   (void) PDM_eLoadRecord(&sMibColourControl.sDesc,
						  (uint16)(MIB_ID_COLOUR_CONTROL & 0xFFFF),
						  (void *) &sMibColourControl.sPerm,
						  sizeof(sMibColourControl.sPerm),
						  FALSE);
	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sPDM_eLoadRecord(MibColourControl) = %d", acDebugIndent, sMibColourControl.sDesc.eState);

	/* Building Group MIB ? */
	#if MK_BLD_MIB_GROUP
	{
		/* Was the group's MIB PDM not recovered ? */
		if (MibGroup_ePdmStateInit() != PDM_RECOVERY_STATE_RECOVERED)
		{
			in6_addr sAddr;

			/* Build "All Colour Bulbs" group address */
			Address_vBuildGroup(&sAddr, NULL, (uint16)(MIB_ID_COLOUR_CONTROL & 0xffff));
			/* Make a dummy call to get it in the group address array */
			bJIP_GroupCallback(E_JIP_GROUP_JOIN, &sAddr);
		}
	}
	#endif

	/* Didn't load record ? */
	if (PDM_RECOVERY_STATE_RECOVERED != sMibColourControl.sDesc.eState)
	{
		/* Initialise permament data */
		sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(F_TO_U16(CLD_COLOURCONTROL_WHITE_X), F_TO_U16(CLD_COLOURCONTROL_WHITE_Y));
	}

	/* Is an initialisation mode specified (values from flash retained otherwise) ? */
	if (sMibColourConfig.sPerm.u8InitMode < VAR_VAL_COLOUR_CONTROL_MODE_COUNT)
	{
		/* Apply initial mode and target level from config */
		sMibColourControl.sPerm.u8Mode      = sMibColourConfig.sPerm.u8InitMode;
		sMibColourControl.sPerm.u16SceneId  = 0;
		sMibColourControl.sPerm.u32XYTarget = sMibColourConfig.sPerm.u32InitXYTarget;
	}

	/* Initialising to DOWN or UP modes ? */
	if (sMibColourControl.sPerm.u8Mode       >= VAR_VAL_COLOUR_CONTROL_MODE_HUE_DOWN  &&
		sMibColourControl.sPerm.u8Mode       <= VAR_VAL_COLOUR_CONTROL_MODE_CCT_UP)
	{
		/* Not allowed initialise to stopped mode instead */
		sMibColourControl.sPerm.u8Mode       = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
	}

	/* Initialise colour transition structure */
	sMibColourControl.sColourTransition.psColourData                   = &sMibColourConfig.sColourData;
	strcpy(sMibColourControl.sColourTransition.sXYInterpolation.acName,  "XY");
	sMibColourControl.sColourTransition.sXYInterpolation.u8Dimensions  = XY_DIMS;
	sMibColourControl.sColourTransition.sXYInterpolation.u8Bits        = 16;
	sMibColourControl.sColourTransition.sXYInterpolation.bForced       = FALSE;
	strcpy(sMibColourControl.sColourTransition.sHSInterpolation.acName,  "HS");
	sMibColourControl.sColourTransition.sHSInterpolation.u8Dimensions  = HS_DIMS;
	sMibColourControl.sColourTransition.sHSInterpolation.u8Bits        = 16;
	sMibColourControl.sColourTransition.sHSInterpolation.bForced       = FALSE;
	strcpy(sMibColourControl.sColourTransition.sCctInterpolation.acName,  "CCT");
	sMibColourControl.sColourTransition.sCctInterpolation.u8Dimensions = CCT_DIMS;
	sMibColourControl.sColourTransition.sCctInterpolation.u8Bits       = 16;
	sMibColourControl.sColourTransition.sCctInterpolation.bForced      = FALSE;
	strcpy(sMibColourControl.sColourTransition.sRGBInterpolation.acName, "RGB");
	sMibColourControl.sColourTransition.sRGBInterpolation.u8Dimensions = RGB_DIMS;
	sMibColourControl.sColourTransition.sRGBInterpolation.u8Bits       = 8;
	sMibColourControl.sColourTransition.sRGBInterpolation.bForced      = TRUE;

	/* Does the configuration data indicate the bulb has failed ? */
	if (sMibColourConfig.sPerm.u8InitMode == VAR_VAL_COLOUR_CONTROL_MODE_FAILED)
	{
		/* Make sure control data indicates the same */
		sMibColourControl.sPerm.u8Mode       = VAR_VAL_COLOUR_CONTROL_MODE_FAILED;
		/* Is the bulb on - turn it off ? */
		if (DriverBulb_bOn()) DriverBulb_vOff();
	}
	/* Config data indicates the bulb is ok ? */
	else
	{
		/* Is the control data flagged up as failed ? */
		if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_FAILED)
		{
			/* Override with on mode */
			sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
			/* Colour is off - turn it on */
			if (DriverBulb_bOn() == FALSE) DriverBulb_vOn();
		}
	}

	/* Initialise the bulb driver */
	DriverBulb_vInit();

	/* Update component target values */
	sMibColourControl.sTemp.u16XTarget  = U32_TO_X(sMibColourControl.sPerm.u32XYTarget);
	sMibColourControl.sTemp.u16YTarget  = U32_TO_Y(sMibColourControl.sPerm.u32XYTarget);
	/* Update Current XY from Target XY */
	sMibColourControl.sTemp.u32XYCurrent = sMibColourControl.sPerm.u32XYTarget;
	sMibColourControl.sTemp.u16XCurrent  = sMibColourControl.sTemp.u16XTarget;
	sMibColourControl.sTemp.u16YCurrent  = sMibColourControl.sTemp.u16YTarget;

	/* Convert target XY to target HS */
	eCLD_ColourControl_xyY2HSV(
		&sMibColourConfig.sColourData,
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		(uint8) 255,
		&sMibColourControl.sTemp.u16HueTarget,
		&sMibColourControl.sTemp.u8SatTarget,
		&sMibColourControl.u8Discard);
	/* Build combined HS target */
	sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
	/* Update current HS from target HS */
	sMibColourControl.sTemp.u32HueSatCurrent = sMibColourControl.sTemp.u32HueSatTarget;
	sMibColourControl.sTemp.u16HueCurrent    = sMibColourControl.sTemp.u16HueTarget;
	sMibColourControl.sTemp.u8SatCurrent     = sMibColourControl.sTemp.u8SatTarget;

	/* Convert target XY to target CCT */
	vCLD_ColourControl_xyY2CCT(
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		255,
		&sMibColourControl.sTemp.u16CctTarget);
	/* Update current CCT from target CCT*/
	sMibColourControl.sTemp.u16CctCurrent = sMibColourControl.sTemp.u16CctTarget;

	/* Convert current xy to current RGB */
	eCLD_ColourControl_GetRGB(
		&sMibColourConfig.sColourData,
		sMibColourControl.sTemp.u16XCurrent,
		sMibColourControl.sTemp.u16YCurrent,
		&sMibColourControl.sTemp.u8RedCurrent,
		&sMibColourControl.sTemp.u8GreenCurrent,
		&sMibColourControl.sTemp.u8BlueCurrent);
	/* Need to notify for the Current RGB variables */
	sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
	sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
	sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Assume we are not on CCT line */
		sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
		/* Set colour in bulb driver */
		DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
							  sMibColourControl.sTemp.u8GreenCurrent,
							  sMibColourControl.sTemp.u8BlueCurrent);
	}
	#endif
	/* CCT driver ? */
	#ifdef MK_DRIVER_TYPE_TEMPERATURE
	{
		/* Assume we are on CCT line */
		sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_ON;
		/* Set colour in bulb driver */
		DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
	}
	#endif

    /* Debug */
	Node_vDebugOutdent(DEBUG_MIB_COLOUR_CONTROL);
}

/****************************************************************************
 *
 * NAME: MibColourControl_vRegister
 *
 * DESCRIPTION:
 * Registers MIB
 *
 ****************************************************************************/
PUBLIC void MibColourControl_vRegister(void)
{
    teJIP_Status eStatus;

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_vRegister()", acDebugIndent);
	Node_vDebugIndent(DEBUG_MIB_COLOUR_CONTROL);
	/* Register MIB */
	eStatus = eJIP_RegisterMib(hMibColourControl);
	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%seJIP_RegisterMib(ColourControl) = %d", acDebugIndent, eStatus);
    /* Make sure permament data is saved */
    sMibColourControl.bSaveRecord = TRUE;
	/* Debug */
	Node_vDebugOutdent(DEBUG_MIB_COLOUR_CONTROL);
}

/****************************************************************************
 *
 * NAME: MibColourControl_vSecond
 *
 * DESCRIPTION:
 * Called once per second
 *
 ****************************************************************************/
PUBLIC void MibColourControl_vSecond(void)
{
    /* Has the bulb failed at the driver level and we've not trapped it yet ? */
    if (DriverBulb_bFailed() &&
        sMibColourControl.sPerm.u8Mode != VAR_VAL_COLOUR_CONTROL_MODE_FAILED)
    {
    	/* Update mode to failed */
    	sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_FAILED;
    	/* Issue trap notification */
        sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_MODE);
        /* Save record */
        sMibColourControl.bSaveRecord = TRUE;

		/* Update init mode to failed */
		MibColourConfig_eSetInitMode(VAR_VAL_COLOUR_CONTROL_MODE_FAILED, &sMibColourConfig.sPerm.u8InitMode);
    }

    /* Need to save record ? */
    if (sMibColourControl.bSaveRecord)
    {
        /* Clear flag */
        sMibColourControl.bSaveRecord = FALSE;
        /* Make sure permament data is saved */
        PDM_vSaveRecord(&sMibColourControl.sDesc);
        /* Debug */
		DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sPDM_vSaveRecord(MibColourControl) = %d", acDebugIndent, sMibColourControl.sDesc.eState);
    }
}

/****************************************************************************
 *
 * NAME: MibColourControl_vTick
 *
 * DESCRIPTION:
 * Timer function
 *
 ****************************************************************************/
PUBLIC void MibColourControl_vTick(void)
{
	/* In a transition mode ? */
	switch (sMibColourControl.sColourTransition.u8Mode)
	{
		/* XY transition running ? */
		case COLOUR_TRANSITION_MODE_XY:
		{
			/* Calculate next transition step */
			ColourTransition_bXYNext(&sMibColourControl.sColourTransition);
			/* Note target for this step as current XY values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16XCurrent = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[X_DIM];
			sMibColourControl.sTemp.u16YCurrent = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[Y_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
			/* Note target for this step as current HS values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16HueCurrent = (uint16) (sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[H_DIM] % 3600);
			sMibColourControl.sTemp.u8SatCurrent  = (uint8)   sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[S_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
			/* Note target for this step as current CCT value (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16CctCurrent = (uint16) (sMibColourControl.sColourTransition.sCctInterpolation.au32TargetStep[CCT_DIM]);
			/* Note target for this step as current RGB values (this is what we need to move to) */
			sMibColourControl.sTemp.u8RedCurrent   = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[R_DIM];
			sMibColourControl.sTemp.u8GreenCurrent = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[G_DIM];
			sMibColourControl.sTemp.u8BlueCurrent  = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[B_DIM];

			/* RGB driver ? */
			#ifdef MK_DRIVER_TYPE_COLOUR
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
									  sMibColourControl.sTemp.u8GreenCurrent,
									  sMibColourControl.sTemp.u8BlueCurrent);
			}
			#endif
			/* CCT driver ? */
			#ifdef MK_DRIVER_TYPE_TEMPERATURE
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
			}
			#endif

			/* Completed transition ? */
			if (sMibColourControl.sColourTransition.u8Mode == COLOUR_TRANSITION_MODE_NONE)
			{
				/* Were we transitioning to CCT space ? */
				if (sMibColourControl.u8CctMode == MIB_COLOUR_CONTROL_CCT_MODE_TRANS)
				{
					/* We should be on CCT line */
					sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_ON;
				}
				/* Not transitioning to CCT space ? */
				else
				{
					/* We are not on CCT line */
					sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
				}

				/* Stopped mode ? */
				if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_STOP)
				{
					/* Need to notify for the changed current variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
				}

				/* CCT down mode ? */
				else if(sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_CCT_DOWN)
				{
					/* Is the current sat above the minimum */
					if (sMibColourControl.sTemp.u16CctCurrent > CLD_CCT_MIRED_MIN)
					{
						uint32 u32TransitionTime;

						/* Scale configured transition time for full range down to remaining range */
						u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (sMibColourControl.sTemp.u16CctCurrent)) / (uint32) 500;
						/* Enforce minimum transition time */
						if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
						/* Set new hue target to minimum */
						sMibColourControl.sTemp.u16CctTarget = CLD_CCT_MIRED_MIN;
						/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
						if (FALSE == MibColourControl_bNewCctTarget(FALSE, (uint16) u32TransitionTime))
						{
							/* Revert back to stop mode */
							sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
						}
					}
				}

				/* CCT up mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_CCT_UP)
				{
					/* Is the current sat below the maximum */
					if (sMibColourControl.sTemp.u8SatCurrent < CLD_CCT_MIRED_MAX)
					{
						uint32 u32TransitionTime;

						/* Scale configured transition time for full range down to remaining range */
						u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (CLD_CCT_MIRED_MAX - sMibColourControl.sTemp.u16CctCurrent)) / (uint32) 500;
						/* Enforce minimum transition time */
						if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
						/* Set new sat target to maximum */
						sMibColourControl.sTemp.u16CctTarget = CLD_CCT_MIRED_MAX;
						/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
						if (FALSE == MibColourControl_bNewCctTarget(FALSE, (uint16) u32TransitionTime))
						{
							/* Revert back to stop mode */
							sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
						}
					}
				}

				/* Test mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_TEST_CCT)
				{
					/* Run the next iteration ? */
					if (FALSE == MibColourControl_bModeTestCctNext())
					{
						/* Revert back to stop mode */
						sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					}
				}
			}
		}
		break;

		/* HS transition running ? */
		case COLOUR_TRANSITION_MODE_HS:
		{
			/* Calculate next transition step */
			ColourTransition_bHSNext(&sMibColourControl.sColourTransition);
			/* Note target for this step as current HS values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16HueCurrent = (uint16) (sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[H_DIM] % 3600);
			sMibColourControl.sTemp.u8SatCurrent  = (uint8)   sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[S_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
			/* Note target for this step as current XY values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16XCurrent     = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[X_DIM];
			sMibColourControl.sTemp.u16YCurrent     = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[Y_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
			/* Note target for this step as current CCT value (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16CctCurrent = (uint16) (sMibColourControl.sColourTransition.sCctInterpolation.au32TargetStep[CCT_DIM]);
			/* Note target for this step as current RGB values (this is what we need to move to) */
			sMibColourControl.sTemp.u8RedCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[R_DIM];
			sMibColourControl.sTemp.u8GreenCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[G_DIM];
			sMibColourControl.sTemp.u8BlueCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[B_DIM];

			/* RGB driver ? */
			#ifdef MK_DRIVER_TYPE_COLOUR
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
									  sMibColourControl.sTemp.u8GreenCurrent,
									  sMibColourControl.sTemp.u8BlueCurrent);
			}
			#endif
			/* CCT driver ? */
			#ifdef MK_DRIVER_TYPE_TEMPERATURE
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
			}
			#endif

			/* Completed transition ? */
			if (sMibColourControl.sColourTransition.u8Mode == COLOUR_TRANSITION_MODE_NONE)
			{
		        /* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_vTick() HS_END u8Mode = %d", acDebugIndent, sMibColourControl.sPerm.u8Mode);
				/* Were we transitioning to CCT space ? */
				if (sMibColourControl.u8CctMode == MIB_COLOUR_CONTROL_CCT_MODE_TRANS)
				{
					/* We should be on CCT line */
					sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_ON;
				}
				/* Not transitioning to CCT space ? */
				else
				{
					/* We are not on CCT line */
					sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
				}

				/* Stopped mode ? */
				if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_STOP)
				{
					/* Need to notify for the changed current variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
				}
				/* Loop down mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_LOOP_DOWN)
				{
					/* Set new hue change */
					sMibColourControl.sTemp.i16HueChange = MIB_COLOUR_CONTROL_HUE_DOWN_RANGE;
					/* Handle the new hue target (no notifications, configured transition) ? */
					if (FALSE == MibColourControl_bNewHueChange(FALSE, sMibColourConfig.sPerm.u16TransitionTime))
					{
						/* Revert back to stop mode */
						sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					}
				}
				/* Loop up mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_LOOP_UP)
				{
					/* Set new hue change */
					sMibColourControl.sTemp.i16HueChange = MIB_COLOUR_CONTROL_HUE_UP_RANGE;
					/* Handle the new hue target (no notifications, configured transition) ? */
					if (FALSE == MibColourControl_bNewHueChange(FALSE, sMibColourConfig.sPerm.u16TransitionTime))
					{
				        /* Debug */
						DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, " > STOP", acDebugIndent);
						/* Revert back to stop mode */
						sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					}
				}
				/* Hue down mode ? */
				/* Hue up   mode ? */
				/* Sat down mode ? */
				/* Sat up   mode ? */
				else if (sMibColourControl.sPerm.u8Mode >= VAR_VAL_COLOUR_CONTROL_MODE_HUE_DOWN &&
						 sMibColourControl.sPerm.u8Mode <= VAR_VAL_COLOUR_CONTROL_MODE_SAT_UP)
				{
					/* Revert back to stop mode */
					sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					/* Need to notify for the changed current variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
					/* Note final target values from current values */
					sMibColourControl.sTemp.u16HueTarget    = sMibColourControl.sTemp.u16HueCurrent;
					sMibColourControl.sTemp.u8SatTarget     = sMibColourControl.sTemp.u8SatCurrent;
					sMibColourControl.sTemp.u32HueSatTarget = sMibColourControl.sTemp.u32HueSatCurrent;
					sMibColourControl.sTemp.u16XTarget      = sMibColourControl.sTemp.u16XCurrent;
					sMibColourControl.sTemp.u16YTarget      = sMibColourControl.sTemp.u16YCurrent;
					sMibColourControl.sPerm.u32XYTarget     = sMibColourControl.sTemp.u32XYCurrent;
					sMibColourControl.sTemp.u16CctTarget    = sMibColourControl.sTemp.u16CctCurrent;
					/* Make sure permament data is saved */
					sMibColourControl.bSaveRecord = TRUE;
					/* Need to notify for the changed target variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
				}
				/* Test mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_TEST_HUE_SAT)
				{
					/* Run the next iteration ? */
					if (FALSE == MibColourControl_bModeTestHueSatNext())
					{
						/* Revert back to stop mode */
						sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					}
				}
			}
		}
		break;

		/* CCT transition running ? */
		case COLOUR_TRANSITION_MODE_CCT:
		{
			/* Calculate next transition step */
			ColourTransition_bCctNext(&sMibColourControl.sColourTransition);
			/* Note target for this step as current CCT value (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16CctCurrent = (uint16) (sMibColourControl.sColourTransition.sCctInterpolation.au32TargetStep[CCT_DIM]);
			/* Note target for this step as current XY values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16XCurrent     = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[X_DIM];
			sMibColourControl.sTemp.u16YCurrent     = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[Y_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
			/* Note target for this step as current HS values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16HueCurrent = (uint16) (sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[H_DIM] % 3600);
			sMibColourControl.sTemp.u8SatCurrent  = (uint8)   sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[S_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
			/* Note target for this step as current RGB values (this is what we need to move to) */
			sMibColourControl.sTemp.u8RedCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[R_DIM];
			sMibColourControl.sTemp.u8GreenCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[G_DIM];
			sMibColourControl.sTemp.u8BlueCurrent    = (uint8)  sMibColourControl.sColourTransition.sRGBInterpolation.au32TargetStep[B_DIM];

			/* RGB driver ? */
			#ifdef MK_DRIVER_TYPE_COLOUR
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
									  sMibColourControl.sTemp.u8GreenCurrent,
									  sMibColourControl.sTemp.u8BlueCurrent);
			}
			#endif
			/* CCT driver ? */
			#ifdef MK_DRIVER_TYPE_TEMPERATURE
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
			}
			#endif

			/* Completed transition ? */
			if (sMibColourControl.sColourTransition.u8Mode == COLOUR_TRANSITION_MODE_NONE)
			{
				/* We should be on CCT line */
				sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_ON;

				/* Stopped mode ? */
				if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_STOP)
				{
					/* Need to notify for the changed current variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
				}
				/* Cct down mode ? */
				/* Cct up   mode ? */
				else if (sMibColourControl.sPerm.u8Mode >= VAR_VAL_COLOUR_CONTROL_MODE_CCT_DOWN &&
						 sMibColourControl.sPerm.u8Mode <= VAR_VAL_COLOUR_CONTROL_MODE_CCT_UP)
				{
					/* Revert back to stop mode */
					sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					/* Need to notify for the changed current variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
					/* Note final target values from current values */
					sMibColourControl.sTemp.u16HueTarget    = sMibColourControl.sTemp.u16HueCurrent;
					sMibColourControl.sTemp.u8SatTarget     = sMibColourControl.sTemp.u8SatCurrent;
					sMibColourControl.sTemp.u32HueSatTarget = sMibColourControl.sTemp.u32HueSatCurrent;
					sMibColourControl.sTemp.u16XTarget      = sMibColourControl.sTemp.u16XCurrent;
					sMibColourControl.sTemp.u16YTarget      = sMibColourControl.sTemp.u16YCurrent;
					sMibColourControl.sPerm.u32XYTarget     = sMibColourControl.sTemp.u32XYCurrent;
					sMibColourControl.sTemp.u16CctTarget    = sMibColourControl.sTemp.u16CctCurrent;
					/* Make sure permament data is saved */
					sMibColourControl.bSaveRecord = TRUE;
					/* Need to notify for the changed target variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
				}
				/* Test mode ? */
				else if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_TEST_CCT)
				{
					/* Run the next iteration ? */
					if (FALSE == MibColourControl_bModeTestCctNext())
					{
						/* Revert back to stop mode */
						sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
					}
				}
			}
		}
		break;

		/* Others ? */
		default:
		{
			/* Do nothing */
			;
		}
		break;
	}

	/* Are there any ColourControl variable notifications pending ? */
	if ((sMibColourControl.u32NotifyChanged & VAR_MASK_COLOUR_CONTROL) != 0)
	{
		/* Use common function to output notifications */
		Node_vJipNotifyChanged(hMibColourControl, &sMibColourControl.u32NotifyChanged, VAR_MASK_COLOUR_CONTROL, VAR_COUNT_COLOUR_CONTROL);
	}
}

/****************************************************************************
 *
 * NAME: MibColourControl_vStackEvent
 *
 * DESCRIPTION:
 * Called when stack events take place
 *
 ****************************************************************************/
PUBLIC void MibColourControl_vStackEvent(te6LP_StackEvent eEvent)
{
	/* Which event ? */
	switch (eEvent)
	{
		/* Network up ? */
		case E_STACK_JOINED:
		case E_STACK_STARTED:
		{
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_vStackEvent(JOINED)", acDebugIndent);
		}
		break;

		case E_STACK_RESET:
		{
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_vStackEvent(RESET)", acDebugIndent);
		}
		break;

		default:
		{
		}
		break;
	}
}

/****************************************************************************
 *
 * NAME: MibColourControl_bModeStop
 *
 * DESCRIPTION:
 * Mode set data callback
 *
 ****************************************************************************/
PUBLIC bool_t MibColourControl_bModeStop(bool_t bInternal)
{
    bool_t bReturn = TRUE;

	/* Not stopped already ? */
	if (sMibColourControl.sPerm.u8Mode != VAR_VAL_COLOUR_CONTROL_MODE_STOP)
	{
		/* Stop any running transition ? */
		(void) ColourTransition_bEnd(&sMibColourControl.sColourTransition);
		/* Are we leaving a colour altering mode (need to update variables with current values) ? */
		if (  (sMibColourControl.sPerm.u8Mode >= VAR_VAL_COLOUR_CONTROL_MODE_LOOP_DOWN
		   &&  sMibColourControl.sPerm.u8Mode <= VAR_VAL_COLOUR_CONTROL_MODE_LOOP_UP  )
		   || (sMibColourControl.sPerm.u8Mode >= VAR_VAL_COLOUR_CONTROL_MODE_HUE_DOWN
		   &&  sMibColourControl.sPerm.u8Mode <= VAR_VAL_COLOUR_CONTROL_MODE_CCT_UP   ))
		{
			/* Note target for this step as current XY values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16XCurrent = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[X_DIM];
			sMibColourControl.sTemp.u16YCurrent = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[Y_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
			/* Note target for this step as current HS values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16HueCurrent = (uint16) (sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[H_DIM] % 3600);
			sMibColourControl.sTemp.u8SatCurrent  = (uint8)   sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[S_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
			/* Note target for this step as target CCT value (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16CctCurrent = (uint16) (sMibColourControl.sColourTransition.sCctInterpolation.au32TargetStep[CCT_DIM]);
			/* Need to notify for the changed current variables */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);
			/* Note target for this step as target XY values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16XTarget = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[X_DIM];
			sMibColourControl.sTemp.u16YTarget = (uint16) sMibColourControl.sColourTransition.sXYInterpolation.au32TargetStep[Y_DIM];
			/* Update combined target value */
			sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);
			/* Note target for this step as target HS values (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16HueTarget = (uint16) (sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[H_DIM] % 3600);
			sMibColourControl.sTemp.u8SatTarget  = (uint8)   sMibColourControl.sColourTransition.sHSInterpolation.au32TargetStep[S_DIM];
			/* Update combined current value */
			sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
			/* Note target for this step as target CCT value (though it will be lagging behind this) */
			sMibColourControl.sTemp.u16CctTarget = (uint16) (sMibColourControl.sColourTransition.sCctInterpolation.au32TargetStep[CCT_DIM]);
			/* Need to notify for the changed target variables */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
			/* WOW! potentially a lot of notifications here */
		}
		/* In a test mode (need to restore variables to what they were) ? */
		else if (sMibColourControl.sPerm.u8Mode >= VAR_VAL_COLOUR_CONTROL_MODE_TEST_HUE_SAT &&
				 sMibColourControl.sPerm.u8Mode <= VAR_VAL_COLOUR_CONTROL_MODE_TEST_CCT)
		{
			/* Restore ColourControl settings */
			sMibColourControl.sPerm.u32XYTarget = sMibColourControl.u32TestMode_XYTarget;
			/* Update component target values */
			sMibColourControl.sTemp.u16XTarget  = U32_TO_X(sMibColourControl.sPerm.u32XYTarget);
			sMibColourControl.sTemp.u16YTarget  = U32_TO_Y(sMibColourControl.sPerm.u32XYTarget);
			/* Handle the new XY target (don't notify any other changed variables, short transition) ? */
			(void) MibColourControl_bNewXYTarget(FALSE, 64);
			/* Restore BulbControl and BulbConfig settings */
			sMibBulbControl.sPerm.u8LumTarget = sMibColourControl.u8TestMode_BulbControlLumTarget;
			sMibBulbConfig.sPerm.u8LumRate    = sMibColourControl.u8TestMode_BulbConfigLumRate;
		}
		/* Was this set internally (rather than remotely) ? */
		if (bInternal)
		{
			/* Set new value */
			sMibColourControl.sPerm.u8Mode = VAR_VAL_COLOUR_CONTROL_MODE_STOP;
			/* Flag a trap notification */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_MODE);
		}
	}

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetMode
 *
 * DESCRIPTION:
 * Mode set data callback
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetMode(uint8 u8Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_BAD_VALUE;
    bool_t        bSave   = FALSE;

    /* Debug */
    DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetMode(%d)", acDebugIndent, u8Val);
    Node_vDebugIndent(DEBUG_MIB_COLOUR_CONTROL);

    /* Has the bulb failed ? */
    if (sMibColourControl.sPerm.u8Mode == VAR_VAL_COLOUR_CONTROL_MODE_FAILED)
    {
   		/* Return this option is currently disabled */
   		eReturn = E_JIP_ERROR_DISABLED;
    }
    /* Other valid ? */
    else if (u8Val < VAR_VAL_COLOUR_CONTROL_MODE_COUNT)
    {
        /* Mode change was made ? */
        if (sMibColourControl.sPerm.u8Mode != u8Val)
        {
			bool_t bOk = FALSE;

            /* Which new mode ? */
            switch (u8Val)
            {
				/* Stop ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_STOP:
				{
					/* Call helper function (not internally set) */
					bOk = MibColourControl_bModeStop(FALSE);
				}
				break;

				/* Loop down mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_LOOP_DOWN:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Set new hue change */
						sMibColourControl.sTemp.i16HueChange = MIB_COLOUR_CONTROL_HUE_DOWN_RANGE;
						/* Handle the new hue target (no notifications, configured transition) ? */
						bOk = MibColourControl_bNewHueChange(FALSE, sMibColourConfig.sPerm.u16TransitionTime);
					}
					#endif
				}
				break;

				/* Loop up mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_LOOP_UP:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Set new hue change */
						sMibColourControl.sTemp.i16HueChange = MIB_COLOUR_CONTROL_HUE_UP_RANGE;
						/* Handle the new hue target (no notifications, configured transition) ? */
						bOk = MibColourControl_bNewHueChange(FALSE, sMibColourConfig.sPerm.u16TransitionTime);
					}
					#endif
				}
				break;

				/* Hue down mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_HUE_DOWN:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Is the current sat above the minimum */
						if (sMibColourControl.sTemp.u16HueCurrent > 0)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) sMibColourControl.sTemp.u16HueCurrent) / (uint32) 1200;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new hue target to minimum */
							sMibColourControl.sTemp.u16HueTarget = 0;
							/* Build combined variable value */
							sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
							/* Handle new HueSatTarget value (don't notify and using calculated transition time, unoptimised) */
							bOk = MibColourControl_bNewHueSatTarget(FALSE, (uint16) u32TransitionTime, FALSE);
						}
					}
					#endif
				}
				break;

				/* Hue up mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_HUE_UP:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Is the current sat below the maximum */
						if (sMibColourControl.sTemp.u8SatCurrent < 0x3599)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (3599 - sMibColourControl.sTemp.u16HueCurrent)) / (uint32) 1200;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new sat target to maximum */
							sMibColourControl.sTemp.u16HueTarget = 3599;
							/* Build combined variable value */
							sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
							/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
							bOk = MibColourControl_bNewHueSatTarget(FALSE, (uint16) u32TransitionTime, FALSE);
						}
					}
					#endif
				}
				break;

				/* Sat down mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_SAT_DOWN:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Is the current sat above the minimum */
						if (sMibColourControl.sTemp.u8SatCurrent > 0)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) sMibColourControl.sTemp.u8SatCurrent) / (uint32) 255;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new sat target to minimum */
							sMibColourControl.sTemp.u8SatTarget = 0;
							/* Build combined variable value */
							sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
							/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
							bOk = MibColourControl_bNewHueSatTarget(FALSE, (uint16) u32TransitionTime, FALSE);
						}
					}
					#endif
				}
				break;

				/* Sat up mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_SAT_UP:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Is the current sat below the maximum */
						if (sMibColourControl.sTemp.u8SatCurrent < 255)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (255 - sMibColourControl.sTemp.u8SatCurrent)) / (uint32) 255;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new sat target to maximum */
							sMibColourControl.sTemp.u8SatTarget = 255;
							/* Build combined variable value */
							sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
							/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
							bOk = MibColourControl_bNewHueSatTarget(FALSE, (uint16) u32TransitionTime, FALSE);
						}
					}
					#endif
				}
				break;

				/* CCT down mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_CCT_DOWN:
				{
					/* Are we not already on the CCT line ? */
					if (sMibColourControl.u8CctMode != MIB_COLOUR_CONTROL_CCT_MODE_ON)
					{
						/* Quickly transition onto CCT line ? */
						bOk = MibColourControl_bNewCctTarget(FALSE, 64);
					}
					else
					{
						/* Is the current sat above the minimum */
						if (sMibColourControl.sTemp.u16CctCurrent > CLD_CCT_MIRED_MIN)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (sMibColourControl.sTemp.u16CctCurrent)) / (uint32) 500;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new hue target to minimum */
							sMibColourControl.sTemp.u16CctTarget = CLD_CCT_MIRED_MIN;
							/* Handle new HueSatTarget value (don't notify and using calculated transition time, unoptimised) */
							bOk = MibColourControl_bNewCctTarget(FALSE, (uint16) u32TransitionTime);
						}
					}
				}
				break;

				/* CCT up mode ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_CCT_UP:
				{
					/* Are we not already on the CCT line ? */
					if (sMibColourControl.u8CctMode != MIB_COLOUR_CONTROL_CCT_MODE_ON)
					{
						/* Quickly transition onto CCT line ? */
						bOk = MibColourControl_bNewCctTarget(FALSE, 64);
					}
					else
					{
						/* Is the current sat below the maximum */
						if (sMibColourControl.sTemp.u8SatCurrent < CLD_CCT_MIRED_MAX)
						{
							uint32 u32TransitionTime;

							/* Scale configured transition time for full range down to remaining range */
							u32TransitionTime = ((uint32) sMibColourConfig.sPerm.u16TransitionTime * (uint32) (CLD_CCT_MIRED_MAX - sMibColourControl.sTemp.u16CctCurrent)) / (uint32) 500;
							/* Enforce minimum transition time */
							if (u32TransitionTime < MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN) u32TransitionTime = MIB_COLOUR_CONTROL_TRANSITION_TIME_MIN;
							/* Set new sat target to maximum */
							sMibColourControl.sTemp.u16CctTarget = CLD_CCT_MIRED_MAX;
							/* Handle new HueSatTarget value (don't notify and using calculated transition time) */
							bOk = MibColourControl_bNewCctTarget(FALSE, (uint16) u32TransitionTime);
						}
					}
				}
				break;

				/* Test ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_TEST_HUE_SAT:
				{
					/* RGB driver ? */
					#ifdef MK_DRIVER_TYPE_COLOUR
					{
						/* Save ColourControl settings */
						sMibColourControl.u32TestMode_XYTarget = sMibColourControl.sPerm.u32XYTarget;
						/* Save BulbControl and BulbConfig settings */
						sMibColourControl.u8TestMode_BulbControlLumTarget = sMibBulbControl.sPerm.u8LumTarget;
						sMibColourControl.u8TestMode_BulbConfigLumRate    = sMibBulbConfig.sPerm.u8LumRate;
						/* Do next step */
						bOk = MibColourControl_bModeTestHueSatNext();
					}
					#endif
				}
				break;

				/* Test ? */
				case VAR_VAL_COLOUR_CONTROL_MODE_TEST_CCT:
				{
					/* Save ColourControl settings */
					sMibColourControl.u32TestMode_XYTarget = sMibColourControl.sPerm.u32XYTarget;
					/* Save BulbControl and BulbConfig settings */
					sMibColourControl.u8TestMode_BulbControlLumTarget = sMibBulbControl.sPerm.u8LumTarget;
					sMibColourControl.u8TestMode_BulbConfigLumRate    = sMibBulbConfig.sPerm.u8LumRate;
					/* Set a hot CCT target */
					sMibColourControl.sTemp.u16CctTarget = 750;
					/* Handle the new CCT target (don't notify any other changed variables, short transition) ? */
					bOk = MibColourControl_bNewCctTarget(FALSE, 64);
				}
				break;
			}

			/* Everything ok ? */
			if (bOk)
			{
	            /* Call standard function */
    	        eReturn = eSetUint8(u8Val, pvCbData);
			    /* Debug */
    			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%ssMibColourControl.sPerm.u8Mode = %d", acDebugIndent, sMibColourControl.sPerm.u8Mode);
        	    /* Make sure permament data is saved */
            	sMibColourControl.bSaveRecord = bSave;
			}
        }
    }

    /* Debug */
    Node_vDebugOutdent(DEBUG_MIB_COLOUR_CONTROL);
    DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, " = %d {%d}", eReturn, sMibColourControl.sPerm.u8Mode);

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetSceneId
 *
 * DESCRIPTION:
 * Set SceneId callback
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetSceneId(uint16 u16Val, void *pvCbData)
{
    teJIP_Status eReturn;

    /* Debug */
    DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetSceneId(%d)", acDebugIndent, u16Val);
    Node_vDebugIndent(DEBUG_MIB_COLOUR_CONTROL);

    /* Try to apply scene ? */
    eReturn = MibDeviceScene_eActivateScene(u16Val);
    /* Scene applied ? */
    if (eReturn == E_JIP_OK)
    {
    	/* Call standard function */
        eReturn = eSetUint16(u16Val, pvCbData);

		/* Set BulbControl SceneId */
		sMibBulbControl.sPerm.u16SceneId = u16Val;
		/* Notify for BulbControl SceneId */
		sMibBulbControl.u32NotifyChanged |= (1 << VAR_IX_BULB_CONTROL_SCENE_ID);
		/* Notify for DeviceControl SceneId */
		sMibBulbControl.u32DeviceControlNotifyChanged |= (1 << VAR_IX_BULB_CONTROL_SCENE_ID);
	}

    /* Debug */
    Node_vDebugOutdent(DEBUG_MIB_COLOUR_CONTROL);
    DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, " = %d", acDebugIndent, eReturn);

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetXYTarget
 *
 * DESCRIPTION:
 * Sets luminance target
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetXYTarget(uint32 u32Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sPerm.u32XYTarget != u32Val)
			{
				/* Call standard function */
				eReturn = eSetUint32(u32Val, pvCbData);
				/* Update component target values */
				sMibColourControl.sTemp.u16XTarget  = U32_TO_X(sMibColourControl.sPerm.u32XYTarget);
				sMibColourControl.sTemp.u16YTarget  = U32_TO_Y(sMibColourControl.sPerm.u32XYTarget);
				/* Make sure permanent data is saved */
				sMibColourControl.bSaveRecord = TRUE;
				/* Need to notify for the component variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetXYTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sPerm.u32XYTarget);

				/* Handle new XYTarget value (notifying and using configured transition time */
				(void) MibColourControl_bNewXYTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetXTarget
 *
 * DESCRIPTION:
 * Sets X colour coordinate target
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetXTarget(uint16 u16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u16XTarget != u16Val)
			{
				/* Call standard function */
				eReturn = eSetUint16(u16Val, pvCbData);
				/* Update combined target value */
				sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);
				/* Make sure permanent data is saved */
				sMibColourControl.bSaveRecord = TRUE;
				/* Need to notify for the combined variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetXTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u16XTarget);

				/* Handle new XYTarget value (notifying and using configured transition time */
				(void) MibColourControl_bNewXYTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetYTarget
 *
 * DESCRIPTION:
 * Sets Y colour coordinate target
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetYTarget(uint16 u16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u16YTarget != u16Val)
			{
				/* Call standard function */
				eReturn = eSetUint16(u16Val, pvCbData);
				/* Update combined target value */
				sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);
				/* Make sure permanent data is saved */
				sMibColourControl.bSaveRecord = TRUE;
				/* Need to notify for the component variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetYTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u16YTarget);

				/* Handle new XYTarget value (notifying and using configured transition time */
				(void) MibColourControl_bNewXYTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetXYCurrent
 *
 * DESCRIPTION:
 * Sets luminance target
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetXYCurrent(uint32 u32Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u32XYCurrent != u32Val)
			{
				/* Call standard function */
				eReturn = eSetUint32(u32Val, pvCbData);
				/* Update component current values */
				sMibColourControl.sTemp.u16XCurrent  = U32_TO_X(sMibColourControl.sTemp.u32XYCurrent);
				sMibColourControl.sTemp.u16YCurrent  = U32_TO_Y(sMibColourControl.sTemp.u32XYCurrent);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetXYCurrent(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u32XYCurrent);

				/* Target XY is different to Current XY ? */
				if (sMibColourControl.sPerm.u32XYTarget != sMibColourControl.sTemp.u32XYCurrent)
				{
					/* Update Target XY */
					sMibColourControl.sPerm.u32XYTarget = sMibColourControl.sTemp.u32XYCurrent;
					/* Update component target values */
					sMibColourControl.sTemp.u16XTarget  = sMibColourControl.sTemp.u16XCurrent;
					sMibColourControl.sTemp.u16YTarget  = sMibColourControl.sTemp.u16YCurrent;
					/* Make sure permanent data is saved */
					sMibColourControl.bSaveRecord = TRUE;
					/* Need to notify for the Target XY variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
				}

				/* Convert current xy to current HS */
				eCLD_ColourControl_xyY2HSV(
					&sMibColourConfig.sColourData,
					sMibColourControl.sTemp.u16XCurrent,
					sMibColourControl.sTemp.u16YCurrent,
					(uint8) 255,
					&sMibColourControl.sTemp.u16HueCurrent,
					&sMibColourControl.sTemp.u8SatCurrent,
					&sMibColourControl.u8Discard);
				/* Build combined variable value */
				sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
				/* Need to notify for the Current Hue Sat variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);

				/* Target HS is different to Current HS ? */
				if (sMibColourControl.sTemp.u32HueSatTarget != sMibColourControl.sTemp.u32HueSatCurrent)
				{
					/* Update Target HS */
					sMibColourControl.sTemp.u32HueSatTarget = sMibColourControl.sTemp.u32HueSatCurrent;
					sMibColourControl.sTemp.u16HueTarget    = sMibColourControl.sTemp.u16HueCurrent;
					sMibColourControl.sTemp.u8SatTarget     = sMibColourControl.sTemp.u8SatCurrent;
					/* Need to notify for the Target HS variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
				}

				/* Convert current xy to current CCT */
				vCLD_ColourControl_xyY2CCT(
					sMibColourControl.sTemp.u16XCurrent,
					sMibColourControl.sTemp.u16YCurrent,
					255,
					&sMibColourControl.sTemp.u16CctCurrent);
				/* Need to notify for the Current CCT variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);

				/* Target CCT is different to Current CCT ? */
				if (sMibColourControl.sTemp.u16CctCurrent != sMibColourControl.sTemp.u16CctCurrent)
				{
					/* Update Target CCT */
					sMibColourControl.sTemp.u16CctTarget    = sMibColourControl.sTemp.u16CctCurrent;
					/* Need to notify for the Target HS variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
				}

				/* Convert current xy to current RGB */
				eCLD_ColourControl_GetRGB(&sMibColourConfig.sColourData,
										  sMibColourControl.sTemp.u16XCurrent,
										  sMibColourControl.sTemp.u16YCurrent,
										  &sMibColourControl.sTemp.u8RedCurrent,
										  &sMibColourControl.sTemp.u8GreenCurrent,
										  &sMibColourControl.sTemp.u8BlueCurrent);
				/* Need to notify for the Current RGB variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);

				/* Moving off CCT line */
				sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
				/* RGB driver ? */
				#ifdef MK_DRIVER_TYPE_COLOUR
				{
					/* Set colour in bulb driver */
					DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
										  sMibColourControl.sTemp.u8GreenCurrent,
										  sMibColourControl.sTemp.u8BlueCurrent);
				}
				#endif
				/* CCT driver ? */
				#ifdef MK_DRIVER_TYPE_TEMPERATURE
				{
					/* Set colour in bulb driver */
					DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
				}
				#endif
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetHueSatTarget
 *
 * DESCRIPTION:
 * Sets hue and saturation target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetHueSatTarget(uint32 u32Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u32HueSatTarget != u32Val)
			{
				/* Call standard function */
				eReturn = eSetUint32(u32Val, pvCbData);
				/* Update component variables (validating hue) */
				sMibColourControl.sTemp.u16HueTarget = U32_TO_HUE(sMibColourControl.sTemp.u32HueSatTarget) % 3600;
				sMibColourControl.sTemp.u8SatTarget  = U32_TO_SAT(sMibColourControl.sTemp.u32HueSatTarget);
				/* Rebuild combined variable as the hue component may have been changed */
				sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
				/* Need to notify for the component variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetHueSatTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u32HueSatTarget);

				/* Handle new HueSatTarget value (notifying and using configured transition time, optimised) */
				(void) MibColourControl_bNewHueSatTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime, TRUE);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetHueTarget
 *
 * DESCRIPTION:
 * Sets hue target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetHueTarget(uint16 u16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u16HueTarget != u16Val)
			{
				/* Call standard function */
				eReturn = eSetUint16(u16Val, pvCbData);
				/* Ensure new value is in correct range */
				sMibColourControl.sTemp.u16HueTarget %= 3600;
				/* Build combined variable */
				sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
				/* Need to notify for the combined variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetHueTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u16HueTarget);

				/* Handle new HueSatTarget value (notifying and using configured transition time */
				(void) MibColourControl_bNewHueSatTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime, TRUE);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetHueChange
 *
 * DESCRIPTION:
 * Sets hue target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetHueChange(int16 i16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Call standard function */
			eReturn = eSetUint16(i16Val, pvCbData);
			/* Ensure new value is in correct range */
			sMibColourControl.sTemp.i16HueChange %= 3600;
			/* Debug */
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetHueChange(%d)",
				acDebugIndent,
				sMibColourControl.sTemp.i16HueChange);
			/* Handle the new value (allowing notifications to be sent for other variables and the configured transition time) */
			MibColourControl_bNewHueChange(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetSatTarget
 *
 * DESCRIPTION:
 * Sets hue target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetSatTarget(uint8 u8Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u8SatTarget != u8Val)
			{
				/* Call standard function */
				eReturn = eSetUint8(u8Val, pvCbData);
				/* Build combined variable value */
				sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
				/* Need to notify for the combined variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetSatTarget(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u8SatTarget);

				/* Handle new HueSatTarget value (notifying and using configured transition time */
				(void) MibColourControl_bNewHueSatTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime, TRUE);
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetSatChange
 *
 * DESCRIPTION:
 * Sets sat target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetSatChange(int8 i8Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Call standard function */
			eReturn = eSetUint8(i8Val, pvCbData);
			/* Debug */
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetSatChange(%d)",
				acDebugIndent,
				sMibColourControl.sTemp.i8SatChange);

			/* Actual change specified ? */
			if (sMibColourControl.sTemp.i8SatChange != 0)
			{
				uint8 u8SatTarget;

				/* Get absolute value of change */
				u8SatTarget = abs(sMibColourControl.sTemp.i8SatChange);

				/* Change is positive ? */
				if (sMibColourControl.sTemp.i8SatChange > 0)
				{
					/* Trying to go above the maximum ? */
					if (sMibColourControl.sTemp.u8SatTarget > 255 - u8SatTarget)
					{
						/* Set new value to maximum */
						u8SatTarget = 255;
					}
					else
					{
						/* Calculate new value */
						u8SatTarget = sMibColourControl.sTemp.u8SatTarget + u8SatTarget;
					}
				}
				/* Change is negative ? */
				else if (sMibColourControl.sTemp.i8SatChange < 0)
				{
					/* Trying to go below the minimum ? */
					if (sMibColourControl.sTemp.u8SatTarget < u8SatTarget)
					{
						/* Set new value to minimum */
						u8SatTarget = 0;
					}
					else
					{
						/* Calculate new value */
						u8SatTarget = sMibColourControl.sTemp.u8SatTarget - u8SatTarget;
					}
				}

				/* New sat target ? */
				if (sMibColourControl.sTemp.u8SatTarget != u8SatTarget)
				{
					/* Set new value */
					sMibColourControl.sTemp.u8SatTarget = u8SatTarget;
					/* Build combined variable */
					sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
					/* Need to notify for the variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);

					/* Convert target HS to target xy */
					eCLD_ColourControl_HSV2xyY(&sMibColourConfig.sColourData,
						sMibColourControl.sTemp.u16HueTarget,
						sMibColourControl.sTemp.u8SatTarget,
						255,	/* Use full value (gets scaled later) */
						&sMibColourControl.sTemp.u16XTarget,
						&sMibColourControl.sTemp.u16YTarget,
						&sMibColourControl.u8Discard);
					/* Update combined target value */
					sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);
					/* Make sure permanent data is saved */
					sMibColourControl.bSaveRecord = TRUE;
					/* Need to notify for the Target XY variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);

					/* Convert target XY to target CCT */
					vCLD_ColourControl_xyY2CCT(
						sMibColourControl.sTemp.u16XTarget,
						sMibColourControl.sTemp.u16YTarget,
						255,
						&sMibColourControl.sTemp.u16CctTarget);
					/* Need to notify for the Target CCT variable */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);

					/* Initialise transition data */
					MibColourControl_vInitTransition(sMibColourConfig.sPerm.u16TransitionTime);
					/* Moving off CCT line */
					sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
					/* Set up the transition */
					(void) ColourTransition_bHSStart(&sMibColourControl.sColourTransition, TRUE);
				}
			}
		}
	}
	#endif

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetHueSatCurrent
 *
 * DESCRIPTION:
 * Sets hue and saturation current value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetHueSatCurrent(uint32 u32Val, void *pvCbData)
{
	teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* RGB driver ? */
	#ifdef MK_DRIVER_TYPE_COLOUR
	{
		/* Go to stop mode if necessary (with notifications) */
		MibColourControl_bModeStop(TRUE);
		/* In a mode where the user is in control of the target level ? */
		if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
			(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
		{
			/* Return ok (for now) */
			eReturn = E_JIP_OK;

			/* New value ? */
			if (sMibColourControl.sTemp.u32HueSatCurrent != u32Val)
			{
				/* Call standard function */
				eReturn = eSetUint32(u32Val, pvCbData);
				/* Split into component variables ensuring hue is in valid range */
				sMibColourControl.sTemp.u16HueCurrent = U32_TO_HUE(sMibColourControl.sTemp.u32HueSatCurrent) % 3600;
				sMibColourControl.sTemp.u8SatCurrent  = U32_TO_SAT(sMibColourControl.sTemp.u32HueSatCurrent);
				/* Rebuild combined variable now hue has been validated */
				sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
				/* Debug */
				DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetHueSatCurrent(0x%x)",
					acDebugIndent,
					sMibColourControl.sTemp.u32HueSatCurrent);

				/* Target HS is different to Current HS ? */
				if (sMibColourControl.sTemp.u32HueSatTarget != sMibColourControl.sTemp.u32HueSatCurrent)
				{
					/* Update Target HS */
					sMibColourControl.sTemp.u32HueSatTarget = sMibColourControl.sTemp.u32HueSatCurrent;
					sMibColourControl.sTemp.u16HueTarget    = sMibColourControl.sTemp.u16HueCurrent;
					sMibColourControl.sTemp.u8SatTarget     = sMibColourControl.sTemp.u8SatCurrent;
					/* Need to notify for the Target HS variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
				}

				/* Convert current HS to current xy */
				eCLD_ColourControl_HSV2xyY(&sMibColourConfig.sColourData,
					sMibColourControl.sTemp.u16HueCurrent,
					sMibColourControl.sTemp.u8SatCurrent,
					255,	/* Use full value (gets scaled later) */
					&sMibColourControl.sTemp.u16XCurrent,
					&sMibColourControl.sTemp.u16YCurrent,
					&sMibColourControl.u8Discard);
				/* Update combined current value */
				sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
				/* Need to notify for the Current XY variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);

				/* Target XY is different to Current XY ? */
				if (sMibColourControl.sPerm.u32XYTarget != sMibColourControl.sTemp.u32XYCurrent)
				{
					/* Update Target XY */
					sMibColourControl.sPerm.u32XYTarget = sMibColourControl.sTemp.u32XYCurrent;
					sMibColourControl.sTemp.u16XTarget  = sMibColourControl.sTemp.u16XCurrent;
					sMibColourControl.sTemp.u16YTarget  = sMibColourControl.sTemp.u16YCurrent;
					/* Make sure permanent data is saved */
					sMibColourControl.bSaveRecord = TRUE;
					/* Need to notify for the Target XY variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
				}

				/* Convert current xy to current CCT */
				vCLD_ColourControl_xyY2CCT(
					sMibColourControl.sTemp.u16XCurrent,
					sMibColourControl.sTemp.u16YCurrent,
					255,
					&sMibColourControl.sTemp.u16CctCurrent);
				/* Need to notify for the Current CCT variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_CURRENT);

				/* Target CCT is different to Current CCT ? */
				if (sMibColourControl.sTemp.u16CctCurrent != sMibColourControl.sTemp.u16CctCurrent)
				{
					/* Update Target CCT */
					sMibColourControl.sTemp.u16CctTarget    = sMibColourControl.sTemp.u16CctCurrent;
					/* Need to notify for the Target HS variables */
					sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
				}

				/* Convert current xy to current RGB */
				eCLD_ColourControl_GetRGB(&sMibColourConfig.sColourData,
										  sMibColourControl.sTemp.u16XCurrent,
										  sMibColourControl.sTemp.u16YCurrent,
										  &sMibColourControl.sTemp.u8RedCurrent,
										  &sMibColourControl.sTemp.u8GreenCurrent,
										  &sMibColourControl.sTemp.u8BlueCurrent);
				/* Need to notify for the Current RGB variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);

				/* Moving off CCT line */
				sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
				/* RGB driver ? */
				#ifdef MK_DRIVER_TYPE_COLOUR
				{
					/* Set colour in bulb driver */
					DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
										  sMibColourControl.sTemp.u8GreenCurrent,
										  sMibColourControl.sTemp.u8BlueCurrent);
				}
				#endif
				/* CCT driver ? */
				#ifdef MK_DRIVER_TYPE_TEMPERATURE
				{
					/* Set colour in bulb driver */
					DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
				}
				#endif
			}
		}
	}
	#endif

	return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetCctTarget
 *
 * DESCRIPTION:
 * Sets CCT target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetCctTarget(uint16 u16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* Go to stop mode if necessary (with notifications) */
	MibColourControl_bModeStop(TRUE);
    /* In a mode where the user is in control of the target level ? */
    if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
    	(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
    {
		/* Return ok (for now) */
		eReturn = E_JIP_OK;

		/* Bring value within limits */
		#if (CLD_CCT_MIRED_MIN > 0)
		if (u16Val < CLD_CCT_MIRED_MIN) u16Val = CLD_CCT_MIRED_MIN;
		#endif
		#if (CLD_CCT_MIRED_MAX < 0xffff)
		if (u16Val > CLD_CCT_MIRED_MAX) u16Val = CLD_CCT_MIRED_MAX;
		#endif

		/* New value or not on CCT line ? */
		if (sMibColourControl.sTemp.u16CctTarget != u16Val ||
			sMibColourControl.u8CctMode != MIB_COLOUR_CONTROL_CCT_MODE_ON)
		{
			/* Call standard function */
			eReturn = eSetUint16(u16Val, pvCbData);
			/* Debug */
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetCctTarget(%d)",
				acDebugIndent,
				sMibColourControl.sTemp.u16CctTarget);
			/* Handle the new value (allowing notifications to be sent for other variables and the configured transition time) */
			MibColourControl_bNewCctTarget(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
		}
    }

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetCctChange
 *
 * DESCRIPTION:
 * Sets CCT target value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetCctChange(int16 i16Val, void *pvCbData)
{
    teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* Go to stop mode if necessary (with notifications) */
	MibColourControl_bModeStop(TRUE);
    /* In a mode where the user is in control of the target level ? */
    if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
    	(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
    {
		/* Call standard function */
		eReturn = eSetUint16(i16Val, pvCbData);
		/* Debug */
		DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetCctChange(%d)",
			acDebugIndent,
			sMibColourControl.sTemp.i16CctChange);
		/* Handle the new value (allowing notifications to be sent for other variables and the configured transition time) */
		MibColourControl_bNewCctChange(TRUE, sMibColourConfig.sPerm.u16TransitionTime);
    }

    return eReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_eSetCctCurrent
 *
 * DESCRIPTION:
 * Sets hue and saturation current value
 *
 ****************************************************************************/
PUBLIC teJIP_Status MibColourControl_eSetCctCurrent(uint16 u16Val, void *pvCbData)
{
	teJIP_Status eReturn = E_JIP_ERROR_DISABLED;

	/* Go to stop mode if necessary (with notifications) */
	MibColourControl_bModeStop(TRUE);
    /* In a mode where the user is in control of the target level ? */
    if ((sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_OFF) ||
    	(sMibBulbControl.sPerm.u8Mode == VAR_VAL_BULB_CONTROL_MODE_ON ))
	{
		/* Return ok (for now) */
		eReturn = E_JIP_OK;

		/* Bring value within limits */
		#if (CLD_CCT_MIRED_MIN > 0)
		if (u16Val < CLD_CCT_MIRED_MIN) u16Val = CLD_CCT_MIRED_MIN;
		#endif
		#if (CLD_CCT_MIRED_MAX < 0xffff)
		if (u16Val > CLD_CCT_MIRED_MAX) u16Val = CLD_CCT_MIRED_MAX;
		#endif

		/* New value ? */
		if (sMibColourControl.sTemp.u16CctCurrent != u16Val)
		{
			/* Call standard function */
			eReturn = eSetUint16(u16Val, pvCbData);
			/* Debug */
			DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_eSetCctCurrent(%d)",
				acDebugIndent,
				sMibColourControl.sTemp.u16CctCurrent);

			/* Target CCT is different to current CCT ? */
			if (sMibColourControl.sTemp.u16CctTarget != sMibColourControl.sTemp.u16CctCurrent)
			{
				/* Update Target CCT */
				sMibColourControl.sTemp.u16CctTarget    = sMibColourControl.sTemp.u16CctCurrent;
				/* Need to notify for the Target HS variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
			}

			/* Convert current CCT to current xy */
			vCLD_ColourControl_CCT2xyY(sMibColourControl.sTemp.u16CctCurrent,
        		&sMibColourControl.sTemp.u16XCurrent,
        		&sMibColourControl.sTemp.u16YCurrent,
        		&sMibColourControl.u8Discard);
			/* Update combined current value */
			sMibColourControl.sTemp.u32XYCurrent = X_Y_TO_U32(sMibColourControl.sTemp.u16XCurrent, sMibColourControl.sTemp.u16YCurrent);
			/* Need to notify for the Current XY variable */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_CURRENT);

			/* Target XY is different to Current XY ? */
			if (sMibColourControl.sPerm.u32XYTarget != sMibColourControl.sTemp.u32XYCurrent)
			{
				/* Update Target XY */
				sMibColourControl.sPerm.u32XYTarget = sMibColourControl.sTemp.u32XYCurrent;
				sMibColourControl.sTemp.u16XTarget  = sMibColourControl.sTemp.u16XCurrent;
				sMibColourControl.sTemp.u16YTarget  = sMibColourControl.sTemp.u16YCurrent;
				/* Make sure permanent data is saved */
				sMibColourControl.bSaveRecord = TRUE;
				/* Need to notify for the Target XY variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
			}

			/* Convert current xy to current HS */
			eCLD_ColourControl_xyY2HSV(
				&sMibColourConfig.sColourData,
				sMibColourControl.sTemp.u16XCurrent,
				sMibColourControl.sTemp.u16YCurrent,
				(uint8) 255,
				&sMibColourControl.sTemp.u16HueCurrent,
				&sMibColourControl.sTemp.u8SatCurrent,
				&sMibColourControl.u8Discard);
			/* Build combined variable value */
			sMibColourControl.sTemp.u32HueSatCurrent = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueCurrent, sMibColourControl.sTemp.u8SatCurrent);
			/* Need to notify for the Current Hue Sat variable */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_CURRENT);

			/* Target HS is different to Current HS ? */
			if (sMibColourControl.sTemp.u32HueSatTarget != sMibColourControl.sTemp.u32HueSatCurrent)
			{
				/* Update Target HS */
				sMibColourControl.sTemp.u32HueSatTarget = sMibColourControl.sTemp.u32HueSatCurrent;
				sMibColourControl.sTemp.u16HueTarget    = sMibColourControl.sTemp.u16HueCurrent;
				sMibColourControl.sTemp.u8SatTarget     = sMibColourControl.sTemp.u8SatCurrent;
				/* Need to notify for the Target HS variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
			}

			/* Convert current xy to current RGB */
			eCLD_ColourControl_GetRGB(&sMibColourConfig.sColourData,
									  sMibColourControl.sTemp.u16XCurrent,
									  sMibColourControl.sTemp.u16YCurrent,
									  &sMibColourControl.sTemp.u8RedCurrent,
									  &sMibColourControl.sTemp.u8GreenCurrent,
									  &sMibColourControl.sTemp.u8BlueCurrent);
			/* Need to notify for the Current RGB variables */
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_RED_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_GREEN_CURRENT);
			sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_BLUE_CURRENT);

			/* Moving to CCT line */
			sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_ON;
			/* RGB driver ? */
			#ifdef MK_DRIVER_TYPE_COLOUR
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetColour(sMibColourControl.sTemp.u8RedCurrent,
									  sMibColourControl.sTemp.u8GreenCurrent,
									  sMibColourControl.sTemp.u8BlueCurrent);
			}
			#endif
			/* CCT driver ? */
			#ifdef MK_DRIVER_TYPE_TEMPERATURE
			{
				/* Set colour in bulb driver */
				DriverBulb_vSetTunableWhiteColourTemperature((int32)(1000000/sMibColourControl.sTemp.u16CctCurrent));
			}
			#endif
		}
	}

	return eReturn;
}

/****************************************************************************/
/***        Local Functions                                               ***/
/****************************************************************************/

/****************************************************************************
 *
 * NAME: MibColourControl_vInitTransition
 *
 * DESCRIPTION:
 * Sets up transition data from MIB data
 *
 ****************************************************************************/
PRIVATE void MibColourControl_vInitTransition(uint16 u16TransitionTime)
{
	/* Source XY is current XY */
	sMibColourControl.sColourTransition.sXYInterpolation.au32Source[X_DIM] = sMibColourControl.sTemp.u16XCurrent;
	sMibColourControl.sColourTransition.sXYInterpolation.au32Source[Y_DIM] = sMibColourControl.sTemp.u16YCurrent;
	/* Target XY is target XY */
	sMibColourControl.sColourTransition.sXYInterpolation.au32Target[X_DIM] = sMibColourControl.sTemp.u16XTarget;
	sMibColourControl.sColourTransition.sXYInterpolation.au32Target[Y_DIM] = sMibColourControl.sTemp.u16YTarget;
	/* XY steps is determined by the ColourConfig MIB TransitionTime variable */
	sMibColourControl.sColourTransition.sXYInterpolation.u8StepsPowerOfTwo = 0;
	sMibColourControl.sColourTransition.sXYInterpolation.u32Steps          =
		(uint32)(u16TransitionTime >> MIB_COLOUR_CONTROL_RGB_INTERPOLATION_STEPS_POWER_OF_TWO);

	/* Source HS is current HS */
	sMibColourControl.sColourTransition.sHSInterpolation.au32Source[H_DIM] = sMibColourControl.sTemp.u16HueCurrent;
	sMibColourControl.sColourTransition.sHSInterpolation.au32Source[S_DIM] = sMibColourControl.sTemp.u8SatCurrent;
	/* Target HS is target HS */
	sMibColourControl.sColourTransition.sHSInterpolation.au32Target[H_DIM] = sMibColourControl.sTemp.u16HueTarget;
	sMibColourControl.sColourTransition.sHSInterpolation.au32Target[S_DIM] = sMibColourControl.sTemp.u8SatTarget;
	/* HS steps is determined by the ColourConfig MIB TransitionTime variable */
	sMibColourControl.sColourTransition.sHSInterpolation.u8StepsPowerOfTwo = 0;
	sMibColourControl.sColourTransition.sHSInterpolation.u32Steps          =
		(uint32)(u16TransitionTime >> MIB_COLOUR_CONTROL_RGB_INTERPOLATION_STEPS_POWER_OF_TWO);

	/* Source CCT is current CCT */
	sMibColourControl.sColourTransition.sCctInterpolation.au32Source[CCT_DIM] = sMibColourControl.sTemp.u16CctCurrent;
	/* Target CCT is target CCT */
	sMibColourControl.sColourTransition.sCctInterpolation.au32Target[CCT_DIM] = sMibColourControl.sTemp.u16CctTarget;
	/* CCT steps is determined by the ColourConfig MIB TransitionTime variable */
	sMibColourControl.sColourTransition.sCctInterpolation.u8StepsPowerOfTwo = 0;
	sMibColourControl.sColourTransition.sCctInterpolation.u32Steps          =
		(uint32)(u16TransitionTime >> MIB_COLOUR_CONTROL_RGB_INTERPOLATION_STEPS_POWER_OF_TWO);

	/* RGB steps is a fixed power of two */
	sMibColourControl.sColourTransition.sRGBInterpolation.u8StepsPowerOfTwo = MIB_COLOUR_CONTROL_RGB_INTERPOLATION_STEPS_POWER_OF_TWO;
	sMibColourControl.sColourTransition.sRGBInterpolation.u32Steps          = 0;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bNewXYTarget
 *
 * DESCRIPTION:
 * Handle new XYTarget value
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bNewXYTarget(bool_t bNotifyChanged, uint16 u16TransitionTime)
{
    bool_t bReturn = TRUE;

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_bNewXYTarget(%d, %d)",
		acDebugIndent,
		bNotifyChanged,
		u16TransitionTime);

	/* Convert target xy to target HS */
	eCLD_ColourControl_xyY2HSV(
		&sMibColourConfig.sColourData,
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		(uint8) 255,
		&sMibColourControl.sTemp.u16HueTarget,
		&sMibColourControl.sTemp.u8SatTarget,
		&sMibColourControl.u8Discard);
	/* Build combined variable */
	sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);

	/* Convert target XY to target CCT */
	vCLD_ColourControl_xyY2CCT(
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		255,
		&sMibColourControl.sTemp.u16CctTarget);

	/* Need to set flags for changed variables ? */
	if (bNotifyChanged)
	{
		/* Need to notify for the Target Hue Sat variables */
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
		/* Need to notify for the Target CCT variable */
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
	}

	/* Initialise transition data */
	MibColourControl_vInitTransition(u16TransitionTime);
	/* Moving off CCT line */
	sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
	/* Set up the transition */
	bReturn = ColourTransition_bXYStart(&sMibColourControl.sColourTransition);

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, " = %d", bReturn);

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bNewHueChange
 *
 * DESCRIPTION:
 * Handles a new HueChange or SatChange value
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bNewHueChange(bool_t bNotifyChanged, uint16 u16TransitionTime)
{
    bool_t bReturn = FALSE;

	/* Ensure new value is in correct range */
	sMibColourControl.sTemp.i16HueChange %= 3600;

	/* Actual change specified ? */
	if (sMibColourControl.sTemp.i16HueChange != 0)
	{
		uint16 u16HueTarget;

		/* Get absolute value of change */
		u16HueTarget = abs(sMibColourControl.sTemp.i16HueChange);

		/* Change is positive ? */
		if (sMibColourControl.sTemp.i16HueChange > 0)
		{
			/* Calculate new hue target */
			u16HueTarget = (sMibColourControl.sTemp.u16HueTarget + u16HueTarget) % 3600;
		}
		/* Change is negative ? */
		else if (sMibColourControl.sTemp.i16HueChange < 0)
		{
			/* Calculate new hue target */
			u16HueTarget = (sMibColourControl.sTemp.u16HueTarget + 3600 - u16HueTarget) % 3600;
		}

		/* Is the new calculated value different to the old value ? */
		if (sMibColourControl.sTemp.u16HueTarget != u16HueTarget)
		{
			/* Use the new value */
			sMibColourControl.sTemp.u16HueTarget = u16HueTarget;
			/* Build combined variable */
			sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);
			/* Need to set flags for changed variables ? */
			if (bNotifyChanged)
			{
				/* Need to notify for the variables */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
			}
			/* Handle new HueSatTarget value (notifying and using configured transition time */
			bReturn = MibColourControl_bNewHueSatTarget(bNotifyChanged, u16TransitionTime, TRUE);
		}
    }

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bNewHueSatTarget
 *
 * DESCRIPTION:
 * Handle new hue and saturation target value
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bNewHueSatTarget(bool_t bNotifyChanged, uint16 u16TransitionTime, bool_t bOptimise)
{
    bool_t bReturn = TRUE;

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_bNewHueSatTarget(%d, %d) [%d, %d] > [%d, %d]",
		acDebugIndent,
		bNotifyChanged,
		u16TransitionTime,
		sMibColourControl.sTemp.u16HueCurrent,
		sMibColourControl.sTemp.u8SatCurrent,
		sMibColourControl.sTemp.u16HueTarget,
		sMibColourControl.sTemp.u8SatTarget);

	/* Convert target HS to target xy */
	eCLD_ColourControl_HSV2xyY(&sMibColourConfig.sColourData,
		sMibColourControl.sTemp.u16HueTarget,
		sMibColourControl.sTemp.u8SatTarget,
		255,	/* Use full value (gets scaled later) */
		&sMibColourControl.sTemp.u16XTarget,
		&sMibColourControl.sTemp.u16YTarget,
		&sMibColourControl.u8Discard);
	/* Combine into XY Target */
	sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);

	/* Convert target XY to target CCT */
	vCLD_ColourControl_xyY2CCT(
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		255,
		&sMibColourControl.sTemp.u16CctTarget);

	/* Need to set flags for changed variables ? */
	if (bNotifyChanged)
	{
		/* Need to notify for the Target XY variables */
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
		/* Need to notify for the Target CCT variable */
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
		/* Make sure permanent data is saved */
		sMibColourControl.bSaveRecord = TRUE;
	}

	/* Initialise transition data */
	MibColourControl_vInitTransition(u16TransitionTime);
	/* Moving off CCT line */
	sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_OFF;
	/* Set up the transition */
	bReturn = ColourTransition_bHSStart(&sMibColourControl.sColourTransition, bOptimise);

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, " = %d", bReturn);

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bNewCctChange
 *
 * DESCRIPTION:
 * Handles a new CctChange value
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bNewCctChange(bool_t bNotifyChanged, uint16 u16TransitionTime)
{
    bool_t bReturn = FALSE;

	/* Actual change specified ? */
	if (sMibColourControl.sTemp.i16CctChange != 0)
	{
		uint16 u16CctTarget;

		/* Get absolute value of change */
		u16CctTarget = abs(sMibColourControl.sTemp.i16CctChange);

		/* Change is positive ? */
		if (sMibColourControl.sTemp.i16CctChange > 0)
		{
			/* Trying to go above the maximum ? */
			if (sMibColourControl.sTemp.u16CctTarget > CLD_CCT_MIRED_MAX - u16CctTarget)
			{
				/* Set new value to maximum */
				u16CctTarget = CLD_CCT_MIRED_MAX;
			}
			else
			{
				/* Calculate new value */
				u16CctTarget = sMibColourControl.sTemp.u16CctTarget + u16CctTarget;
			}
		}
		/* Change is negative ? */
		else if (sMibColourControl.sTemp.i16CctChange < 0)
		{
			/* Trying to go below the minimum ? */
			if (sMibColourControl.sTemp.u16CctTarget < CLD_CCT_MIRED_MIN + u16CctTarget)
			{
				/* Set new value to minimum */
				u16CctTarget = CLD_CCT_MIRED_MIN;
			}
			else
			{
				/* Calculate new value */
				u16CctTarget = sMibColourControl.sTemp.u16CctTarget - u16CctTarget;
			}
		}

		/* Is the new calculated value different to the old value ? */
		if (sMibColourControl.sTemp.u16CctTarget != u16CctTarget)
		{
			/* Use the new value */
			sMibColourControl.sTemp.u16CctTarget = u16CctTarget;
			/* Need to set flags for changed variables ? */
			if (bNotifyChanged)
			{
				/* Notify for the target variable */
				sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_CCT_TARGET);
			}
			/* Handle the new CctTarget variable */
			bReturn = MibColourControl_bNewCctTarget(bNotifyChanged, u16TransitionTime);
		}
    }

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bNewCctTarget
 *
 * DESCRIPTION:
 * Handles a new CctTarget value
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bNewCctTarget(bool_t bNotifyChanged, uint16 u16TransitionTime)
{
    bool_t bReturn = TRUE;

	/* Convert target CCT to target xy */
	vCLD_ColourControl_CCT2xyY(
		sMibColourControl.sTemp.u16CctTarget,
		&sMibColourControl.sTemp.u16XTarget,
		&sMibColourControl.sTemp.u16YTarget,
		&sMibColourControl.u8Discard);
	/* Update combined target value */
	sMibColourControl.sPerm.u32XYTarget = X_Y_TO_U32(sMibColourControl.sTemp.u16XTarget, sMibColourControl.sTemp.u16YTarget);

	/* Convert target xy to target HS */
	eCLD_ColourControl_xyY2HSV(
		&sMibColourConfig.sColourData,
		sMibColourControl.sTemp.u16XTarget,
		sMibColourControl.sTemp.u16YTarget,
		(uint8) 255,
		&sMibColourControl.sTemp.u16HueTarget,
		&sMibColourControl.sTemp.u8SatTarget,
		&sMibColourControl.u8Discard);
	/* Build combined variable */
	sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);

	/* Need to set flags for changed variables ? */
	if (bNotifyChanged)
	{
		/* Notify for the other target variables */
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_XY_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_X_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_Y_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_SAT_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_HUE_TARGET);
		sMibColourControl.u32NotifyChanged |= (1 << VAR_IX_COLOUR_CONTROL_SAT_TARGET);
		/* Make sure permanent data is saved */
		sMibColourControl.bSaveRecord = TRUE;
	}

	/* Initialise transition data */
	MibColourControl_vInitTransition(u16TransitionTime);
	/* Are we on the CCT line ? */
	if (sMibColourControl.u8CctMode == MIB_COLOUR_CONTROL_CCT_MODE_ON)
	{
		/* Set up the transition across CCT space */
		(void) ColourTransition_bCctStart(&sMibColourControl.sColourTransition);
	}
	/* Colour was not previously set in XY space ? */
	else
	{
		/* Transitioning to CCT line */
		sMibColourControl.u8CctMode = MIB_COLOUR_CONTROL_CCT_MODE_TRANS;
		/* Set up the transition across XY space to get to the CCT line */
		(void) ColourTransition_bXYStart(&sMibColourControl.sColourTransition);
	}

    return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bModeTestHSNext
 *
 * DESCRIPTION:
 * Calculates next value for cct test
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bModeTestHueSatNext(void)
{
	bool_t bReturn = FALSE;
	uint16 u16Random;
	uint16 u16HueTarget;
	uint8   u8SatTarget;

	/* Loop until we get a new hue or sat target */
	do
	{
		/* Select a psuedo random number */
		u16Random = (uint16) (rand() & 0xFFFF);
		/* Pick a random hue target (0-3599) */
		u16HueTarget = u16Random % 3600;
		/* Pick a random sat target (128-255) */
		u8SatTarget = 192 + (u16Random >> 10);
	}
	while (sMibColourControl.sTemp.u16HueTarget == u16HueTarget &&
	       sMibColourControl.sTemp.u8SatTarget  == u8SatTarget);
	/* Note new targets */
	sMibColourControl.sTemp.u16HueTarget = u16HueTarget;
	sMibColourControl.sTemp.u8SatTarget  =  u8SatTarget;
	/* Build combined variable */
	sMibColourControl.sTemp.u32HueSatTarget = HUE_SAT_TO_U32(sMibColourControl.sTemp.u16HueTarget, sMibColourControl.sTemp.u8SatTarget);

	/* Can we handle the HS target (don't notify, use medium transition time) ? */
	bReturn = MibColourControl_bNewHueSatTarget(FALSE, 64, TRUE);

	return bReturn;
}

/****************************************************************************
 *
 * NAME: MibColourControl_bModeTestCctNext
 *
 * DESCRIPTION:
 * Calculates next value for cct test
 *
 ****************************************************************************/
PRIVATE bool_t MibColourControl_bModeTestCctNext(void)
{
	bool_t bReturn = FALSE;
	uint16 u16Random;
	uint16 u16CctTarget;

	/* Loop until we get a new cct target */
	do
	{
		/* Select a psuedo random number */
		u16Random = (uint16) (rand() & 0xFFFF);
		/* Pick a random cct target (600-855) */
		u16CctTarget = 600 + (u16Random & 0xFF);
	}
	while (sMibColourControl.sTemp.u16CctTarget == u16CctTarget);
	/* Note new cct target */
	sMibColourControl.sTemp.u16CctTarget = u16CctTarget;

	/* Set a lum rate from 1 to 16 */
	sMibBulbConfig.sPerm.u8LumRate = ((uint8)((u16Random >> 8) & 0xF) + 1);

	/* Current level is high ? */
	if (sMibBulbControl.sTemp.u8LumCurrent > 224)
	{
		/* Fade down */
		sMibBulbControl.sPerm.u8LumTarget = 0;
	}
	/* Current level is low ? */
	else if (sMibBulbControl.sTemp.u8LumCurrent < 100)
	{
		/* Fade up */
		sMibBulbControl.sPerm.u8LumTarget = 255;
	}
	else
	{
		/* Should we go down (toss a coin) */
		if (u16Random & 0x1000)
		{
			/* Fade down */
			sMibBulbControl.sPerm.u8LumTarget = 0;
		}
		else
		{
			/* Fade up */
			sMibBulbControl.sPerm.u8LumTarget = 255;
		}
	}

	/* Can we handle the CCT target (don't notify, use short transition time) ? */
	bReturn = MibColourControl_bNewCctTarget(FALSE, 16);

	/* Debug */
	DBG_vPrintf(DEBUG_MIB_COLOUR_CONTROL, "\n%sMibColourControl_bModeTestCctNext() = %d {%d, %d, %d}",
		acDebugIndent,
		bReturn,
		sMibColourControl.sTemp.u16CctTarget,
		sMibBulbConfig.sPerm.u8LumRate,
		sMibBulbControl.sPerm.u8LumTarget);

	return bReturn;
}

/****************************************************************************/
/***        END OF FILE                                                   ***/
/****************************************************************************/
