/************************************************************************ Maximus.cpp - Copyright buret Here you can write a license for your code, some comments or any other information you want to have in your generated code. To to this simply configure the "headings" directory in uml to point to a directory where you have your heading files. or you can just replace the contents of this file with your own. If you want to do this, this file is located at /usr/share/apps/umbrello/headings/heading.cpp -->Code Generators searches for heading files based on the file extension i.e. it will look for a file name ending in ".h" to include in C++ header files, and for a file name ending in ".java" to include in all generated java code. If you name the file "heading.", Code Generator will always choose this file even if there are other files with the same extension in the directory. If you name the file something else, it must be the only one with that extension in the directory to guarantee that Code Generator will choose it. you can use variables in your heading files which are replaced at generation time. possible variables are : author, date, time, filename and filepath. just write %variable_name% This file was generated on %date% at %time% The original location of this file is /home/buret/eclipse/maximus/coreengine/src/Maximus.cpp **************************************************************************/ #include "Maximus.h" #include "Sta.h" #include "Msg.h" #include "CoreEngine.h" #include "ISystem.h" #include "IFunctionCall.h" #include "INetworkClock.h" #include "ISci.h" #include "IChannel.h" #include "PhySciMsgMpdu.h" #include "ChannelSettings.h" #include "Error.h" #include "Logger.h" #include // for 'remove()' #include // for 'cout', 'cerr' and 'clog' #include // for 'ifstream' #include // for 'getopt_long()' #include // for 'signal()', 'SIGINT', 'raise()', 'SIGTERM' #include // for 'min()' using namespace std; // For unitary tests bool UNITTEST = false; string stationTest; // For Maximus log Logger logger(LOG_WARNING); // To catch signals Maximus * pMaximus; // Constructors/Destructors // Maximus::Maximus ( ): mpCoreEngine(NULL), mMaxTickValue(0), mWaitTickValue(0), mIsWireshark(false), mEtherLogFileDescriptor(-1) { logFunction(); try { if (UNITTEST) { // For unitary tests log logger.setLogLevel(LOG_DEBUG); } mpCoreEngine = new CoreEngine(); } catchFunction(this); } Maximus::Maximus ( CoreEngine * p_core_engine ): mpCoreEngine(NULL), mMaxTickValue(0), mWaitTickValue(0) { logFunction(); try { if (UNITTEST) { // For unitary tests log logger.setLogLevel(LOG_DEBUG); mpCoreEngine = p_core_engine; } else { errno = EBADRQC; throw Error(__PRETTY_FUNCTION__, "FOR UNITARY TESTS ONLY", errno); } } catchFunction(this); } Maximus::~Maximus ( ) { logFunction(); stop(); } // // Methods // // public methods void Maximus::init ( int argc, char * argv[] ) { logFunction(); try { // To catch signals pMaximus = this; signal(SIGINT, Maximus::wrapper); struct option longOptions[] = { {"station-executable", required_argument, 0, 'e'}, {"station-log", required_argument, 0, 's'}, {"maximus-log", required_argument, 0, 'm'}, {"log-level", required_argument, 0, 'l'}, {"max-tick-value", required_argument, 0, 't'}, {"debugger", required_argument, 0, 'd'}, {"frequency", required_argument, 0, 'f'}, {"wireshark", required_argument, 0, 'w'} }; int optionIndex = 0; int optionChar = 0; // Station executable string stationExecutable; bool isStationExecutableSet = false; // Station log string stationLog("-"); // Maximus log string maximusLog("maximus_log"); // Log level int logLevel = LOG_WARNING; // Debugger string debugger("xterm -title '\"%n\" debug' -e gdb %e %p & sleep 1"); // Frequency float frequency = 50; // in Hz // Wireshark string wireshark; while (EOF != optionChar) { optionChar = getopt_long(argc, argv, "e:s:m:l:t:d:f:w:", longOptions, &optionIndex); switch (optionChar) { case 'e': clog << logger(LOG_INFO) << "station executable = " << optarg << endl; stationExecutable = optarg; isStationExecutableSet = true; break; case 's': clog << logger(LOG_INFO) << "station log = " << optarg << endl; stationLog = optarg; break; case 'm': clog << logger(LOG_INFO) << "maximus log = " << optarg << endl; maximusLog = optarg; break; case 'l': clog << logger(LOG_INFO) << "log level = " << optarg << endl; if ((LOG_DEBUG <= atoi(optarg)) && (LOG_NONE >= atoi(optarg))) { logLevel = atoi(optarg); } else { clog << logger(LOG_ERROR) << "usage: -l log_level with log_level in range from 0 to 6!" << endl; clog << logger(LOG_ERROR) << "user value is not taken into account => apply default value!" << endl; } break; case 't': clog << logger(LOG_INFO) << "max tick value = " << optarg << endl; setMaxTickValue(atoi(optarg)); break; case 'd': clog << logger(LOG_INFO) << "debugger = " << optarg << endl; debugger = optarg; break; case 'f': clog << logger(LOG_INFO) << "frequency = " << optarg << endl; if ((50 == atof(optarg)) || (60 == atof(optarg)) || (0 == atof(optarg))) { frequency = atof(optarg); } else { clog << logger(LOG_ERROR) << "usage: -f frequency with frequency 50 or 60 Hz, or 0!" << endl; clog << logger(LOG_ERROR) << "user value is not taken into account => apply default value (50 Hz)!" << endl; } break; case 'w': clog << logger(LOG_INFO) << "wireshark = " << optarg << endl; wireshark = optarg; if ( (0 == wireshark.compare("on")) || (0 == wireshark.compare("On")) || (0 == wireshark.compare("ON")) ) { mIsWireshark = true; } else if ( (0 == wireshark.compare("off")) || (0 == wireshark.compare("Off")) || (0 == wireshark.compare("OFF")) ) { mIsWireshark = false; } else { clog << logger(LOG_ERROR) << "usage: -w wireshark with wireshark on or off!" << endl; clog << logger(LOG_ERROR) << "user value is not taken into account => apply default value (off)!" << endl; } break; case '?': errno = EINVAL; throw Error(__PRETTY_FUNCTION__, "Usage: -e station_executable [-s station_log -m maximus_log -l log_level -t max_tick_value -d debugger -f frequency -w wireshark]", errno); break; } } if (!isStationExecutableSet) { errno = EINVAL; throw Error(__PRETTY_FUNCTION__, "Usage: -e station_executable [-s station_log -m maximus_log -l log_level -t max_tick_value -d debugger -f frequency -w wireshark]", errno); } // Maximus log if ( (!maximusLog.empty()) && (maximusLog.compare("-")) ) { // In case of the file already exists, delete it remove(maximusLog.c_str()); mMaximusLogFile.open(maximusLog.c_str(), ios_base::app | ios_base::out); if (mMaximusLogFile.is_open()) { clog << logger(LOG_INFO) << "Maximus logs will be output into " << maximusLog << endl; logger.setLogFile(mMaximusLogFile); } else { clog << logger(LOG_ERROR) << "error while opening Maximus log file!" << endl; clog << logger(LOG_ERROR) << "Maximus logs will be output on standard output!" << endl; } } else { clog << logger(LOG_ERROR) << "Maximus logs will be output on standard output!" << endl; } // Log level logger.setLogLevel(logLevel); mpCoreEngine->init(stationExecutable, stationLog, debugger, frequency); } catchFunction(this); } void Maximus::init_phy ( PhyMpduCb interface_cb ) { logFunction(); try { if (!getPhyProcessor()->init(interface_cb)) { throw Error(__PRETTY_FUNCTION__, "PHY initialization failed"); } } catchFunction(this); } File_Descriptor Maximus::init_ether ( EtherCb interface_cb ) { logFunction(); try { if (!getEthernet()->init(interface_cb)) { throw Error(__PRETTY_FUNCTION__, "Ethernet initialization failed"); } if (isWireshark()) { char dev[] = "tap10\0"; if (0 > (mEtherLogFileDescriptor = getEthernet()->allocTap(dev))) { throw Error(__PRETTY_FUNCTION__, "Bad Ether log file descriptor", errno); } } } catchFunction(this); return mEtherLogFileDescriptor; } void Maximus::process ( ) { logFunction(); try { Network_Clock_Tick tickValue = 0; // tick value until which to process if (0 == getMaxTickValue()) { tickValue = getWaitTickValue(); } else if (0 != getWaitTickValue()) { tickValue = min(getMaxTickValue(), getWaitTickValue()); } getCoreEngine()->process(tickValue); if (0 != getMaxTickValue()) { if (getMaxTickValue() <= getNetworkClockProcessor()->getCurrentTickValue()) { clog << logger(LOG_FATAL) << "Max tick value is reached!" << endl; stop(); exit(1); } } } catchFunction(this); } Sta & Maximus::create_sta ( const string & station_executable ) { logFunction(); Sta * pSta = NULL; try { if (!station_executable.empty()) { pSta = new Sta(this, getSystemManager(), station_executable); } else { pSta = new Sta(this, getSystemManager(), getSystemManager()->getDefaultStationExecutable()); } if (NULL == pSta) { throw Error(__PRETTY_FUNCTION__, "Station pointer is NULL"); } mListOfStas.push_back(pSta); // If channel perturbation is enabled, // inform the channel package that a new station has been created if (getPhyProcessor()->isChannelEnabled()) { getChannel()->addChannelSettings(pSta->getStationId()); } } catchFunction(this); return *pSta; } Msg & Maximus::create_fc ( const string & name ) { logFunction(); Msg * pMsg = NULL; try { pMsg = new Msg(this, getFunctionCallManager(), getSystemManager(), name); if (NULL == pMsg) { throw Error(__PRETTY_FUNCTION__, "Message pointer is NULL"); } mListOfMsgs.push_back(pMsg); } catchFunction(this); return *pMsg; } Msg & Maximus::create_probe ( ) { logFunction(); Msg * pMsg = NULL; try { pMsg = new Msg(this, getFunctionCallManager(), getSystemManager()); if (NULL == pMsg) { throw Error(__PRETTY_FUNCTION__, "Message pointer is NULL"); } mListOfMsgs.push_back(pMsg); } catchFunction(this); return *pMsg; } PhySciMsgMpdu * Maximus::create_mpdu ( ) { logFunction(); return getPhyProcessor()->createMpdu(); } void Maximus::send_mpdu ( PhySciMsgMpdu * p_mpdu ) { logFunction(); try { if (NULL == p_mpdu) { errno = EINVAL; throw Error(__PRETTY_FUNCTION__, "PHY SCI message MPDU pointer is NULL", errno); } if (!getPhyProcessor()->sendMpdu(p_mpdu)) { throw Error(__PRETTY_FUNCTION__, "MPDU has not been sent correctly", errno); } } catchFunction(this); } EtherSciMsg * Maximus::create_ether ( ) { logFunction(); return getEthernet()->createEther(); } void Maximus::send_ether ( EtherSciMsg & ether ) { logFunction(); try { if (!getEthernet()->sendEther(ether)) { throw Error(__PRETTY_FUNCTION__, "Ethernet SCI message has not been sent correctly", errno); } } catchFunction(this); } void Maximus::wait ( const tick_t value ) { logFunction(); try { setWaitTickValue(getNetworkClockProcessor()->getCurrentTickValue() + value); while (getWaitTickValue() > getNetworkClockProcessor()->getCurrentTickValue()) { process(); } setWaitTickValue(0); } catchFunction(this); } void Maximus::wait ( ) { logFunction(); try { while ( (NULL != getFunctionCallManager()->getListOfCallbacks()) && (!getFunctionCallManager()->getListOfCallbacks()->empty()) ) { process(); } } catchFunction(this); } void Maximus::disturb_channel ( const bool enable ) { logFunction(); try { getCoreEngine()->disturbChannel(enable); } catchFunction(this); } const tick_t Maximus::get_date ( ) { logFunction(); tick_t date = 0; try { date = getNetworkClockProcessor()->getCurrentTickValue(); } catchFunction(this); return date; } void Maximus::set_freq ( const float frequency ) { logFunction(); try { getPhyProcessor()->setFrequency(frequency); } catchFunction(this); } const float Maximus::get_freq ( ) { logFunction(); float frequency = 0; try { frequency = getPhyProcessor()->getFrequency(); } catchFunction(this); return frequency; } void Maximus::set_snr ( const float snr_value ) { logFunction(); try { // If channel perturbation is enabled, set the SNR value if (getPhyProcessor()->isChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(0 /* tx_station_id */, 0 /* rx_station_id */, false); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snr_value); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr ( const string & snr_file ) { logFunction(); try { // Read the user SNR file float snrArray[MAXIMUS_CHANNEL_INTERVAL_MAX_NB][PHY_CARRIER_NB + 1]; if (!readSnrFile(snr_file, snrArray)) { for (int j=0; j<= PHY_CARRIER_NB; j++) { for (int i=0; iisChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(0 /* tx_station_id */, 0 /* rx_station_id */, false); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snrArray); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_from_src ( const float snr_value, const Sta & src, const bool both_directions ) { logFunction(); try { // If channel perturbation is enabled, set the SNR value if (getPhyProcessor()->isChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(src.getStationId() /* tx_station_id */, 0 /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snr_value); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_from_src ( const string & snr_file, const Sta & src, const bool both_directions ) { logFunction(); try { // Read the user SNR file float snrArray[MAXIMUS_CHANNEL_INTERVAL_MAX_NB][PHY_CARRIER_NB + 1]; if (!readSnrFile(snr_file, snrArray)) { for (int j=0; j<= PHY_CARRIER_NB; j++) { for (int i=0; iisChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(src.getStationId() /* tx_station_id */, 0 /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snrArray); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_to_dst ( const float snr_value, const Sta & dst, const bool both_directions ) { logFunction(); try { // If channel perturbation is enabled, set the SNR value if (getPhyProcessor()->isChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(0 /* tx_station_id */, dst.getStationId() /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snr_value); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_to_dst ( const string & snr_file, const Sta & dst, const bool both_directions ) { logFunction(); try { // Read the user SNR file float snrArray[MAXIMUS_CHANNEL_INTERVAL_MAX_NB][PHY_CARRIER_NB + 1]; if (!readSnrFile(snr_file, snrArray)) { for (int j=0; j<= PHY_CARRIER_NB; j++) { for (int i=0; iisChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(0 /* tx_station_id */, dst.getStationId() /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snrArray); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_from_src_to_dst ( const float snr_value, const Sta & src, const Sta & dst, const bool both_directions ) { logFunction(); try { // If channel perturbation is enabled, set the SNR value if (getPhyProcessor()->isChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(src.getStationId() /* tx_station_id */, dst.getStationId() /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snr_value); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::set_snr_from_src_to_dst ( const string & snr_file, const Sta & src, const Sta & dst, const bool both_directions ) { logFunction(); try { float snrArray[MAXIMUS_CHANNEL_INTERVAL_MAX_NB][PHY_CARRIER_NB + 1]; if (!readSnrFile(snr_file, snrArray)) { for (int j=0; j<= PHY_CARRIER_NB; j++) { for (int i=0; iisChannelEnabled()) { std::vector listOfChannelSettings = getChannel()->findChannelSettings(src.getStationId() /* tx_station_id */, dst.getStationId() /* rx_station_id */, both_directions); std::vector::size_type size = listOfChannelSettings.size(); for (std::vector::size_type s=0; ssetSnr(snrArray); } listOfChannelSettings.pop_back(); } } else { errno = EPROTO; throw Error(__PRETTY_FUNCTION__, "Channel perturbation is disabled", errno); } } catchFunction(this); } void Maximus::activate_false_alarm ( const Network_Clock_Tick average_duration, const float std_deviation ) { logFunction(); try { if (!getPhyProcessor()->activateFalseAlarm(average_duration, std_deviation)) { throw Error(__PRETTY_FUNCTION__, "Cannot activate false alarm"); } } catchFunction(this); } void Maximus::deactivate_false_alarm ( ) { logFunction(); try { if (!getPhyProcessor()->deactivateFalseAlarm()) { throw Error(__PRETTY_FUNCTION__, "Cannot deactivate false alarm"); } } catchFunction(this); } const bool Maximus::is_station_idle ( Sci_Msg_Station_Id station_id ) { logFunction(); bool isIdle = false; try { isIdle = getSystemManager()->isStationIdle(station_id); } catchFunction(this); return isIdle; } // private methods // CoreEngine * Maximus::getCoreEngine ( ) { try { if (NULL == mpCoreEngine) { throw Error(__PRETTY_FUNCTION__, "Core engine pointer is NULL"); } } catchFunction(this); return mpCoreEngine; } ISystem * Maximus::getSystemManager ( ) { ISystem * pSystemManager = NULL; try { if ( NULL == (pSystemManager = getCoreEngine()->getSystem()) ) { throw Error(__PRETTY_FUNCTION__, "System manager pointer is NULL"); } } catchFunction(this); return pSystemManager; } IFunctionCall * Maximus::getFunctionCallManager ( ) { IFunctionCall * pFunctionCallManager = NULL; try { if ( NULL == (pFunctionCallManager = getCoreEngine()->getFunctionCall()) ) { throw Error(__PRETTY_FUNCTION__, "Function call manager pointer is NULL"); } } catchFunction(this); return pFunctionCallManager; } INetworkClock * Maximus::getNetworkClockProcessor ( ) { INetworkClock * pNetworkClockProcessor = NULL; try { if ( NULL == (pNetworkClockProcessor = getCoreEngine()->getNetworkClock()) ) { throw Error(__PRETTY_FUNCTION__, "Network clock processor pointer is NULL"); } } catchFunction(this); return pNetworkClockProcessor; } IPhy * Maximus::getPhyProcessor ( ) { IPhy * pPhyProcessor = NULL; try { if ( NULL == (pPhyProcessor = getCoreEngine()->getPhy()) ) { throw Error(__PRETTY_FUNCTION__, "Phy processor pointer is NULL"); } } catchFunction(this); return pPhyProcessor; } ISci * Maximus::getSciServer ( ) { ISci * pSciServer = NULL; try { if ( NULL == (pSciServer = getCoreEngine()->getSci()) ) { throw Error(__PRETTY_FUNCTION__, "SCI server pointer is NULL"); } } catchFunction(this); return pSciServer; } IChannel * Maximus::getChannel ( ) { IChannel * pChannel = NULL; try { if ( NULL == (pChannel = getCoreEngine()->getChannel()) ) { throw Error(__PRETTY_FUNCTION__, "Channel pointer is NULL"); } } catchFunction(this); return pChannel; } IEthernet * Maximus::getEthernet ( ) { IEthernet * pEthernet = NULL; try { if ( NULL == (pEthernet = getCoreEngine()->getEthernet()) ) { throw Error(__PRETTY_FUNCTION__, "Ethernet pointer is NULL"); } } catchFunction(this); return pEthernet; } Network_Clock_Tick Maximus::getMaxTickValue ( ) const { return mMaxTickValue; } bool Maximus::setMaxTickValue ( const Network_Clock_Tick max_tick_value ) { mMaxTickValue = max_tick_value; return true; } Network_Clock_Tick Maximus::getWaitTickValue ( ) const { return mWaitTickValue; } bool Maximus::setWaitTickValue ( const Network_Clock_Tick wait_tick_value ) { mWaitTickValue = wait_tick_value; return true; } bool Maximus::readSnrFile ( const string & snr_file, float snr_array[MAXIMUS_CHANNEL_INTERVAL_MAX_NB][PHY_CARRIER_NB + 1] ) { logFunction(); bool bRead = true; try { // Read file // memset(snr_array, '\0', MAXIMUS_CHANNEL_INTERVAL_MAX_NB * (PHY_CARRIER_NB + 1) * sizeof(float)); ifstream snrFile(snr_file.c_str(), ifstream::in); if (snrFile.is_open()) { /* Read end times (in ticks) of each interval of the beacon period. */ char c; float tempEndTimeOfLastInterval = (2 * 1000000) / (getPhyProcessor()->getFrequency()); unsigned short int endTimeOfLastInterval = (unsigned short int)tempEndTimeOfLastInterval; unsigned short int numberOfIntervals = MAXIMUS_CHANNEL_INTERVAL_MAX_NB; for (int i=0; i> snr_array[i][0]; if (endTimeOfLastInterval <= snr_array[i][0]) { snr_array[i][0] = endTimeOfLastInterval; numberOfIntervals = i + 1; break; } c = snrFile.peek(); while ( ('\t' == c) || (' ' == c) || (EOF == c) ) { snrFile.ignore(); c = snrFile.peek(); } if ('#' == c) { while ( ('\n' != c) && (EOF != c) ) { snrFile.ignore(); c = snrFile.peek(); } } if ('\n' == c) { snrFile.ignore(); numberOfIntervals = i + 1; if (endTimeOfLastInterval != snr_array[i][0]) { if (MAXIMUS_CHANNEL_INTERVAL_MAX_NB > i+1) { snr_array[i+1][0] = endTimeOfLastInterval; numberOfIntervals++; } else { errno = EINVAL; throw Error(__PRETTY_FUNCTION__, "Too many time intervals in SNR file", errno); } } break; } } /* Read SNR values (in dB) for each carrier. */ for (int j=1; j<=PHY_CARRIER_NB; j++) { for (int i=0; i> snr_array[i][j]; } c = snrFile.peek(); while ( ('\n' != c) && (EOF != c) ) { snrFile.ignore(); c = snrFile.peek(); } } } else { throw Error(__PRETTY_FUNCTION__, "Error while opening SNR file", errno); } snrFile.close(); } catchFunction(this); return bRead; } const bool Maximus::isWireshark ( ) const { return mIsWireshark; } // public methods // void Maximus::wrapper ( int n ) { logFunction(); if (NULL != pMaximus) { clog << logger(LOG_FATAL) << "Catch CTRL+C!" << endl; pMaximus->stop(); raise(SIGTERM); } } void Maximus::stop ( ) { logFunction(); unsigned int counter = 0; clog << logger(LOG_FATAL) << "*** Exit Fulminata Maximus simulator ***" << endl; for (unsigned int i=0; i