/* * 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 #include #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; i0) { 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; i0) { 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; i1) { //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_cycles0)) { 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(); }