#include #include #include #include #include #include #include #include #include #include "maximus/common/interfaces/Maximus.h" #include "maximus/common/interfaces/Sta.h" #include "maximus/common/interfaces/Msg.h" #include "ISystem.h" #include "IFunctionCall.h" #include "PhySciMsgMpdu.h" #include "PhySciMsgFc.h" #include "EtherSciMsg.h" #include "Logger.h" #include "common/defs/ethernet.h" using namespace std; using namespace boost::python; // For unitary tests extern bool UNITTEST; extern string stationTest; #if CONFIG_LOG // For Maximus log extern Logger logger; #endif /* CONFIG_LOG */ // To catch signals extern Maximus * pMaximus; // To log Ether SCI messages File_Descriptor etherLogFileDescriptor = -1; typedef std::multimap CbsList; CbsList listOfCbs; typedef struct rx_param_phy { object create_pb; object cb; bool activated; } rx_param_phy_t; rx_param_phy_t phy_rx_param; typedef struct rx_param_ether { object create_eth; object create_mme; object create_buffer; object cb; object catch_all_cb; bool activated; bool catch_all_activated; bool is_create_set; // same creation callback functions are used in both cases ("catch all" reception or not) } rx_param__ether_t; rx_param__ether_t ether_rx_param; void log_ether ( EtherSciMsg & ether ) { logFunction(); if (-1 != etherLogFileDescriptor) { /* Write the Ether SCI message into the Ether log file. */ int length = 0; int totalLength = 0; int dataLength = (int)ether.getSpecializedSciMsgDataLength(); unsigned char * pData = ether.getSpecializedSciMsgData(); unsigned char data[ETH_PACKET_MIN_SIZE_ALLOWED]; memset(data, 0x00, ETH_PACKET_MIN_SIZE_ALLOWED); // padding zero if (dataLength < ETH_PACKET_MIN_SIZE_ALLOWED) { memcpy(data, ether.getSpecializedSciMsgData(), ether.getSpecializedSciMsgDataLength()); dataLength = ETH_PACKET_MIN_SIZE_ALLOWED; pData = data; } while(totalLength < dataLength) { length = write(etherLogFileDescriptor, pData + totalLength, dataLength - totalLength); if(length < 0) { if (EAGAIN != errno) { Error e(__PRETTY_FUNCTION__, "write Ether SCI message failed", errno); e.display(); throw e; } else { length = 0; } } totalLength += length; } } } void set_fcall_cb ( const Msg & msg, object user_cb ) { listOfCbs.insert(CbsList::value_type(msg.get_tx_msg_id(), user_cb)); } void remove_fcall_cb ( const Msg & msg ) { for (CbsList::const_iterator it = listOfCbs.begin(); it != listOfCbs.end(); ++it) { if (msg.get_tx_msg_id() == it->first) { listOfCbs.erase(it->first); break; } } } void recv_fcall_cb ( Msg & msg ) { for (CbsList::const_iterator it = listOfCbs.begin(); it != listOfCbs.end(); ++it) { if (msg.get_rx_msg_id() == it->first) { (it->second)(msg); listOfCbs.erase(it->first); break; } } } void recv_phy_mpdu_cb ( PhySciMsgMpdu & mpdu ) { logFunction(); if (phy_rx_param.activated) { // Create a new MPDU Python object (PB) object rx_mpdu = phy_rx_param.create_pb(); // Get PHY SCI message MPDU attributes // and set the MPDU object attributes // (FC 1.0, FC AV and MPDU payload) string payload((char *)mpdu.getSpecializedSciMsgData(), mpdu.getSpecializedSciMsgDataLength()); rx_mpdu.attr("set_mpdu_attr")(mpdu.getFc10(), make_tuple(mpdu.getFcAv()[0], mpdu.getFcAv()[1], mpdu.getFcAv()[2], mpdu.getFcAv()[3]), payload); // Call the Python reception callback phy_rx_param.activated = !phy_rx_param.cb(rx_mpdu); } } void recv_ether_cb ( EtherSciMsg & ether ) { logFunction(); if ( (ETHERNET_TYPE_DATA == ether.getSpecializedSciMsgType()) || (ETHERNET_TYPE_MME == ether.getSpecializedSciMsgType ())) { // Log the received Ether SCI message log_ether(ether); } if ( ether_rx_param.activated || ether_rx_param.catch_all_activated || (ETHERNET_TYPE_BUFFER_RELEASED == ether.getSpecializedSciMsgType()) ) { // Get Ethernet SCI message attributes string payload((char *)ether.getSpecializedSciMsgData(), ether.getSpecializedSciMsgDataLength()); /* Create a new MSDU Python object (Eth, MME or Buffer). */ object rx_msdu; if (ETHERNET_TYPE_DATA == ether.getSpecializedSciMsgType()) { rx_msdu = ether_rx_param.create_eth(); } else if (ETHERNET_TYPE_MME == ether.getSpecializedSciMsgType()) { rx_msdu = ether_rx_param.create_mme(); } else if (ETHERNET_TYPE_BUFFER_RELEASED == ether.getSpecializedSciMsgType()) { rx_msdu = ether_rx_param.create_buffer(); } else { errno = ENOMSG; Error e (__PRETTY_FUNCTION__, "receive an Ether SCI message with a bad type \ (should be DATA, MME or BUFFER_RELEASED)", errno); e.display(); throw e; } if (ETHERNET_TYPE_BUFFER_RELEASED == ether.getSpecializedSciMsgType()) { // Reallocate a buffer if requested by user rx_msdu.attr("realloc")(ether.getSciMsgStationId(), payload); } // Set the MSDU object attributes (payload) rx_msdu.attr("set_msdu_attr")(payload); if ( (ether_rx_param.catch_all_activated) && (ETHERNET_TYPE_BUFFER_RELEASED != ether.getSpecializedSciMsgType()) ) { // Call the "catch all" Python reception callback before the other one, // because of the reception counter that should not be decremented before this call ether_rx_param.catch_all_cb (rx_msdu); } if (ether_rx_param.activated) { // Call the Python reception callback ether_rx_param.activated = !ether_rx_param.cb(rx_msdu); } } } /* void init_wrap ( Maximus & m, const int argc, const string args ) { size_t previous = 0; size_t found = 0; char * argv[argc]; int i = 0; do { found = args.find(' ', previous); string temp = args.substr(previous, found-previous); argv[i] = new char[temp.size()+1]; strcpy(argv[i], temp.c_str()); previous = found+1; i++; } while ((found != string::npos) && (i args_copy[argc]; char *argv[argc]; /* Make the argv array. */ for (int i = 0; i < argc; i++) { const std::string s = extract (args[i]); args_copy[i].insert (args_copy[i].end (), s.c_str (), s.c_str () + s.size () + 1); argv[i] = &args_copy[i][0]; } /* Call the real function. */ m.init (argc, argv); phy_rx_param.activated = false; ether_rx_param.activated = false; ether_rx_param.catch_all_activated = false; ether_rx_param.is_create_set = false; m.init_phy (&recv_phy_mpdu_cb); etherLogFileDescriptor = m.init_ether (&recv_ether_cb); } void uninit_wrap ( Maximus & m ) { /* Free all resources. */ m.stop(); } PyObject * create_sta_wrapx1 ( Maximus & m ) { return_internal_reference<1, Maximus>::result_converter::apply::type converter; return converter(m.create_sta()); } PyObject * create_sta_wrapx2 ( Maximus & m, const string & station_executable ) { return_internal_reference<1, Maximus>::result_converter::apply::type converter; return converter(m.create_sta(station_executable)); } PyObject * create_sta_wrapx3 ( Maximus & m, const string & station_executable, uint32_t seed ) { return_internal_reference<1, Maximus>::result_converter::apply::type converter; return converter(m.create_sta(station_executable, seed)); } PyObject * create_fcall_wrap ( Maximus & m, const string name ) { return_internal_reference<1, Maximus>::result_converter::apply::type converter; return converter(m.create_fc(name)); } PyObject * create_probe_wrap ( Maximus & m ) { return_internal_reference<1, Maximus>::result_converter::apply::type converter; return converter(m.create_probe()); } void send_phy ( Maximus & m, object mpdu ) { /* Create a PHY SCI message MPDU. */ PhySciMsgMpdu * pMpdu = m.create_mpdu(); /* Extract MPDU object attributes * and set the PHY SCI message MPDU attributes. */ // Extract and set FC 1.0 uint32_t fc_10 = extract(mpdu.attr("fc_10")); if (0 != fc_10) { pMpdu->setFc10(fc_10); } // Extract and set FC AV uint32_t fc_av[4]; for (int i=0; i<4; i++) { fc_av[i] = extract(mpdu.attr("fc_av")[i]); } pMpdu->setFcAv(fc_av); // Extract MPDU payload and set MPDU payload length and MPDU payload string payload = extract(mpdu.attr("payload")); pMpdu->setMpdu((unsigned long)payload.length(), (unsigned char *)payload.c_str()); // Set MPDU format // HomePlug AV specs => delimiter type (DT_AV) is described by bits 0-2 of first fc_av octet: // 000 Beacon // 001 SOF // 010 SACK // 011 RTS/CTS // 100 SOUND // 101 RSOF pMpdu->setMpduFormat((Phy_Mpdu_Format)((fc_av[0] & 0x07) + 1)); // +1 to have the correspondance with our own MPDU format definition (of 'phy_types.h') // Extract and set FC mode int fc_mode = extract(mpdu.attr("fc_mode")); if ( PHY_FC_MODE_NONE == (Phy_Fc_Mode)fc_mode ) { if (0 == fc_10) { fc_mode = PHY_FC_MODE_AV_1; } else { fc_mode = PHY_FC_MODE_HYBRID_1; } } pMpdu->setFcMode((Phy_Fc_Mode)fc_mode); // Extract and set short PPDU pMpdu->setShortPpdu((Phy_Short_Ppdu)extract(mpdu.attr("short_ppdu"))); // Set default flags pMpdu->setFlags(PHY_FLAG_CRC_OK); if (!pMpdu->getShortPpdu()) { // Extract and set modulation int mod = extract(mpdu.attr("mod")); if (PHY_MOD_TM == (Phy_Mod)mod) { errno = EINVAL; Error e(__PRETTY_FUNCTION__, "modulation cannot be set to PHY_MOD_TM", errno); e.display(); throw e; } else if ((PHY_MOD_NONE == (Phy_Mod)mod) && (MAC_PB136_BYTES >= payload.length())) { mod = PHY_MOD_MINI_ROBO; } else if ((PHY_MOD_NONE == (Phy_Mod)mod) && (MAC_PB136_BYTES < payload.length())) { mod = PHY_MOD_ROBO; } pMpdu->setMod((Phy_Mod)mod); // Set default FEC rate pMpdu->setFecrate(PHY_FEC_RATE_1_2); if (PHY_MOD_MINI_ROBO == pMpdu->getMod()) { // Set default Guard Interval pMpdu->setGil(PHY_GIL_567); // Set default PB size pMpdu->setPbSize(MAC_PB136_BYTES); } else { // Set default Guard Interval pMpdu->setGil(PHY_GIL_417); // Set default PB size pMpdu->setPbSize(MAC_PB520_BYTES); // Set default flags pMpdu->setFlags(PHY_FLAG_CRC_OK+PHY_FLAG_PB512); } } // Extract and set PB Header uint32_t pbHeader = extract(mpdu.attr("first_pb_header")); if (0 != pbHeader) { unsigned short int mfboCounter = 1; unsigned long mfbo = extract(mpdu.attr("mfbo")[mfboCounter]); for (unsigned short int n=0; ngetPbSize())) ) { // increment MFBO counter mfboCounter++; // extract MFBO mfbo = extract(mpdu.attr("mfbo")[mfboCounter]); } // extract MFBO if ( (0 != mfbo) && (mfbo < (unsigned long)((n + 1) * pMpdu->getPbSize())) ) { // set MFBF pbHeader |= (1 << 27); // set MFB0 pbHeader += ((mfbo % pMpdu->getPbSize()) << 16); } } // set PBs Headers pMpdu->setPbsHeaders(n, pbHeader); // reset MFBF and MFBO, and increment SSN if (0xFFFF > (pbHeader & 0xFFFF)) { pbHeader = (pbHeader & 0xF600FFFF) + 1; } else { pbHeader &= 0xF6000000; } } } /* Send the PHY SCI message MPDU. */ m.send_mpdu(pMpdu); while (!pMpdu->isSent()) { m.process(); } /* Delete the PHY SCI message MPDU. */ if (NULL != pMpdu) { delete (pMpdu); pMpdu = NULL; } } void set_phy_rx ( Maximus & m, object user_cb, object create_pb_function ) { phy_rx_param.cb = user_cb; phy_rx_param.create_pb = create_pb_function; phy_rx_param.activated = true; } void send_ether ( Maximus & m, object msdu, int station_id ) { /* Create an Ether SCI message. */ EtherSciMsg * pEther = m.create_ether(); /* Set the Ether SCI message attributes. */ // Extract MSDU payload and set Ether SCI message payload length and Ether SCI message payload string payload = extract(msdu.attr("get")()); pEther->setSpecializedSciMsgDataLength((unsigned long)payload.length()); pEther->setSpecializedSciMsgData((unsigned char *)payload.c_str()); // Set Ether SCI message type int type = extract(msdu.attr("get_ether_type")()); pEther->setSpecializedSciMsgType(static_cast(type)); // Set station ID pEther->setSciMsgStationId(static_cast(station_id)); if ( (ETHERNET_TYPE_DATA == pEther->getSpecializedSciMsgType()) || (ETHERNET_TYPE_MME == pEther->getSpecializedSciMsgType()) ) { /* Log the Ether SCI message to send. */ log_ether(*pEther); } /* Send the Ether SCI message. */ m.send_ether(*pEther); /* Delete the Ether SCI message. */ if (NULL != pEther) { delete (pEther); pEther = NULL; } } void set_ether_rx_catch_all ( Maximus & m, object user_cb, object create_eth_function, object create_mme_function, object create_buffer_function) { ether_rx_param.catch_all_cb = user_cb; ether_rx_param.catch_all_activated = true; if (!ether_rx_param.is_create_set) { ether_rx_param.create_eth = create_eth_function; ether_rx_param.create_mme = create_mme_function; ether_rx_param.create_buffer = create_buffer_function; ether_rx_param.is_create_set = true; } } void reset_ether_rx_catch_all ( Maximus & m ) { ether_rx_param.catch_all_activated = false; } void set_ether_rx ( Maximus & m, object user_cb, object create_eth_function, object create_mme_function, object create_buffer_function) { ether_rx_param.cb = user_cb; ether_rx_param.activated = true; if (!ether_rx_param.is_create_set) { ether_rx_param.create_eth = create_eth_function; ether_rx_param.create_mme = create_mme_function; ether_rx_param.create_buffer = create_buffer_function; ether_rx_param.is_create_set = true; } } PyObject * add_param_bool ( Msg & msg, const string name, const bool value ) { copy_non_const_reference::apply::type converter; msg.add_param(name, value); return converter(msg); } PyObject * add_param_uchar ( Msg & msg, const string name, const unsigned char value ) { copy_non_const_reference::apply::type converter; msg.add_param(name, sizeof(unsigned char), &value); return converter(msg); } PyObject * add_param_ushort ( Msg & msg, const string name, const unsigned short int value ) { copy_non_const_reference::apply::type converter; msg.add_param(name, value); return converter(msg); } PyObject * add_param_ulong ( Msg & msg, const string name, const unsigned long int value ) { copy_non_const_reference::apply::type converter; msg.add_param(name, value); return converter(msg); } PyObject * add_param_ull ( Msg & msg, const string name, const unsigned long long value ) { copy_non_const_reference::apply::type converter; msg.add_param(name, value); return converter(msg); } PyObject * add_param_n_u8 ( Msg & msg, const string name, tuple value ) { copy_non_const_reference::apply::type converter; unsigned long length = (unsigned long)len(value); unsigned char param[length]; for (unsigned long i=0; i(value[i]); } msg.add_param(name, length*sizeof(unsigned char), param); return converter(msg); } PyObject * add_param_n_u16 ( Msg & msg, const string name, tuple value ) { copy_non_const_reference::apply::type converter; unsigned long length = (unsigned long)len(value); unsigned short int param[length]; for (unsigned long i=0; i(value[i])); } msg.add_param(name, length*sizeof(unsigned short int), (unsigned char *)¶m); return converter(msg); } PyObject * add_param_n_u32 ( Msg & msg, const string name, tuple value ) { copy_non_const_reference::apply::type converter; unsigned long length = (unsigned long)len(value); unsigned long int param[length]; for (unsigned long i=0; i(value[i])); } msg.add_param(name, length*sizeof(unsigned long int), (unsigned char *)¶m); return converter(msg); } PyObject * set_cb_wrap ( Msg & msg, object user_cb ) { copy_non_const_reference::apply::type converter; remove_fcall_cb(msg); set_fcall_cb(msg, user_cb); msg.set_cb(&recv_fcall_cb); return converter(msg); } PyObject * remove_cb_wrap ( Msg & msg ) { copy_non_const_reference::apply::type converter; remove_fcall_cb(msg); msg.remove_cb(); return converter(msg); } string bind_param ( Msg & msg, const string name ) { string str; unsigned long ulLength = FUNCTION_CALL_PARAM_MAX_SIZE; unsigned char ucValue[ulLength]; if (NULL != msg.bind_param(name, ulLength, ucValue)) { str.assign((char *)ucValue, ulLength); } return str; } string bind_param_string ( Msg & msg, const string name ) { string str(bind_param(msg, name)); if ( (0 < str.length()) && ('\0' == str[str.length()-1]) ) { str.erase(str.length()-1); } return str; } bool bind_param_bool ( Msg & msg, const string name ) { return msg.bind_param(name); } unsigned short int bind_param_ushort ( Msg & msg, const string name ) { return msg.bind_param(name); } unsigned long int bind_param_ulong ( Msg & msg, const string name ) { return msg.bind_param(name); } unsigned long long bind_param_ull ( Msg & msg, const string name ) { return msg.bind_param(name); } tuple bind_param_n_u8 ( Msg & msg, const string name ) { tuple t = make_tuple(); string str(bind_param(msg, name)); for (unsigned int n=0; n("Maximus") .def("init", init_wrap) .def("uninit", uninit_wrap) .def("process", &Maximus::process) .def("create_sta", create_sta_wrapx1) // create a station with the default station executable (from command line arguments) .def("create_sta", create_sta_wrapx2) // create a station with an explicit station executable .def("create_sta", create_sta_wrapx3) // create a station with an explicit station executable and with a seed .def("create_fcall", create_fcall_wrap) .def("create_probe", create_probe_wrap) .def("send_mpdu", send_phy) .def("set_mpdu_rx", set_phy_rx) .def("send_msdu", send_ether) .def("set_msdu_rx", set_ether_rx) .def("set_msdu_rx_catch_all", set_ether_rx_catch_all) .def("reset_msdu_rx_catch_all", reset_ether_rx_catch_all) .def("wait", waitx1) .def("wait", waitx2) .def("disturb_channel", &Maximus::disturb_channel, disturb_channel_overloads()) .def("get_date", &Maximus::get_date) .def("set_freq", &Maximus::set_freq) .def("get_freq", &Maximus::get_freq) .def("set_snr", set_snrx1) .def("set_snr", set_snrx2) .def("set_snr_from_src", set_snr_from_srcx1) .def("set_snr_from_src", set_snr_from_srcx2) .def("set_snr_to_dst", set_snr_to_dstx1) .def("set_snr_to_dst", set_snr_to_dstx2) .def("set_snr_from_src_to_dst", set_snr_from_src_to_dstx1) .def("set_snr_from_src_to_dst", set_snr_from_src_to_dstx2) .def("activate_false_alarm", &Maximus::activate_false_alarm) .def("deactivate_false_alarm", &Maximus::deactivate_false_alarm) .def("is_station_idle", &Maximus::is_station_idle) .def ("hide_sta", &Maximus::hide_sta) ; /* class Sta */ class_("Sta", init< Maximus *, ISystem *, const string &, optional >()) .def("remove", &Sta::remove) .def("deactivate", &Sta::deactivate) .def("activate", &Sta::activate) .def("debug", &Sta::debug) .def("is_idle", &Sta::is_idle) .def("get_station_id", &Sta::getStationId) .def("set_name", &Sta::set_name) ; /* class Msg */ Msg & (Msg::*add_paramx1)(const string &) = &Msg::add_param; Msg & (Msg::*add_paramx2)(const string &, const string &) = &Msg::add_param; void (Msg::*send_asyncx1)(void) = &Msg::send_async; void (Msg::*send_asyncx2)(Sta &) = &Msg::send_async; Msg & (Msg::*sendx1)(void) = &Msg::send; Msg & (Msg::*sendx2)(Sta &) = &Msg::send; class_("Msg", init< Maximus *, IFunctionCall *, ISystem *, optional >()) .def("add_param", add_paramx1, return_value_policy()) .def("add_param", add_paramx2, return_value_policy()) .def("add_param_bool", add_param_bool) .def("add_param_uchar", add_param_uchar) .def("add_param_ushort", add_param_ushort) .def("add_param_ulong", add_param_ulong) .def("add_param_ull", add_param_ull) .def("add_param_n_u8", add_param_n_u8) .def("add_param_n_u16", add_param_n_u16) .def("add_param_n_u32", add_param_n_u32) .def("remove_param", &Msg::remove_param, return_value_policy()) .def("set_cb", set_cb_wrap) .def("remove_cb", remove_cb_wrap) .def("set_sta", &Msg::set_sta, return_value_policy()) .def("send_async", send_asyncx1) .def("send_async", send_asyncx2) .def("send", sendx1, return_value_policy()) .def("send", sendx2, return_value_policy()) .def("is_param", &Msg::is_param) .def("bind_param", bind_param) .def("bind_param_string", bind_param_string) .def("bind_param_bool", bind_param_bool) .def("bind_param_ushort", bind_param_ushort) .def("bind_param_ulong", bind_param_ulong) .def("bind_param_ull", bind_param_ull) .def("bind_param_n_u8", bind_param_n_u8) .def("bind_param_n_u16", bind_param_n_u16) .def("bind_param_n_u32", bind_param_n_u32) ; }