/*
 * xlru_interface.cpp
 *
 */


#include "xlru_manager.h"

#include "xlru_comm.h"

#include "xlru_lcu.h"
#include "xlru_pps.h"
#include "xlru_psm.h"
#include "xlru_message_mng.h"

#include "mrk.h"
#include "mrk_net.h"

#include "bsp_platform.h"

#include "rtlog.h"

#include <string.h>
#include <stdint.h>

#define THREAD_STACK	(8*1024)

static const char LID[]="XLRU";

#if 0
struct xlru_if_msg_t
{

};


//typedef int (*xlru_command_message_encoder_t)(unsigned char* buffer, const void* opaque_data);
//extern int xlru_lcu_command_message_encoder(unsigned char* buffer, const void* opaque_data);
//extern int xlru_pps_command_message_encoder(unsigned char* buffer, const void* opaque_data);
//extern int xlru_psm_command_message_encoder(unsigned char* buffer, const void* opaque_data);

struct xlru_lcu_command_t
{
	int mode;
};

struct xlru_psm_command_t
{
	int mode;
};

struct xlru_pps_command_t
{
	int mode;
};
#endif

//-

typedef int (*xlru_command_encoder_t)(unsigned int);
typedef int (*xlru_reply_decoder_t)(unsigned int, const char* msg, unsigned int len);

//static int dummy_command_encoder(unsigned int uid);
static int psm_command_encoder(unsigned int u);
static int lcu_command_encoder(unsigned int u);
static int pps_command_encoder(unsigned int u);

struct xlru_unit_sts_t
{
	XLruManager::unit_status_t* public_sts;
#if 0
	//TODO: extend with more detail for field messages
	unsigned int comm_fail;

	unsigned int good_message;
	unsigned int fail_message;

	unsigned int pending_msg;
#endif
};

enum xlru_units_t { xlru_id_broadcast=0, xlru_id_psm, xlru_id_lcu, xlru_id_pps, xlru_id_number_};
enum { xlru_number_=3};

enum xlru_id_t { DEVICE_PSM=1, DEVICE_PPS=2, DEVICE_LCU=3};

struct xlru_cx_t
{
	uint64_t stack[THREAD_STACK/sizeof(uint64_t)];

    mrk_thread_t thread;
    mrk_mutex_t  mutex;

    char psm_message[1024];
    char pps_message[1024];
    char lcu_message[1024];

    //xlru_psm_command_t psm_cmd;
    //xlru_pps_command_t pps_cmd;
    //xlru_lcu_command_t lcu_cmd;

    xlru_unit_sts_t sts[xlru_id_number_];

    XLruManager::unit_status_t invalid_unit_status;

    XLruManager::psm_status_t psm_status;
    XLruManager::pps_status_t pps_status;
    XLruManager::lcu_status_t lcu_status;

    XLruManager::manager_status_t status;

    int psm_temperature;
    int pps_temperature;
    int lcu_temperature;

    volatile int pps_cmd;
    volatile int pps_unlimited;
    volatile int pps_hazard;
};

struct xlru_ovr_t
{
    int pps_cmd_ovr;
    int pps_unlimited;
    int pps_hazard;
};

static volatile xlru_ovr_t autoMonitorable_xlruovr;

static xlru_cx_t xlru_cx;

static int common_reply_decoder(unsigned int, const char* msg, unsigned int len);

struct xlru_unit_map_t
{
	const char* name;
	unsigned int chid;
	unsigned int uid;
	const char* cmd_buffer;

	xlru_command_encoder_t encoder;
	//xlru_reply_decoder_t reply_decoder;
	int (*reply_decoder)(const xlru_message_received_t& rx_msg);

	const char* sim_reply;
};

#ifdef __MINGW32__
enum { null_ch=0, psm_ch = 0, pps_ch = 0, lcu_ch = 0, ch_num=4 };

#define UDP_START_DELAY	-1

#else
enum { null_ch=0, psm_ch = 1, pps_ch = 3, lcu_ch = 3, ch_num=4};	//REP ZynQ PL FPGA UART: Uart 1 = PSM, Uart 3 = PPS, LCU

#define UDP_START_DELAY	5

#endif

static int psm_reply_decoder(const xlru_message_received_t& rx_msg);
static int pps_reply_decoder(const xlru_message_received_t& rx_msg);
static int lcu_reply_decoder(const xlru_message_received_t& rx_msg);

static xlru_unit_map_t xlru_unit_map[xlru_number_]=
{
		{"PSM", psm_ch, DEVICE_PSM, xlru_cx.psm_message, psm_command_encoder, psm_reply_decoder, 0},
		{"PPS", pps_ch, DEVICE_PPS, xlru_cx.pps_message, pps_command_encoder, pps_reply_decoder, 0},
		{"LCU", lcu_ch, DEVICE_LCU, xlru_cx.lcu_message, lcu_command_encoder, lcu_reply_decoder, 0}
};

#if 0
static int dummy_command_encoder(unsigned int u)
{
	//xlru_unit_map[u].cmd_buffer="CIAO0\n";
	return 0;
}
#endif

static int psm_command_encoder(unsigned int u)
{
	xlru_unit_map[u].cmd_buffer=xlru_send_psm_set_message(); //xlru_unit_map[u].cmd_buffer;
	return 0;
}

static int lcu_command_encoder(unsigned int u)
{
	xlru_unit_map[u].cmd_buffer=xlru_send_lcu_set_message();
	return 0;
}

static int pps_command_encoder(unsigned int u)
{
	xlru_unit_map[u].cmd_buffer=xlru_send_pps_set_message();
	return 0;
}

static void copy_status(XLruManager::unit_basic_status_t& dst, const xlru_unit_status_t& src)
{
	dst.unitOk=src.unitOk;
	dst.overtempWarning=src.overtempWarning;
	dst.overtempHazard=src.overtempHazard;
}

static int psm_reply_decoder(const xlru_message_received_t& rx_msg)
{
	if (rx_msg.valid)
	{
		copy_status(xlru_cx.psm_status.status.basicStatus, xlru_psm::xlru_psm_status.status);
		xlru_cx.psm_temperature=xlru_psm::xlru_psm_status.temperature;
		return 0;
	}
	return 1;
}

static int pps_reply_decoder(const xlru_message_received_t& rx_msg)
{
	if (rx_msg.valid)
	{
		copy_status(xlru_cx.pps_status.status.basicStatus, xlru_pps::xlru_pps_status.status);
		xlru_cx.pps_temperature=xlru_pps::xlru_pps_status.rx_board_temp;
		switch(xlru_pps::xlru_pps_status.mode_status)
		{
		default:
			xlru_cx.pps_status.power_sts=XLruManager::pps_power_err;
			xlru_cx.pps_status.power_sts_char='E';
			break;
		case PPSIdle:
			xlru_cx.pps_status.power_sts=XLruManager::pps_power_idle;
			xlru_cx.pps_status.power_sts_char='I';
			break;
		case PPSIBIT:
			xlru_cx.pps_status.power_sts=XLruManager::pps_power_idle;
			xlru_cx.pps_status.power_sts_char='B';
			break;
		case PPSStandBy:
			xlru_cx.pps_status.power_sts=XLruManager::pps_power_stby;
			xlru_cx.pps_status.power_sts_char='S';
			break;
		case PPSOnGo:
			if (xlru_pps::xlru_pps_status.current_limitation_status==PPSCurrentLimitation)
			{
				xlru_cx.pps_status.power_sts=XLruManager::pps_power_low;
				xlru_cx.pps_status.power_sts_char='g';
			}
			else
			{
				xlru_cx.pps_status.power_sts=XLruManager::pps_power_full;
				xlru_cx.pps_status.power_sts_char='G';
			}
			break;
		}
		xlru_cx.pps_status.warning=xlru_pps::xlru_pps_status.warning;
		xlru_cx.pps_status.txPower=0;
		xlru_cx.pps_status.rxPower=xlru_pps::xlru_pps_status.curr_42v;
		return 0;
	}
	return 1;
}

static int lcu_reply_decoder(const xlru_message_received_t& rx_msg)
{
	if (rx_msg.valid)
	{
		copy_status(xlru_cx.lcu_status.status.basicStatus, xlru_lcu::xlru_lcu_status.status);
		return 0;
	}
	return 1;
}


static int common_reply_decoder(unsigned int pending_unit, const char* msg, unsigned int /*len*/)
{
	static xlru_message_received_t message_received;
	strncpy(message_received.full_message, msg, sizeof message_received.full_message);


	int r=xlru_check_message(&message_received);
	if (r)
	{
		++xlru_cx.status.error_messages;
		return -1;
	}

	unsigned int device_id=message_received.device;
	switch(device_id)
	{
	case DEVICE_PSM:
	case DEVICE_PPS:
	case DEVICE_LCU:
		{
			XLruManager::unit_status_t& plrusts=*xlru_cx.sts[device_id].public_sts;

			if (message_received.valid)
				++plrusts.commStatus.good_messages;
			else
				++plrusts.commStatus.error_messages;

			plrusts.commStatus.reply_pending=0;
			plrusts.commStatus.linkUp=true;
			plrusts.commStatus.commDeviceOk=true;
			xlru_unit_map_t& u=xlru_unit_map[device_id-1];
			r=u.reply_decoder(message_received);
			//if (r)
			//	plrusts.basicStatus.unitOk=false;

			if (pending_unit!=device_id)
			{
				++plrusts.commStatus.reply_overlap;
				++xlru_cx.status.received_overlapping;
			}

			break;
		}
	default:
		{
			XLruManager::unit_status_t& plrusts=*xlru_cx.sts[0].public_sts;
			plrusts.commStatus.reply_pending=0;
			++xlru_cx.status.received_invalid_unit;
			r=-1;
			break;
		}
	}
	return r;
}


static bool receive(unsigned int chid, char* buffer, unsigned int& received_len)
{
	const unsigned int max_len=1024;
	received_len=0;

	xlru_comm_sts_t r=xlru_comm_extract_pending_data(chid, buffer, &received_len, max_len);
	if (r==xlru_comm_ok)
	{
		if (received_len>=max_len)
			received_len=max_len-1;
		buffer[received_len]=0;
		return true;
	}
	else
	{
		if (r==xlru_comm_err_overrun)
			++xlru_cx.status.overruns;
		else
			++xlru_cx.status.biterror;

		rtlog_printf(LID, rtlog_error, "rx(%d): %d (%s)", chid, r, xlru_comm_error_string(r));
	}
	return false;
}

static void (*oob_handler)(char c);

class Accumulator
{
public:
	enum { MAX_PENDING_SIZE=256 };

	char pending_message[MAX_PENDING_SIZE+2];
	unsigned int pending_pos;
	unsigned int pending_len;

	void initialize()
	{
		pending_pos=0;
		pending_len=0;
	}

	bool accumulate(const char* buffer, unsigned int len)
	{
		for(unsigned int i=0; i<len; ++i)
		{
			++xlru_cx.status.received_bytes;

			char c=buffer[i];

			if ((c=='\n') || (c=='\r'))
			{
				if (pending_pos>0)
				{
					pending_message[pending_pos]='\r';
					pending_len=pending_pos+1;
					pending_message[pending_len+1]=0;
					pending_pos=0;
					++xlru_cx.status.received_messages;
					return true;
				}
				else
				{
					++xlru_cx.status.received_oob;
					++xlru_cx.status.received_garbage;
					if (oob_handler)
						oob_handler(c);
					continue;

				}
			}
			if (((c<' ') || (c>'}')))// && (c!='\0'))
			{
				if (pending_pos)
					++xlru_cx.status.error_messages;
				pending_pos=0;
				++xlru_cx.status.received_garbage;
			}
			else if (c=='!')
			{
				if (pending_pos>0)
					++xlru_cx.status.error_messages;
				pending_pos=1;
				pending_message[0]=c;
			}
			else
			{
				if (pending_pos>0)
				{
						if (pending_pos>=MAX_PENDING_SIZE)  //overflow
						{
							pending_pos=0;
						}
						else
						{
							pending_message[pending_pos]=c;
							++pending_pos;
						}
				}
				else
				{
					++xlru_cx.status.received_oob;
					++xlru_cx.status.received_garbage;

					if (oob_handler)
						oob_handler(c);
				}
			}
		}
		return false;
	}
};

static Accumulator accumulators[ch_num];
#if 0
#define MAX_PENDING_BUFFER	1024

static char pending_message[MAX_PENDING_BUFFER+2];
static unsigned int pending_pos=0;
static unsigned int pending_len=0;


static bool accumulate(const char* buffer, unsigned int len)
{
	for(unsigned int i=0; i<len; ++i)
	{
		++xlru_cx.status.received_bytes;

		char c=buffer[i];

		if ((c=='\n') || (c=='\r'))
		{
			if (pending_pos>0)
			{
				pending_message[pending_pos]='\r';
				pending_len=pending_pos+1;
				pending_message[pending_len+1]=0;
				pending_pos=0;
				++xlru_cx.status.received_messages;
				return true;
			}
			else
			{
				++xlru_cx.status.received_oob;
				++xlru_cx.status.received_garbage;
				if (oob_handler)
					oob_handler(c);
				continue;

			}
		}

		if (((c<' ') || (c>'}')))// && (c!='\0'))
		{
			if (pending_pos)
				++xlru_cx.status.error_messages;
			pending_pos=0;
			++xlru_cx.status.received_garbage;
		}
		else if (c=='!')
		{
			if (pending_pos>0)
				++xlru_cx.status.error_messages;
			pending_pos=1;
			pending_message[0]=c;
		}
		else
		{
			if (pending_pos>0)
			{
					if (pending_pos>=MAX_PENDING_BUFFER)  //overflow
					{
						pending_pos=0;
					}
					else
					{
						pending_message[pending_pos]=c;
						++pending_pos;
					}
			}
			else
			{
				++xlru_cx.status.received_oob;
				++xlru_cx.status.received_garbage;

				if (oob_handler)
					oob_handler(c);
			}
		}
	}
	return false;
}
#endif

static char oob_data[128];
static volatile unsigned int oob_counter;

static int udp_start_delay=UDP_START_DELAY;

#define PANIC_STRING "PANIC!"

static void xlru_exec()
{
	static char buffer[1024];
	static mrk_net_udp_socket_t panic_socket;
	static char panic_message[32];
	const unsigned int panic_port=60000;
	const bool panic_enabled=true;
	unsigned int unit_scheduler=0;

	const unsigned int major_frame_ms=1000;	//1second
	const unsigned int minor_frame_time_ms=major_frame_ms/xlru_number_;
	const unsigned int rx_poll_ms=10;
	unsigned int minor_frame_poll_cycles=minor_frame_time_ms/rx_poll_ms;

	rtlog_const_message(LID, rtlog_info|rtlog_breaking_news, "XLRU Manager started");

	if (bsp_is_evm())
	{
		for(int i=0; i<xlru_number_; ++i)
			xlru_unit_map[i].chid=null_ch;
	}

	xlru_comm_initialize();

	static unsigned int pending_ch=0;
	static unsigned int pending_unit=0;

	XLruManager::psmFastEnable(true);
	XLruManager::psmPowerDown(false);
	XLruManager::lcuHeaterOn(false);
	XLruManager::lcuExecuteInterruptiveBit(false);
	XLruManager::lcuReset(false);

	xlru_pps::set_pps_radome_bounce(1); //Limit current by default
	xlru_pps::set_pps_hazard_override(0);
	xlru_pps::set_pps_operative_cmd(0);

	xlru_cx.pps_cmd=0;
	xlru_cx.pps_hazard=0;
	xlru_cx.pps_unlimited=0;

	xlru_unit_map[0].sim_reply="!1n+SGNcwANNNNNNN0E002100330096FF6C300002038901000008000140__47\r";
	xlru_unit_map[1].sim_reply="!2a-SBNCwABNNUNUU000021002B0071FF82EE000102081234000208__66\r";
	xlru_unit_map[2].sim_reply="!3mTsPI_FH____4610823F00228000808080808080__1E0BFF__0101____F5\r";

	mrk_net_udp_socket(&panic_socket, "XLRU-Panic");
	mrk_net_udp_bind(&panic_socket, 0, panic_port);

	mrk_net_udp_set_capacity(&panic_socket, 1);

	unsigned int panic_counter=0;

	for(;;)
	{
#ifdef __MINGW32__
//			mrk_thread_sleep_ms(rx_poll_ms);
		minor_frame_poll_cycles=minor_frame_poll_cycles/4;
		if (minor_frame_poll_cycles<4)
			minor_frame_poll_cycles=4;
#endif

		//XLruManager::unit_status_t& plrusts=*xlru_cx.sts[pending_unit].public_sts;

		if (panic_enabled)
		{
			mrk_net_ip_raw_address_t remote_address=0;
			unsigned short remote_port=panic_port;
			unsigned int received_len=0;
			mrk_net_result_t r=mrk_net_udp_receive(&panic_socket, &panic_message, sizeof panic_message, &remote_address, &remote_port, &received_len, 0);
			if (r==mrk_net_ok)
			{
				if (strncmp(PANIC_STRING, panic_message, sizeof(PANIC_STRING))==0)
				{
					++panic_counter;
					rtlog_printf("PANIC", rtlog_error|rtlog_breaking_news, "PANIC %u", panic_counter);
					if (panic_counter>1)
					{
						//XLruManager::psmRecycle(true);
					}
				}
			}

			if (panic_counter>1)
			{
				rtlog_printf("PANIC", rtlog_error|rtlog_breaking_news, "PANIC %u", panic_counter);
				++panic_counter;
				if (panic_counter>4)
				{
					rtlog_const_message("PANIC", rtlog_fatal|rtlog_breaking_news, "PANIC! PANIC! PANIC! Trying recycle...");
					XLruManager::psmRecycle(true);
				}
			}
		}

		if (autoMonitorable_xlruovr.pps_cmd_ovr)
			xlru_pps::set_pps_operative_cmd(autoMonitorable_xlruovr.pps_cmd_ovr-1);
		else
			xlru_pps::set_pps_operative_cmd(xlru_cx.pps_cmd);

		if (autoMonitorable_xlruovr.pps_unlimited)
			xlru_pps::set_pps_radome_bounce(autoMonitorable_xlruovr.pps_unlimited==1 ? 0 : 1); //Limit current by default
		else
			xlru_pps::set_pps_radome_bounce(1); //TODO: remove protection -> xlru_cx.pps_unlimited ? 0 : 1); //Limit current by default

		if (autoMonitorable_xlruovr.pps_hazard)
			xlru_pps::set_pps_hazard_override(1);
		else
			xlru_pps::set_pps_hazard_override(0);

		for(unsigned int poll_cycles=0; poll_cycles<minor_frame_poll_cycles; ++poll_cycles)
		{
			unsigned int received_len=0;
#ifndef __MINGW32__
			mrk_thread_sleep_ms(rx_poll_ms);
#else
			mrk_thread_sleep_ms(rx_poll_ms*2);
#endif

			if (oob_counter)
			{
				xlru_comm_raw_transmit(1, oob_data, oob_counter);
				oob_counter=0;
			}

			if (pending_ch<1)
				continue;

			bool ok=receive(pending_ch, buffer, received_len);
#if 0
			if (pending_unit==1)
			{
				strcpy(buffer, xlru_unit_map[pending_unit-1].sim_reply);
				received_len=strlen(buffer);
				ok=true;
			}
#endif

#if 1
			Accumulator* acc=&accumulators[pending_ch];

			if ((!ok || (received_len<=0)) && (poll_cycles==0))
			{
				received_len=0;
				ok=xlru_comm_dbg_get_data(buffer, &received_len, sizeof buffer);
				acc=&accumulators[0];
			}

			if (ok && (received_len>0))
			{
				ok=acc->accumulate(buffer, received_len);
				if (ok)
				{
					const char* current_message=acc->pending_message;
					unsigned int current_len=acc->pending_len;

					xlru_comm_dbg_add_data(1, current_message, current_len);

					//const xlru_unit_map_t& lru=xlru_unit_map[pending_unit];

					common_reply_decoder(pending_unit, current_message, current_len);//lru.reply_decoder(pending_unit, current_message, current_len);
				}
			}
#else
			if (ok && (received_len>0))
			{

				ok=accumulate(buffer, received_len);
				//TODO: Decode the message
				if (ok)
				{
					xlru_comm_dbg_add_data(1, pending_message, pending_len);
					const char* current_message=pending_message;
					unsigned int current_len=pending_len;
					//const xlru_unit_map_t& lru=xlru_unit_map[pending_unit];

					common_reply_decoder(pending_unit, current_message, current_len);//lru.reply_decoder(pending_unit, current_message, current_len);

					//plrusts.commStatus.reply_pending=0;
				}
			}
#endif
		}

		//TX frame:
		{
			if (unit_scheduler==0)
				xlru_comm_dbg_flush();

			const xlru_unit_map_t& lru=xlru_unit_map[unit_scheduler];
			xlru_unit_sts_t& lrusts=xlru_cx.sts[lru.uid];

			int r=lru.encoder(unit_scheduler);

			xlru_comm_sts_t txres=xlru_comm_ok;
			if (lru.chid>=1)
			{
				if (r==0)
				{
					if (lrusts.public_sts->commStatus.reply_pending>0)
					{
						++lrusts.public_sts->commStatus.reply_missed;
						if (lrusts.public_sts->commStatus.reply_pending>3)
						{
							lrusts.public_sts->commStatus.linkUp=false;
							lrusts.public_sts->basicStatus.unitOk=false;
						}
					}

					unsigned int len=strlen(lru.cmd_buffer);
					//rtlog_printf(LID, rtlog_info|rtlog_breaking_news, "TX: %s", lru.cmd_buffer);
					txres=xlru_comm_raw_transmit(lru.chid, lru.cmd_buffer, len);
					xlru_comm_dbg_add_data(lru.chid, lru.cmd_buffer, len);

					if (lrusts.public_sts->commStatus.reply_pending<1000) //do not let the counter overflow
						++lrusts.public_sts->commStatus.reply_pending;

					++lrusts.public_sts->commStatus.sent_messages;

					++xlru_cx.status.poroduce_messages;

					if (txres==0)
						++xlru_cx.status.transmitted_bytes+=len;
					txres=xlru_comm_ok;

					//if (lru.sim_reply)
					//	xlru_comm_raw_transmit(lru.chid, lru.sim_reply, 0);
				}
				rtlog_severity_t severity=(r || txres) ? rtlog_error | rtlog_breaking_news : rtlog_info;

				rtlog_printf(LID, severity, "tx(%s): %d (%s)", lru.name, txres, xlru_comm_error_string(txres));
			}
			pending_ch=lru.chid;
			pending_unit=lru.uid;
		}

		++unit_scheduler;

		if (unit_scheduler>=xlru_number_)
		{
			unit_scheduler=0;
			if (udp_start_delay>=0)
			{
				if (udp_start_delay==0)
				{
					xlru_comm_udp_monitor_enable(true);
				}
				--udp_start_delay;
			}
		}
	}
}


static void xlru_manager_mex_extension();

//External I/F
static bool manager_started;

void xlru_channel_map(unsigned int psm, unsigned int pps, unsigned int lcu)
{
	xlru_unit_map[0].chid=psm;
	xlru_unit_map[1].chid=pps;
	xlru_unit_map[2].chid=lcu;

	if (!manager_started)
		XLruManager::start();
}

bool XLruManager::start()
{
	xlru_cx.sts[0].public_sts=&xlru_cx.invalid_unit_status;

	xlru_cx.sts[1].public_sts=&xlru_cx.psm_status.status;
	xlru_cx.sts[2].public_sts=&xlru_cx.pps_status.status;
	xlru_cx.sts[3].public_sts=&xlru_cx.lcu_status.status;

	if (manager_started)
		return true;
	manager_started=true;

	mrk_mutex_create(&xlru_cx.mutex, "XLRU");
    mrk_thread_create(&xlru_cx.thread, "XLRU", xlru_exec, 0, mrk_std_priority_above_normal, sizeof xlru_cx.stack, xlru_cx.stack, 0);

    xlru_manager_mex_extension();

    return true;
}

XLruManager::manager_status_t& XLruManager::managerStatus()
{
	return xlru_cx.status;
}


void XLruManager::emergyEnable(bool enable)
{
	psmEmergency(enable);
	xlru_cx.pps_hazard=enable ? 1 : 0;
	//xlru_pps::set_pps_hazard_override(enable ? 1 : 0);
}

//PSM
XLruManager::psm_status_t& XLruManager::psmStatus()
{
	static XLruManager::psm_status_t sts;
	mrk_mutex_acquire(&xlru_cx.mutex, mrk_wait_forever);
	sts=xlru_cx.psm_status;
	mrk_mutex_release(&xlru_cx.mutex);
	return sts;
}

float XLruManager::psmTemperature()
{
	return xlru_cx.psm_temperature;
}

void XLruManager::psmPowerDown(bool enable)
{
	xlru_psm::set_psm_cmd_id(enable ? 0 : 2);
}

void XLruManager::psmRecycle(bool enable)
{
	xlru_psm::set_psm_cmd_id(enable ? 1 : 2);
}

void XLruManager::psmEmergency(bool enable)
{
	xlru_psm::set_psm_emergency(enable ? 1 : 2);
}

void XLruManager::psmFastEnable(bool enable)
{
	xlru_psm::set_psm_fast_cmd(enable ? 0 : 1);
}

//PPS
void XLruManager::ppsPowerOuputEnable(bool enable)
{
	xlru_cx.pps_cmd=enable ? 1 : 0; //xlru_pps::set_pps_operative_cmd(enable ? 1 : 0);
}

void XLruManager::ppsPowerLimitationEnable(bool enable)
{
	xlru_cx.pps_unlimited=enable ? 0 : 1; //xlru_pps::set_pps_radome_bounce(enable ? 1 : 0);
}
XLruManager::pps_status_t& XLruManager::ppsStatus()
{
	static XLruManager::pps_status_t sts;
	mrk_mutex_acquire(&xlru_cx.mutex, mrk_wait_forever);
	sts=xlru_cx.pps_status;
	mrk_mutex_release(&xlru_cx.mutex);
	return sts;
}

float XLruManager::ppsTemperature()
{
	return xlru_cx.pps_temperature;
}
//LCU:
XLruManager::lcu_status_t& XLruManager::lcuStatus()
{
	static XLruManager::lcu_status_t sts;
	mrk_mutex_acquire(&xlru_cx.mutex, mrk_wait_forever);
	sts=xlru_cx.lcu_status;
	mrk_mutex_release(&xlru_cx.mutex);
	return sts;
}

float XLruManager::lcuTemperature()
{
	return xlru_cx.lcu_temperature;
}

void XLruManager::lcuHeaterOn(bool enable)
{
	xlru_lcu::set_lcu_heater(enable);
}

void XLruManager::lcuExecuteInterruptiveBit(bool enable)
{
	xlru_lcu::set_lcu_ibit(enable);
}

void XLruManager::lcuReset(bool enable)
{
	xlru_lcu::set_lcu_restart(enable);
}


void XLruManager::setOutOfBandDataHandler(void (*handler)(char c))
{
	oob_handler=handler;
}

void XLruManager::injectOutofBandData(char c)
{
	if (oob_counter>=sizeof(oob_data))
		return;
	oob_data[oob_counter]=c;
	++oob_counter;
}

//
extern void xlru_mex_initialize();

static void xlru_manager_mex_extension()
{
	xlru_mex_initialize();
}


