/**
  ******************************************************************************
  * @file           : rdm_implementation.c
  * @brief          : Simple example for showing rdm functionality using the provided rdm library
  ******************************************************************************
  * @attention
  *
  * Copyright (c) Kuenzler Technologies GbR
  * All rights reserved.
  *
  *
  ******************************************************************************
*/

/*==============================================================================*/
/* Includes                                                                  	*/
/*==============================================================================*/
#include "rdm_implementation.h"
#include "string.h"
#include "stdio.h"
#include "variables.h"
#include "defines.h"
#include "stdlib.h"

#include "libRdmInterface.h"
#include "libIqMeshSpiInterface.h"

/*==============================================================================*/
/* Private functions                                                          	*/
/*==============================================================================*/
static uint8_t dump_u64(uint64_t x, char* buf, uint8_t bufLength);

/*==============================================================================*/
/* Private variables                                                          	*/
/*==============================================================================*/
static bool resetFlag = false;
static uint32_t resetTime = 0;

/*==============================================================================*/
/* Function definitions                                                     	*/
/*==============================================================================*/
void InitRdmImp(void (*callback)(const uint8_t * msg, uint16_t length, bool sentBreak, uint8_t id))
{
	rdm_init(get_rdmid().array,callback);
}

void RdmTask(uint32_t tickMs)
{
	if(resetFlag)
	{
		if(resetTime == 0)
		{
			resetTime = tickMs;
		}
		else if(tickMs - resetTime > 2000)
		{
			HardwareRdmReset();
		}
	}
}

void RdmSet(const uint8_t* buf, uint16_t length, uint8_t id)
{
	rdm_decodeMessage(buf, length, id);
}

void RdmExtGetFactoryDefaults(rdm_answer_t* rdmImp,rdm_factory_default_get_response_t* responseBuf )
{
	responseBuf->isDefault = get_factoryDefault();
	(void)rdmImp;
}

void RdmExtGetDeviceInfo(rdm_answer_t* rdmImp, rdm_device_info_get_response_t* responseBuf)
{
	responseBuf->SubDeviceCount = 0;
	responseBuf->deviceModelId = RDM_DEVICEMODEL_ID;
	responseBuf->dmxFootprint = RDM_FOOTPRINTS[get_dmxSettings()->dmxPersonality - 1];
	responseBuf->dmxPersonality = get_dmxSettings()->dmxPersonality;
	responseBuf->dmxPersonalityCount = RDM_PERSONALITY_COUNT;
	responseBuf->dmxStartaddress = get_dmxSettings()->dmxStartadress;
	responseBuf->productCategory = RDM_PRODUCT_CATEGORY;//PRODUCT_CATEGORY_FIXTURE_FIXED;
	responseBuf->protocollVersion = 256;
	responseBuf->sensorCount = RDM_SENSOR_COUNT;
	#ifdef RELEASEBL
	if(((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->reboot_cause == BOOT_NORMAL)
	{
	 memcpy(&responseBuf->softwareVersionId,((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion,4);
	}
	#endif
	// rotate endianess for softwareID
	responseBuf->softwareVersionId = __builtin_bswap32(responseBuf->softwareVersionId);
	(void)rdmImp;
}
void RdmExtGetProductDetail(rdm_answer_t* rdmImp, rdm_product_detail_id_get_response_t* responseBuf)
{
	responseBuf->productDetails[0] = RDM_PRODUCT_DETAIL_LED;
	responseBuf->productDetailsCount = 1;
	(void)rdmImp;
}
void RdmExtGetDeviceModelDescription(rdm_answer_t* rdmImp, rdm_device_model_description_get_response_t* responseBuf)
{
	strcpy((char*)responseBuf->label,RDM_DEVICE_MODEL_DESCRIPTION);
	responseBuf->labelSize = sizeof(RDM_DEVICE_MODEL_DESCRIPTION);
	(void)rdmImp;
}
void RdmExtGetManufacturerLabel(rdm_answer_t* rdmImp, rdm_manufacturer_label_get_response_t* responseBuf)
{
	strcpy((char*)responseBuf->label,RDM_MANUFACTURER_NAME);
	responseBuf->labelSize = sizeof(RDM_MANUFACTURER_NAME);
	(void)rdmImp;
}
void RdmExtGetDeviceLabel(rdm_answer_t* rdmImp, rdm_device_label_get_response_t* responseBuf)
{
	device_label_t label = *get_deviceLabel();
	uint8_t length = (uint8_t)strlen(label.array);
	memcpy(responseBuf->label,label.array,length);
	responseBuf->labelSize = length;
	(void)rdmImp;
}
void RdmExtGetSoftwareVersionLabel(rdm_answer_t* rdmImp,rdm_softwareversion_label_get_response_t* responseBuf)
{
	#ifdef RELEASEBL
	if(((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->reboot_cause == BOOT_NORMAL)
	{
		responseBuf->labelSize = (uint8_t)sprintf((char*)responseBuf->label, "%d.%d.%d.%d", ((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion[0],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion[1],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion[2],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion[3]);
	}
	(void)rdmImp;
	#endif
}
void RdmExtGetBootSoftwareVersionLabel(rdm_answer_t* rdmImp, rdm_boot_softwareversion_label_get_response_t* responseBuf)
{
	#ifdef RELEASEBL
	if(((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->reboot_cause == BOOT_NORMAL)
	{
		responseBuf->labelSize = (uint8_t)sprintf((char*)responseBuf->label, "%d.%d.%d.%d", ((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->bootloaderVersion[0],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->bootloaderVersion[1],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->bootloaderVersion[2],((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->bootloaderVersion[3]);
	}
	(void)rdmImp;
	#endif
}
void RdmExtGetDmxPersonality(rdm_answer_t* rdmImp, rdm_dmx_personality_get_response_t* responseBuf)
{
	responseBuf->currentPersonality = get_dmxSettings()->dmxPersonality;
	responseBuf->numPersonalities = RDM_PERSONALITY_COUNT;
	(void)rdmImp;
}
void RdmExtGetDmxPersonalityDescription(rdm_answer_t* rdmImp, rdm_dmx_personality_description_get_response_t* responseBuf)
{
	if(responseBuf->requestedPersonality > RDM_PERSONALITY_COUNT)
	{
		 rdmImp->response = RDM_NACK_REASON;
		 rdmImp->reason = NR_DATA_OUT_OF_RANGE;
		 return;
	}
	responseBuf->footprint = RDM_FOOTPRINTS[responseBuf->requestedPersonality -1];
	responseBuf->labelSize = (uint8_t)strlen(RDM_PERSONALITY_NAMES[responseBuf->requestedPersonality -1]);
	memcpy((char*)responseBuf->label,RDM_PERSONALITY_NAMES[responseBuf->requestedPersonality -1],responseBuf->labelSize);
	(void)rdmImp;
}
void RdmExtGetDmxStartaddress(rdm_answer_t* rdmImp, rdm_dmx_startaddress_get_response_t* responseBuf)
{
	responseBuf->address = get_dmxSettings()->dmxStartadress;
	(void)rdmImp;
}
void RdmExtGetSensorDefinition(rdm_answer_t* rdmImp, rdm_sensor_defintion_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	rdmImp->reason = NR_DATA_OUT_OF_RANGE;
	(void)responseBuf;
}
void RdmExtGetSensorValue(rdm_answer_t* rdmImp, rdm_sensor_value_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	rdmImp->reason = NR_DATA_OUT_OF_RANGE;
	(void)responseBuf;
}
void RdmExtGetDeviceHours(rdm_answer_t* rdmImp, rdm_device_hours_get_response_t* responseBuf)
{
	responseBuf->deviceHours = get_counter()->deviceCounterMinutes/60;
	(void)rdmImp;
}
void RdmExtGetLampHours(rdm_answer_t* rdmImp, rdm_lamphours_get_response_t* responseBuf)
{
	responseBuf->lampHours = get_counter()->sourceCounterMinutes/60;
	(void)rdmImp;
}
void RdmExtGetLampStrikes(rdm_answer_t* rdmImp, rdm_lampstrike_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	(void)responseBuf;
}
void RdmExtGetLampState(rdm_answer_t* rdmImp, rdm_lampstate_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	(void)responseBuf;
}
void RdmExtGetDevicePowerCycles(rdm_answer_t* rdmImp, rdm_device_power_cycle_get_response_t* responseBuf)
{
	responseBuf->powerCycleCount = get_counter()->devicePowercycle;
	(void)rdmImp;
}
void RdmExtGetIdentify(rdm_answer_t* rdmImp, rdm_identify_device_get_response_t* responseBuf)
{
	responseBuf->identifyState = *get_rdmIdentify();
	(void)rdmImp;
}
void RdmExtGetPowerState(rdm_answer_t* rdmImp, rdm_power_state_get_response_t* responseBuf)
{
	switch(*get_systemState())
	{
		case SYSTEM_STATE_NORMAL:
			responseBuf->powerState = RDMPOWER_STATE_NORMAL;
		break;
		case SYSTEM_STATE_SLEEP:
			responseBuf->powerState = RDMPOWER_STATE_STANDBY;
		break;
		case SYSTEM_STATE_WAKEUP:
			responseBuf->powerState = RDMPOWER_STATE_STANDBY;
		break;
		case SYSTEM_STATE_OFF:
			responseBuf->powerState = RDMPOWER_STATE_SHUTDOWN;
		break;
		case SYSTEM_STATE_TURN_OFF:
			responseBuf->powerState = RDMPOWER_STATE_SHUTDOWN;
		break;
	}
	(void)rdmImp;
}

void RdmExtGetPerformSelftest(rdm_answer_t* rdmImp, rdm_perform_selftest_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	(void)responseBuf;
}
void RdmExtGetSelfTestDescription(rdm_answer_t* rdmImp,rdm_selftest_description_get_response_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	(void)responseBuf;
}
void RdmExtGetIq(rdm_answer_t* rdmImp, rdm_iq_get_response_t* responseBuf)
{
	iqMesh_information_t info;
	uint8_t warningCount = 0;
	uint8_t errorCount = 0;
	uint32_t iqController_firmware = iqMesh_getModuleFirmwareVersion();
	uint32_t iqController_bl_firmware = iqMesh_getModuleBootloaderVersion();
	responseBuf->protocollVersion = 1;
	responseBuf->deviceModelId = RDM_DEVICEMODEL_ID;
	
	responseBuf->serial = (uint64_t)*get_serial();
    
	memcpy(responseBuf->iqControllerFirmware,&iqController_firmware,(size_t) 4);
	memcpy(responseBuf->iqControllerBootloaderFirmware,&iqController_bl_firmware,(size_t) 4);
	memcpy(responseBuf->iqControllerCpuId,iqMesh_getModuleCpuId(),(size_t) 8);
#ifdef RELEASEBL
	if(((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->reboot_cause == BOOT_NORMAL)
	{
		memcpy(responseBuf->fixtureFirmware,((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->file.firmwareVersion,(size_t) 4);
		memcpy(responseBuf->fixtureBootloaderFirmware,((dfu_config_t*) (USER_FLASH_ADDRESS_CONFIG))->bootloaderVersion,(size_t) 4);
	}
	else
	{
		// No bootloader or firmware version available - Anounce it as 255.255.255.255
		responseBuf->fixtureFirmware[0] = 255;
		responseBuf->fixtureFirmware[1] = 255;
		responseBuf->fixtureFirmware[2] = 255;
		responseBuf->fixtureFirmware[3] = 255;
	}
#else
		// No bootloader or firmware version available - Anounce it as 255.255.255.255
		responseBuf->fixtureFirmware[0] = 255;
		responseBuf->fixtureFirmware[1] = 255;
		responseBuf->fixtureFirmware[2] = 255;
		responseBuf->fixtureFirmware[3] = 255;
#endif
	memcpy(responseBuf->fixtureMainCpuId, (uint8_t*) 0x1FFFF7AC, 12);

#if BATTERY_SUPPORT
	responseBuf->battery = HardwareRdmGetBatteryStatePercent();
	if(HardwareOutputSettingGpioReadPowerSupplyPin())
	{
		if(HardwareRdmGetBatteryStatePercent != 100)
		{
			responseBuf->powerSupplyState = IQ_POWERSUPPLY_STATE_CHARGING;
		}
		else
		{
			responseBuf->powerSupplyState = IQ_POWERSUPPLY_STATE_GRID_POWERED;
		}
	}
#else
	if(HardwareOutputSettingGpioReadPowerSupplyPin())
	{
		responseBuf->powerSupplyState = IQ_POWERSUPPLY_STATE_GRID_POWERED;
	}
	else
	{
		responseBuf->powerSupplyState = IQ_POWERSUPPLY_STATE_NOPOWER;
	}

#endif

	switch(*get_inputSource())
	{
#if SUPPORTEDINPUTSOURCE_IQMESH
	case INPUT_SOURCE_IQ_MESH:
		 responseBuf->inputSource = RDMIQINPUTSOURCE_IQMESH;
		 iqMesh_getInformation(&info);
		 iqmesh_status_flags_t flags = iqMesh_getStatusFlags();
		 responseBuf->inputQuality = info.signalQuality;
		 switch(flags.iqStatus)
		 {
		 case IQMESH_STATUS_UNLINKED:
			 responseBuf->inputState = IQ_INPUTSTATE_UNLINKED;
			 break;
		 case IQMESH_STATUS_LINKED:
			 responseBuf->inputState = IQ_INPUTSTATE_LINKED;
			 break;
		 case IQMESH_STATUS_ACTIVE:
			 responseBuf->inputState = IQ_INPUTSTATE_ACTIVE;
			 break;
		 case IQMESH_STATUS_MASTER:
			 responseBuf->inputState = IQ_INPUTSTATE_ACTIVE;
			 break;
		 case IQMESH_STATUS_INACTIVE:
			 responseBuf->inputState = IQ_INPUTSTATE_IDLE;
			 break;
		 }
		break;
#endif
#if SUPPORTEDINPUTSOURCE_DMX
	case INPUT_SOURCE_DMX:
		responseBuf->inputSource = RDMIQINPUTSOURCE_DMX;
		responseBuf->inputQuality = 0;
		responseBuf->inputState = IQ_INPUTSTATE_IDLE;
		break;
#endif
	}
	responseBuf->dmxFootprint = RDM_FOOTPRINTS[get_dmxSettings()->dmxPersonality - 1];
	responseBuf->dmxPersonality = get_dmxSettings()->dmxPersonality;
	responseBuf->dmxStartaddress = get_dmxSettings()->dmxStartadress;
    
	if(warningCount > 15)
	{
		warningCount = 15;
	}
   
	if(errorCount > 15)
	{
		errorCount = 15;
	}
	responseBuf->errorCount = errorCount & 0b1111;
	responseBuf->warningCount = warningCount & 0b1111;
	responseBuf->supportedInputSource = SUPPORTEDINPUTSOURCE_IQMESH + (SUPPORTEDINPUTSOURCE_DMX << 1) + (SUPPORTEDINPUTSOURCE_CRMXWDMX << 2) + (SUPPORTEDINPUTSOURCE_ARTNET << 3) + (SUPPORTEDINPUTSOURCE_SACN << 4);
	responseBuf->featureShippingMode = FEATURE_SHIPPINGMODE_SUPPORT;
	#if FEATURE_EMERGENCY_SUPPORT == 1
    	responseBuf->featureEmergency = (uint8_t)(get_features()->emergencyMode) + 1;
	#endif
	#if FEATURE_RUNTIMESELECTION_SUPPORT == 1
    	responseBuf->featureRuntimeSelection = (uint8_t)(get_features()->runtimeSet) + 1;
	#endif
	#if FEATURE_ANTITHEFTMODE_SUPPORT == 1
    	responseBuf->featureAntitheftMode = (uint8_t)(get_features()->antitheftMode) + 1;
	#endif
    	responseBuf->featureSleepMode = FEATURE_SLEEP_SUPPORT;
	(void)rdmImp;

}

void RdmExtGetCustomError(rdm_answer_t* rdmImp, rdm_custom_label_get_response_t* responseBuf)
{
	uint8_t counter = 0;
//		if(!*get_colorCalibration())
//		{
//		strcpy((char*)&(responseBuf->label[counter]),"CALER");
//		counter += sizeof("CALER");
//		}
	responseBuf->labelSize = counter;
	(void)rdmImp;
}

void RdmExtGetCustomWarning(rdm_answer_t* rdmImp, rdm_custom_label_get_response_t* responseBuf)
{
	uint8_t counter = 0;
	responseBuf->labelSize = counter;
	(void)rdmImp;
}

void RdmExtGetCustomServiceHours(rdm_answer_t* rdmImp, uint32_t* responseBuf)
{
	rdmImp->response = RDM_NACK_REASON;
	rdmImp->reason = NR_UNSUPPORTED_COMMAND_CLASS;
	(void)responseBuf;
}

void RdmExtSetFactoryDefaults(rdm_answer_t* rdmImp)
{
	set_factoryDefault();
	(void)rdmImp;
}
void RdmExtSetDeviceLabel(rdm_answer_t* rdmImp, char* label, uint8_t labelLength)
{
	device_label_t dlabel;
	memset(&dlabel,0, sizeof(device_label_t));
    memcpy(dlabel.array,label,labelLength);
    set_deviceLabel(dlabel);
    (void)rdmImp;
}
void RdmExtSetDmxPersonality(rdm_answer_t* rdmImp, uint8_t personality)
{
	dmx_settings_t settings = *get_dmxSettings();
	settings.dmxPersonality = personality;
	if(!set_dmxSettings(settings))
	{
		rdmImp->response = RDM_NACK_REASON;
		rdmImp->reason = NR_DATA_OUT_OF_RANGE;
	}
}
void RdmExtSetDmxStartaddress(rdm_answer_t* rdmImp,uint16_t dmxStartAddress)
{
	dmx_settings_t settings = *get_dmxSettings();
	settings.dmxStartadress = dmxStartAddress;
	if(!set_dmxSettings(settings))
	{
		rdmImp->response = RDM_NACK_REASON;
		rdmImp->reason = NR_DATA_OUT_OF_RANGE;
	}
}
void RdmExtSetIdentify(rdm_answer_t* rdmImp, bool set)
{
	 set_rdmIdentify(set);
	 (void)rdmImp;
	 (void)set;
}
void RdmExtSetResetDevice(rdm_answer_t* rdmImp,rdm_reset_t reset)
{
	 resetFlag = true;
	 resetTime = 0;
	(void)reset;
	(void)rdmImp;
}
void RdmExtSetPowerState(rdm_answer_t* rdmImp, rdm_powerstate_t _powerState)
{
	switch(_powerState)
	{
		case RDMPOWER_STATE_NORMAL:
			set_systemState(SYSTEM_STATE_NORMAL);
		break;
		case RDMPOWER_STATE_STANDBY:
			set_systemState(SYSTEM_STATE_SLEEP);
		break;
		case RDMPOWER_STATE_SHUTDOWN:
		case RDMPOWER_STATE_FULL_OFF:
			set_systemState(SYSTEM_STATE_TURN_OFF);
		break;
	}
	(void)rdmImp;
}
void RdmExtSetPerformSelftest(rdm_answer_t* rdmImp,uint8_t selftest)
{
	rdmImp->response = RDM_NACK_REASON;
	rdmImp->reason = NR_UNSUPPORTED_COMMAND_CLASS;
	(void)selftest;
}

void RdmExtSetIqInputSource(rdm_answer_t* rdmImp, rdm_iq_inputsource_t inputSource)
{
	switch(inputSource)
	{
#if SUPPORTEDINPUTSOURCE_IQMESH
	case RDMIQINPUTSOURCE_IQMESH:
		set_inputSource(INPUT_SOURCE_IQ_MESH);
	break;
#endif
#if SUPPORTEDINPUTSOURCE_DMX
	case RDMIQINPUTSOURCE_DMX:
		set_inputSource(INPUT_SOURCE_DMX);
	break;
#endif
#if SUPPORTEDINPUTSOURCE_CRMX
	case RDMIQINPUTSOURCE_CRMXWDMX:
#endif
#if SUPPORTEDINPUTSOURCE_ARTNET
	case RDMIQINPUTSOURCE_ARTNET:
		break;
#endif
#if SUPPORTEDINPUTSOURCE_SACN
	case RDMIQINPUTSOURCE_SACN:
		break;
#endif
	case RDMIQINPUTSOURCE_GLPDOP:
	case RDMIQINPUTSOURCE_IRREMOTE:
	case RDMIQINPUTSOURCE_WIRELESS2_4GHZ:
	case RDMIQINPUTSOURCE_WIRELESS2_OTHER:
	case RDMIQINPUTSOURCE_ETHERNET:
	case RDMIQINPUTSOURCE_AUTO:
	case RDMIQINPUTSOURCE_MANUAL:
	default:
		rdmImp->response = RDM_NACK_REASON;
	break;
	}
	(void)rdmImp;
}
void RdmExtSetIqInputState(rdm_answer_t* rdmImp, rdm_iq_set_input_state_t inputState)
{
	if(inputState == IQ_INPUTSTATE_UNLINK)
	{
		// Unlink for example CRMX
	}
	(void)rdmImp;
}

void RdmExtSetIqEmergencyMode(rdm_answer_t* rdmImp,  bool emergencyOnOff)
{
	features_t features = *get_features();
	features.emergencyMode = emergencyOnOff;
	set_features(features);
	(void)rdmImp;
}
void RdmExtSetIqBatteryRuntime(rdm_answer_t* rdmImp,rdm_iq_battery_runtime_t runTime)
{
	features_t features = *get_features();
	features.runtimeSet = runTime;
	set_features(features);
	(void)rdmImp;
}
void RdmExtSetIqAntitheftMode(rdm_answer_t* rdmImp,rdm_iq_antitheft_t antitheft)
{
	features_t features = *get_features();
	features.antitheftMode = antitheft;
	set_features(features);
	(void)rdmImp;
}

void RdmExtSetCustomServiceHours(rdm_answer_t* rdmImp, uint32_t counter)
{
	rdmImp->response = RDM_NACK_REASON;
	rdmImp->reason = NR_UNSUPPORTED_COMMAND_CLASS;
	(void)counter;
}


/* Custom Commands */
typedef enum
{
	RDMCPID_CUSTOMSERIAL = 0x8060,
}rdm_custom_pid_t;

void RdmExtGetSupportedParameter(rdm_answer_t* rdmImp,uint16_t* responseBuf, uint8_t* pidCount)
{
	responseBuf[0] = RDMPID_PRODUCTDETAILIDLIST;
	responseBuf[1] = RDMPID_DEVICEMODELDESCRIPTION;
	responseBuf[2] = RDMPID_MANUFACTURER_LABEL;
	responseBuf[3] = RDMPID_DEVICE_LABEL;
	responseBuf[4] = RDMPID_FACTORY_DEFAULTS;
	responseBuf[5] = RDMPID_BOOT_SOFTWARE_VERSION_LABEL;
	responseBuf[6] = RDMPID_DMX_PERSONALITY;
	responseBuf[7] = RDMPID_DMX_PERSONALITY_DESCRIPTION;
	responseBuf[8] = RDMPID_SLOT_INFO;
	responseBuf[9] = RDMPID_SLOT_DESCRIPTION;
	responseBuf[10] = RDMPID_SENSOR_DEFINITION;
	responseBuf[11] = RDMPID_SENSOR_VALUE;
	responseBuf[12] = RDMPID_DEVICE_HOURS;
	responseBuf[13] = RDMPID_LAMP_HOURS;
	responseBuf[14] = RDMPID_DEVICE_POWER_CYCLES;
	responseBuf[15] = RDMPID_RESET_DEVICE;
	responseBuf[16] = RDMPID_POWER_STATE;
	responseBuf[17] = RDMPID_PERFORM_SELFTEST;
	responseBuf[18] = RDMCPID_CUSTOMERROR;
	responseBuf[19] = RDMCPID_CUSTOMWARNING;
	responseBuf[20] = RDMCPID_CUSTOMSERIAL;
	*pidCount = 21;
	(void)rdmImp;
}

void RdmExtGetParameterDescription(rdm_answer_t* rdmImp,rdm_parameter_description_get_response_t* responseBuf)
{
	switch(responseBuf->requestedParameter)
	{
	case RDMCPID_CUSTOMERROR:
		responseBuf->commandClass = RDM_PD_CC_GET;
		responseBuf->dataType = RDM_DTD_DS_ASCII;
		responseBuf->defaultValue = 0;
		responseBuf->labelSize = (uint8_t)sprintf((char*)responseBuf->description, "Error Codes");
		responseBuf->maxValidValue = 0;
		responseBuf->pdlSize = 32;
		responseBuf->prefix = RDM_PREFIX_NONE;
		responseBuf->type = 0x00;
		responseBuf->unit = RDMUNITS_NONE;

	break;
	case RDMCPID_CUSTOMWARNING:
		responseBuf->commandClass = RDM_PD_CC_GET;
		responseBuf->dataType = RDM_DTD_DS_ASCII;
		responseBuf->defaultValue = 0;
		responseBuf->labelSize = (uint8_t)sprintf((char*)responseBuf->description, "Warning Codes");
		responseBuf->maxValidValue = 0;
		responseBuf->pdlSize = 32;
		responseBuf->prefix = RDM_PREFIX_NONE;
		responseBuf->type = 0x00;
		responseBuf->unit = RDMUNITS_NONE;
	break;
	case RDMCPID_CUSTOMSERIAL:
		responseBuf->commandClass = RDM_PD_CC_GET_SET;
		responseBuf->dataType = RDM_DTD_DS_ASCII;
		responseBuf->defaultValue = 0;
		responseBuf->labelSize = (uint8_t)sprintf((char*)responseBuf->description, "Serial number");
		responseBuf->maxValidValue = 0;
		responseBuf->pdlSize = 32;
		responseBuf->prefix = RDM_PREFIX_NONE;
		responseBuf->type = 0x00;
		responseBuf->unit = RDMUNITS_NONE;
	break;
	}
	(void)rdmImp;
}

typedef struct  __attribute__((__packed__))
{
	uint64_t serial;
}rdm_custom_serial_t;


static void DecodeSetCustomSerial(rdm_answer_t* rdmImp, uint8_t * data, uint16_t length);
static void DecodeGetCustomSerial(rdm_answer_t* rdmImp, uint8_t* responseBuf, uint16_t* responseLength);

void RdmExtSetCustomPid(rdm_answer_t* rdmImp, uint16_t pid, uint8_t* data, uint16_t pdl)
{
  switch(pid)
  {

      case RDMCPID_CUSTOMSERIAL:
        DecodeSetCustomSerial(rdmImp,data,pdl);
      break;
      default:
        rdmImp->response = RDM_NACK_REASON;
        rdmImp->reason = NR_UNKNOWN_PID;
      break;
  }
}
void RdmExtGetCustomPid(uint16_t pid, uint8_t* msg, uint16_t pdl, rdm_answer_t* rdmImp, uint8_t* responseBuf, uint16_t* responseLength)
{
  switch(pid)
  {
      case RDMCPID_CUSTOMSERIAL:
        DecodeGetCustomSerial(rdmImp,responseBuf,responseLength);
      break;
      default:
        rdmImp->response = RDM_NACK_REASON;
        rdmImp->reason = NR_UNKNOWN_PID;
      break;
  }
	(void)msg;
	(void)pdl;
}

static void DecodeGetCustomSerial(rdm_answer_t* rdmImp, uint8_t* responseBuf, uint16_t* responseLength)
{
  uint64_t serial = *get_serial();
  *responseLength = dump_u64(serial,(char*)responseBuf,32);
  (void) rdmImp;
}

static void DecodeSetCustomSerial(rdm_answer_t* rdmImp, uint8_t * data, uint16_t length)
{
  char *end;
  uint64_t serial = strtoll((char*)data, &end, 10);
  set_serial(serial);
  (void) rdmImp;
}

static uint8_t dump_u64(uint64_t x, char* buf, uint8_t bufLength)
{
	char temp[bufLength];
	char* b = temp;
	uint8_t count = 0;
    do
    {
    	if(count < bufLength)
    	{
    		*b++ = (char)('0' + (x % 10));
    		count++;
    	}
    	x /= 10;
    } while (x);
    for(uint8_t i= 0; i< count;i++)
    {
    	buf[i] = temp[count -1 - i];
    }
    return count;
}

