/* ---------------------------------------------------------------------------
 * BusProtocol.c - v0.1                                (c) 2008 Micro-key bv
 * ---------------------------------------------------------------------------
 * Micro-key bv
 * Industrieweg 28, 9804 TG Noordhorn
 * Postbus 92, 9800 AB Zuidhorn
 * The Netherlands
 * Tel: +31 594 503020
 * Fax: +31 594 505825
 * Email: support@microkey.nl  
 * Web: www.microkey.nl
 * ---------------------------------------------------------------------------
 * Description: 
 * ---------------------------------------------------------------------------
 * Version(s):  0.1, Jan 28, 2008, FSc
 *                   Creation.
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * System include files
 * ---------------------------------------------------------------------------
 */
#include <stdio.h>
#include <stdlib.h>

/* ---------------------------------------------------------------------------
 * Application include files
 * ---------------------------------------------------------------------------
 */
#include "BpPort.h"
#include "BusProtocol.h"
#include "ProtocolThread.h"
#include "MessageHandlerQueue.h"
#include "RemoteProcedureCalls.h"
#include "RpcResults.h"
#include "bus.h"
//#include "ElecStatusCache.h"
#include "mem_mod.h"


/* ---------------------------------------------------------------------------
 * Local constant and macro definitions
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Global variable definitions
 * ---------------------------------------------------------------------------
 */

/* ---------------------------------------------------------------------------
 * Local variable definitions
 * ---------------------------------------------------------------------------
 */
typedef struct t_BP_ADMIN {
	UINT8                      deviceId; 
	UINT8                      rpcRequestNr;
	int                        rpcHandle;
	int                        rpcrHandle;
	int                        bpthreadHandle;
	int                        messageHandlerHandle;
} t_bp_admin;

memman  *bpMessagePool;

/* ---------------------------------------------------------------------------
 * Local function definitions
 * ---------------------------------------------------------------------------
 */
static void WriteElectricStatusCallback( int handle, BOOLEAN isDigital, UINT8 device, UINT8 channel, UINT16 value );

/** \brief Initialises the BusProtocol 
 * 
 * \param bus The bus to communicate on
 * \param deviceId the bus identity for this device
 * \retval the handle for the BusProtocol-driver (0 = unsuccesfull)
 */
int bpInit( t_bus_devices bus, UINT8 deviceId, UINT8 highestDeviceId, UINT8 inputQueueSize )
{
	t_bp_admin *newBusProtocol = (t_bp_admin *)pvPortMalloc( sizeof(t_bp_admin));

	if (newBusProtocol != NULL)
	{
		// Fill administration
		newBusProtocol->deviceId = deviceId;
		newBusProtocol->rpcRequestNr = 0;
		newBusProtocol->rpcHandle = rpcInit();
		newBusProtocol->rpcrHandle = rpcrInit();
		newBusProtocol->messageHandlerHandle = mhqInit();
		
		// Allocate payload queue
		bpMessagePool = Memmod_Create( inputQueueSize, 64);  // Make sure size is dividable by 4
		
		// Register RPC Callback
		mhqAdd( newBusProtocol->messageHandlerHandle, BPMSG_MSGID_CALLRPC, rpcRequestHandler, newBusProtocol->rpcHandle );
		
		// Register RPC-result Callback
		mhqAdd( newBusProtocol->messageHandlerHandle, BPMSG_MSGID_GIVERPCRESULTS, rpcrRequestHandler, newBusProtocol->rpcrHandle );

		// Register Write electronic status callbac )
		bpecAttachWriteCallback(newBusProtocol, WriteElectricStatusCallback);
		
		// Open bus
		busInit(bus);
		
		// Create & start thread to poll bus
		newBusProtocol->bpthreadHandle = bpthreadStart( bus, deviceId, highestDeviceId, (int)newBusProtocol, newBusProtocol->messageHandlerHandle ); 
	}
	
	return (int)newBusProtocol;
}

/** \brief Closes the active BusProtocol
 * 
 * \post Protocol on this handle cannot be used anymore 
 * \param handle The handle for the BusProtocol (received with bpInit())
 */
void bpDeinit( int handle )
{
	// Stop & Destroy the bus poll thread
	
	// Close bus
	/* \todo busDeinit( (t_bp_admin *)handle)->bus ); */
	
	rpcDeinit( ((t_bp_admin *)handle)->rpcHandle );
	rpcrDeinit( ((t_bp_admin *)handle)->rpcrHandle );
	bpthreadStop( ((t_bp_admin *)handle)->bpthreadHandle );
	
	// Free BusProtocol-administration
	vPortFree( (void *)handle );
}


/** \brief Indicates whether a message a device is received in the last 10 seconds 
 * Only used by the master 
 */
BOOLEAN bpDeviceIsDetected( int handle, UINT8 deviceId )
{
	return bpthreadDeviceIsDetected(((t_bp_admin *)handle)->bpthreadHandle, deviceId);
}


/** \brief Sends message to pass turn (Nothing to send) 
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 */
void bpSendPassTurn( int handle )
{
	t_bpmsg_message sendPassTurnMessage;
	
	BP_DEBUG_OUT('p');BP_DEBUG_OUT('>');
	
	// Create new message
	sendPassTurnMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendPassTurnMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendPassTurnMessage.targetId = BPMSG_BROADCAST_ID;
	sendPassTurnMessage.packetNr = 0; // packetNr filled at transmitting time
	sendPassTurnMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendPassTurnMessage.messageId = BPMSG_MSGID_PASSTURN;
	sendPassTurnMessage.payloadSize = 0;
	sendPassTurnMessage.payload = NULL;
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendPassTurnMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendPassTurnMessage);
}

/** \brief Sends message to reset another bus device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param deviceId Identity of targeted bus device  (0xFF = all devices)
 */
void bpSendResetClient( int handle, UINT8 deviceId )
{
	t_bpmsg_message sendResetClientMessage;
	
	// Create new message
	sendResetClientMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendResetClientMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendResetClientMessage.targetId = deviceId;
	sendResetClientMessage.packetNr = 0; // packetNr filled at transmitting time
	sendResetClientMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendResetClientMessage.messageId = BPMSG_MSGID_RESETCLIENT;
	sendResetClientMessage.payloadSize = 0;
	sendResetClientMessage.payload = NULL;
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendResetClientMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendResetClientMessage);
}

/** \brief Sends message with all electronic information (DAC's, ADC's and digital I/O)
 * 
 * Broadcasts the electronic status of the device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param nrOfAdcValues Number of ADC-values included in the message
 * \param adcValues Pointer to a UINT16 array
 * \param nrOfDacValues Number of DAC-values included in the message
 * \param dacValues Pointer to a UINT16 array
 * \param nrOfDiValues Number of digital input values included in the message
 * \param diValues Digital input channel values (8 channels per byte)
 * \param nrOfDoValues Number of digital output values inculded in the message
 * \param doValues Digital output channel values (8 channels per byte)
 */
void bpSendGiveElectronicStatus( int handle, 
							     UINT8 nrOfAdcValues,
							     UINT16 *adcValues,
							     UINT8 nrOfDacValues,
							     UINT16 *dacValues,
							     UINT8 nrOfDiValues,
							     UINT8 *diValues,
							     UINT8 nrOfDoValues,
							     UINT8 *doValues
							   )
{
	t_bpmsg_message sendGiveElectronicStatusMessage;
	UINT8 *payload;
	UINT16 payloadSize;
	UINT8  payloadIndex = 0;
	UINT8  index;
	
	// Determine payload size
	payloadSize = BPMSG_UINT8_SIZE;
	payloadSize += nrOfAdcValues * BPMSG_UINT16_SIZE;
	payloadSize += BPMSG_UINT8_SIZE;
	payloadSize += nrOfDacValues * BPMSG_UINT16_SIZE;
	payloadSize += BPMSG_UINT8_SIZE;
	payloadSize += nrOfDiValues * BPMSG_UINT8_SIZE;
	payloadSize += BPMSG_UINT8_SIZE;
	payloadSize += nrOfDoValues * BPMSG_UINT8_SIZE;
	
	payload = (UINT8 *)Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;
	
	// Create new message
	sendGiveElectronicStatusMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendGiveElectronicStatusMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendGiveElectronicStatusMessage.targetId = BPMSG_BROADCAST_ID;
	sendGiveElectronicStatusMessage.packetNr = 0; // packetNr filled at transmitting time
	sendGiveElectronicStatusMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendGiveElectronicStatusMessage.messageId = BPMSG_MSGID_GIVEELECTRONICSTATUS;
	sendGiveElectronicStatusMessage.payloadSize = payloadSize;
	sendGiveElectronicStatusMessage.payload = payload;
	
	// Fill Payload
	payload[payloadIndex] = nrOfAdcValues;
	payloadIndex += BPMSG_UINT8_SIZE;
	for (index = 0; index < nrOfAdcValues; index++)
	{
		bpmsgAdd16bit( &payload[payloadIndex], adcValues[index]);
		payloadIndex += BPMSG_UINT16_SIZE;
	}
	
	payload[payloadIndex] = nrOfDacValues;
	payloadIndex += BPMSG_UINT8_SIZE;
	for (index = 0; index < nrOfDacValues; index++)
	{
		bpmsgAdd16bit( &payload[payloadIndex], dacValues[index]);
		payloadIndex += BPMSG_UINT16_SIZE;
	}

	payload[payloadIndex] = nrOfDiValues;
	payloadIndex += BPMSG_UINT8_SIZE;
	for (index = 0; index < nrOfDiValues; index++)
	{
		payload[payloadIndex] = diValues[index];
		payloadIndex += BPMSG_UINT8_SIZE;
	}

	payload[payloadIndex] = nrOfDoValues;
	payloadIndex += BPMSG_UINT8_SIZE;
	for (index = 0; index < nrOfDoValues; index++)
	{
		payload[payloadIndex] = doValues[index];
		payloadIndex += BPMSG_UINT8_SIZE;
	}

	// Calculate CRC
	bpmsgEncodeMessage(&sendGiveElectronicStatusMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendGiveElectronicStatusMessage);
}

/** \brief Sends message to set a DAC on another bus device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param deviceId Identity of targeted bus device 
 * \param channelNr Number of the DAC-channel
 * \param dacMode Voltage (0) / Ampere (<> 0)
 * \param davValue New DAC value (voltage: 0-10000mV, ampere: 0-20000uA)
 */
void bpSendSetDacValue( int handle, UINT8 deviceId, UINT8 channelNr, UINT8 dacMode, UINT16 dacValue )
{
	t_bpmsg_message sendSetDacMessage;
	UINT8 *payload = (UINT8 *) Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;

	BP_DEBUG_OUT('a');	BP_DEBUG_OUT('>');
	
	// Create new message
	sendSetDacMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendSetDacMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendSetDacMessage.targetId = deviceId;
	sendSetDacMessage.packetNr = 0; // packetNr filled at transmitting time
	sendSetDacMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendSetDacMessage.messageId = BPMSG_MSGID_SETDACVALUE;
	sendSetDacMessage.payloadSize = 4;
	sendSetDacMessage.payload = payload;
	
	// Fill Payload
	payload[0] = channelNr;
	payload[1] = dacMode;
	bpmsgAdd16bit( &payload[2], dacValue);
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendSetDacMessage);

	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendSetDacMessage);
}

/** \brief Sends message to set the values of all DAC's on another bus device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param deviceId Identity of targeted bus device 
 * \param davValue pointer to array with 4  DAC value, i.e. DAC-value position 0 for Channel 0 etc... (voltage: 0-10000mV, ampere: 0-20000uA)
 */
void bpSendSetAllDacValues( int handle, UINT8 deviceId, UINT16 *dacValue )
{
	t_bpmsg_message sendSetDacMessage;
	UINT8 *payload = (UINT8 *) Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;

	BP_DEBUG_OUT('a');	BP_DEBUG_OUT('>');
	
	// Create new message
	sendSetDacMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendSetDacMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendSetDacMessage.targetId = deviceId;
	sendSetDacMessage.packetNr = 0; // packetNr filled at transmitting time
	sendSetDacMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendSetDacMessage.messageId = BPMSG_MSGID_SETALLDACVALUES;
	sendSetDacMessage.payloadSize = 4 * 2;
	sendSetDacMessage.payload = payload;
	
	// Fill Payload
	bpmsgAdd16bit( &payload[0], dacValue[0]);
	bpmsgAdd16bit( &payload[2], dacValue[1]);
	bpmsgAdd16bit( &payload[4], dacValue[2]);
	bpmsgAdd16bit( &payload[6], dacValue[3]);
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendSetDacMessage);

	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendSetDacMessage);
}


/** \brief Sends message to set a digital out on another bus device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param bitNr Number of the digital output pin
 * \param value Low-level (0) or High-level (<> 0)
 */
void bpSendSetDigitalOutValue( int handle, UINT8 deviceId, UINT8 bitNr, UINT8 value )
{
	t_bpmsg_message sendSetDoMessage;
	UINT8 *payload = (UINT8 *)Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;
	
	BP_DEBUG_OUT('d');	BP_DEBUG_OUT('>');

	// Create new message
	sendSetDoMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendSetDoMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendSetDoMessage.targetId = deviceId;
	sendSetDoMessage.packetNr = 0; // packetNr filled at transmitting time
	sendSetDoMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendSetDoMessage.messageId = BPMSG_MSGID_SETDIGITALOUTVALUE;
	sendSetDoMessage.payloadSize = 2;
	sendSetDoMessage.payload = payload;

	// Fill Payload
	payload[0] = bitNr;
	payload[1] = value;
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendSetDoMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendSetDoMessage);
}

/** \brief Sends message to set all digital out ports at once  on another bus device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param deviceId The ID of the other bus device
 * \param bits All bitsNumber of the digital output pin
 */
void bpSendSetAllDigitalOut( int handle, UINT8 deviceId, UINT8 bits)
{
	t_bpmsg_message sendSetDoMessage;
	UINT8 *payload = (UINT8 *)Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;
	
	BP_DEBUG_OUT('d');	BP_DEBUG_OUT('>');

	// Create new message
	sendSetDoMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendSetDoMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendSetDoMessage.targetId = deviceId;
	sendSetDoMessage.packetNr = 0; // packetNr filled at transmitting time
	sendSetDoMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendSetDoMessage.messageId = BPMSG_MSGID_SETALLDIGITALOUT;
	sendSetDoMessage.payloadSize = 1;
	sendSetDoMessage.payload = payload;

	// Fill Payload
	payload[0] = bits;
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendSetDoMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendSetDoMessage);
}

/** \brief Sends message to set all outputs (analogue & digital)  on another bus device
* 
* \param handle The handle for the BusProtocol (received with bpInit())
* \param deviceId Identity of targeted bus device 
* \param bits All bitsNumber of the digital output pin
* \param davValue pointer to array with 4  DAC value, i.e. DAC-value position 0 for Channel 0 etc... (voltage: 0-10000mV, ampere: 0-20000uA)
*/
void bpSendSetAllOutput( int handle, UINT8 deviceId, UINT8 bits, UINT16 *dacValue )
{
	t_bpmsg_message sendSetAllOutpuntMessage;
	UINT8 *payload = (UINT8 *) Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;

	BP_DEBUG_OUT('a');	BP_DEBUG_OUT('o');	BP_DEBUG_OUT('>');
	
	// Create new message
	sendSetAllOutpuntMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendSetAllOutpuntMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendSetAllOutpuntMessage.targetId = deviceId;
	sendSetAllOutpuntMessage.packetNr = 0; // packetNr filled at transmitting time
	sendSetAllOutpuntMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendSetAllOutpuntMessage.messageId = BPMSG_MSGID_SETALLDOUTPUT;
	sendSetAllOutpuntMessage.payloadSize = (4 * 2) + 1;
	sendSetAllOutpuntMessage.payload = payload;
	
	// Fill Payload
	payload[0] = bits;
	bpmsgAdd16bit( &payload[1], dacValue[0]);
	bpmsgAdd16bit( &payload[3], dacValue[1]);
	bpmsgAdd16bit( &payload[5], dacValue[2]);
	bpmsgAdd16bit( &payload[7], dacValue[3]);
	
	// Calculate CRC
	bpmsgEncodeMessage(&sendSetAllOutpuntMessage);

	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendSetAllOutpuntMessage);
}


/** \brief Sends message to call an Remote Procedure Call on an other bus device
 * 
 * Request to execute a procedure on another device
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param deviceId Identity of targeted bus device
 * \param functionId Identity of the RPC-function
 * \param nrOfParams Number of parameters for the RPC-function
 * \param params Pointer to an array of 32-bit integers  
 */
void bpSendCallRpc( int handle, UINT8 deviceId, UINT8 functionId, UINT8 nrOfParams, INT32 *params )
{
	t_bpmsg_message sendCallRpcMessage;
	UINT8 *payload;
	UINT8  payloadSize;
	UINT8  payloadIndex = 0;
	UINT8  index;
	
	BP_DEBUG_OUT('c'); BP_DEBUG_OUT('>');
	
	// Determine payload size
	payloadSize = 3 * BPMSG_UINT8_SIZE;
	payloadSize += nrOfParams * BPMSG_UINT32_SIZE;
	
	payload =  (UINT8 *)Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;
	
	// Create new message
	sendCallRpcMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendCallRpcMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendCallRpcMessage.targetId = deviceId;
	sendCallRpcMessage.packetNr = 0; // packetNr filled at transmitting time
	sendCallRpcMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendCallRpcMessage.messageId = BPMSG_MSGID_CALLRPC;
	sendCallRpcMessage.payloadSize = payloadSize;
	sendCallRpcMessage.payload = payload;
	
	// Fill Payload
	payload[payloadIndex] = ((t_bp_admin *)handle)->rpcRequestNr;
	((t_bp_admin *)handle)->rpcRequestNr++;
	payloadIndex += BPMSG_UINT8_SIZE;

	payload[payloadIndex] = functionId;
	payloadIndex += BPMSG_UINT8_SIZE;

	payload[payloadIndex] = nrOfParams;
	payloadIndex += BPMSG_UINT8_SIZE;

	for (index = 0; index < nrOfParams; index++)
	{
		bpmsgAdd32bit( payload + payloadIndex, (UINT32)params[index]);
		payloadIndex += BPMSG_UINT32_SIZE;
	}
	

	// Calculate CRC
	bpmsgEncodeMessage(&sendCallRpcMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendCallRpcMessage);
}

/** \brief Sends message to give result on issued RPC-function 
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param nrOfResults Number of results to be send
 * \param results Pointer to array with results. 
 */
void bpSendRpcResult( int handle, UINT8 deviceId, UINT8 functionId, UINT8 requestNr, UINT8 nrOfResults, INT32 *results )
{
	t_bpmsg_message sendCallRpcResultMessage;
	UINT8 *payload;
	UINT8  payloadSize;
	UINT8  payloadIndex = 0;
	UINT8  index;
	
	BP_DEBUG_OUT('r'); BP_DEBUG_OUT('>');
	
	// Determine payload size
	payloadSize = 3 * BPMSG_UINT8_SIZE;
	payloadSize += nrOfResults * BPMSG_UINT32_SIZE;
	
	payload = (UINT8 *)Memmod_Alloc( bpMessagePool );
	if (payload == 0) return;
	
	// Create new message
	sendCallRpcResultMessage.uniqueStartByte = BPMSG_STARTBYTE;
	sendCallRpcResultMessage.senderId = ((t_bp_admin *)handle)->deviceId;
	sendCallRpcResultMessage.targetId = deviceId;
	sendCallRpcResultMessage.packetNr = 0; // packetNr filled at transmitting time
	sendCallRpcResultMessage.status = 0; // Clear status (filled by ProtocolThread)
	sendCallRpcResultMessage.messageId = BPMSG_MSGID_GIVERPCRESULTS;
	sendCallRpcResultMessage.payloadSize = payloadSize;
	sendCallRpcResultMessage.payload = payload;
	
	// Fill Payload
	payload[payloadIndex] = requestNr;
	payloadIndex += BPMSG_UINT8_SIZE;

	payload[payloadIndex] = functionId;
	payloadIndex += BPMSG_UINT8_SIZE;

	payload[payloadIndex] = nrOfResults;
	payloadIndex += BPMSG_UINT8_SIZE;

	for (index = 0; index < nrOfResults; index++)
	{
		bpmsgAdd32bit( &payload[payloadIndex], (UINT32)results[index]);
		payloadIndex += BPMSG_UINT32_SIZE;
	}

	// Calculate CRC
	bpmsgEncodeMessage(&sendCallRpcResultMessage);
	
	bpthreadAddMessage(((t_bp_admin *)handle)->bpthreadHandle, &sendCallRpcResultMessage);
}


/** \brief Attachs a callback, which is called when it is the device its turn to send data on the bus
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param onMyTurnCallback pointer to the callback function
 */
void bpAttachOnMyTurn( int handle, t_bp_myturn_callback onMyTurnCallback )
{
	t_bp_admin *bpAdmin = (t_bp_admin *)handle;

	bpthreadAttachMyTurn( bpAdmin->bpthreadHandle, onMyTurnCallback);
}

/** \brief Detaches the above callback
 * 
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param onMyTurnCallback pointer to the callback function
 */
void bpDetachOnMyTurn( int handle, t_bp_myturn_callback onMyTurnCallback )
{
	t_bp_admin *bpAdmin = (t_bp_admin *)handle;

	bpthreadDetachMyTurn( bpAdmin->bpthreadHandle, onMyTurnCallback);
}

/** \brief Attachs a RPC-function, which can be called by another bus device
 *  
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param functionId The identity of the RPC-function
 * \param functionPointer Pointer to actual RPC-function
 * \param nrOfParams Number of parameters, required by RPC
 */ 
void bpAttachRpc( int handle, UINT8 functionId, char * functionName, t_rpc_remote_procedure_call functionPointer, UINT8 nrOfParams )
{
	t_bp_admin *bpAdmin = (t_bp_admin *)handle;

	rpcAdd( bpAdmin->rpcHandle, functionId, functionName, functionPointer, nrOfParams);
}

/** \brief Detaches the above RPC-function
 * 
 * \post RPC-function is not supported anymore
 * \param handle The handle for the BusProtocol (received with bpInit())
 * \param functionId Identity of the detached RPC-function
 */
void bpDetachRpc( int handle, UINT8 functionId )
{
	t_bp_admin *bpAdmin = (t_bp_admin *)handle;
	
	rpcRemove( bpAdmin->rpcHandle, functionId );
}

/** \brief Attachs a "RPC result"-function, which is a result of a requeste RPC-call  on another bus device
 * 
 * \param handle The handle for the BusProtocol (returned by bpInit())
 * \param functionId The functionId on which the result should be catched
 * \param functionPointer The funtion which must be called when a RPC-result is received.
 */
void bpAttachRpcResult( int handle, UINT8 functionId, t_bp_rpcresult_callback functionPointer, UINT8 nrOfResults )
{
    t_bp_admin *bpAdmin = (t_bp_admin *)handle;

    rpcrAdd( bpAdmin->rpcrHandle, functionId, functionPointer, nrOfResults);
}

/** \brief Detaches the above "RPC result"-function 
 *
 * \param handle The handle for the BusProtocol (returned by bpInit())
 * \param functionId The functionId on which the result should be catched
 */
void bpDetachRpcResult( int handle, UINT8 functionId )
{
    t_bp_admin *bpAdmin = (t_bp_admin *)handle;

    rpcrRemove( bpAdmin->rpcrHandle, functionId );
}


t_rpc_entity *bpLookupRpcEntry( int handle, UINT8 functionId )
{
    t_bp_admin *bpAdmin = (t_bp_admin *)handle;

    return rpcLookupEntry( bpAdmin->rpcHandle, functionId );
}

void WriteElectricStatusCallback( int handle, BOOLEAN isDigital, UINT8 device, UINT8 channel, UINT16 value )
{
	if (isDigital)
		{
		bpSendSetDigitalOutValue( handle, device, channel, (BOOLEAN)value )	;	
		}
	else
		{
		bpSendSetDacValue( handle, device, channel, 0, value );
		}
}

