Page MenuHomec4science

measurementsplc.cc
No OneTemporary

File Metadata

Created
Sat, Jul 5, 00:05

measurementsplc.cc

#include <click/config.h>
#include "measurementsplc.hh"
#define DEBUG_CHATTER(arg, ...) do { if (_debug) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
#define VERB_DEBUG_CHATTER(arg, ...) do { if (_verb_debug&&_init) { click_chatter(arg, ## __VA_ARGS__);} } while (0)
CLICK_DECLS
MeasurementsPLC::MeasurementsPLC() : _get_airtime_timer(this), _empty_channel_timer(this)
{
}
MeasurementsPLC::~MeasurementsPLC()
{
}
void *
MeasurementsPLC::cast(const char *name) {
if (strcmp(name, "MeasurementsPLC") == 0)
return (MeasurementsPLC *) this;
else if (strcmp(name, "Measurements") == 0)
return (Measurements *) this;
else
return Measurements::cast(name);
}
int MeasurementsPLC::configure(Vector<String> &conf, ErrorHandler *errh){
_begin.assign_now();
_save_ble = false;
_count_str_ble = 0;
_string_ble = "";
_debug = false;
_verb_debug = false;
_init = false;
if(Args(this, errh).bind(conf)
.read("DEBUG", _debug)
.read("VERB_DEBUG", _verb_debug)
.read("SAVE_BLE", _max_count_ble)
.complete() < 0)
return -1;
_save_ble = (_max_count_ble > 0);
if(_save_ble) {
String str = "BLE timestamp stei dtei del_type lid ble";
click_chatter("[MeasurementsPLC] Format is %s", str.c_str());
}
if(_verb_debug)
_debug = true;
_get_airtime_timer.initialize(this);
_empty_channel_timer.initialize(this);
set_backoff_times();
return 0;
}
int
MeasurementsPLC::initialize(ErrorHandler *errh) {
}
void
MeasurementsPLC::push(int, Packet *p_in) {
if(_init) {
click_ether *eth_hdr = (click_ether *) p_in->data();
if(eth_hdr->ether_type == htons(ETHERTYPE_HP_AV)) {
click_hp_av_sniffer_indicate *hpavh = (click_hp_av_sniffer_indicate *) (eth_hdr+1);
if(ntohs(hpavh->MMType) == SNIFFER_IND) {
parse_plc_packet(hpavh, p_in->length());
}
else {
if(_verb_debug || (_debug && _count_dropped < 3))
click_chatter("[MeasurementsPLC] Receiving packets with wrong MMType (is %4hx, should be %4hx)", ntohs(hpavh->MMType), SNIFFER_IND);
_count_dropped++;
}
}
else {
if(_verb_debug || (_debug && _count_dropped < 3))
click_chatter("[MeasurementsPLC] Receiving frame of ethertype %s (should be %s)", String(eth_hdr->ether_type).c_str(),
String(htons(ETHERTYPE_HP_AV)).c_str());
_count_dropped++;
}
}
if(noutputs() == 0)
p_in->kill();
else
output(0).push(p_in);
}
void MeasurementsPLC::run_timer(Timer *timer){
VERB_DEBUG_CHATTER("[MeasurementsPLC %s] Run timer %p", Timestamp::now().unparse().c_str(), timer);
if (timer==&_get_airtime_timer) {
compute_airtime(0);
}
if (timer==&_empty_channel_timer) {
_now.assign_now();
if(_nb_frames_empty_channel == 0) {
DEBUG_CHATTER("[MeasurementsPLC %s] Channel empty during last %d ms", _now.unparse().c_str(), _freq_empty_channel);
_src_to_notify->notification_empty_channel_plc();
}
else {
DEBUG_CHATTER("[MeasurementsPLC %s] Received %d packets in %d ms", _now.unparse().c_str(), _nb_frames_empty_channel, _freq_empty_channel);
}
_nb_frames_empty_channel = 0;
if(_freq_empty_channel>0)
_empty_channel_timer.schedule_after_msec(_freq_empty_channel);
}
}
void
MeasurementsPLC::parse_plc_packet(click_hp_av_sniffer_indicate *p, uint32_t packet_len) {
_count_all++;
click_hp_av_fc fc = p->fc;
_now.assign_now();
if(_verb_debug || (_debug && _count_all < 2))
click_chatter("[MeasurementsPLC %s] Parsing PLC frame of type %d, length %d from %d to %d, priority %d...",
_now.unparse().c_str(), (int) fc.del_type, (int) fc.fl_av, (int) fc.stei, (int) fc.dtei, (int) fc.lid);
if(fc.del_type == 0) { // beacon
_busy_ns+= (110500+90000); // beacon+beacon-inter-frame-space
_count_beacon++;
}
else if (fc.del_type == 2) { // ack
_count_ack++;
return; // do not count ack, counted after every transmission (TODO: what if acks repeated?)
}
else if (fc.del_type == 1) { // other frames
if(fc.lid == 1) { // do not count priority different than 1 (not regular traffic)
uint16_t frame_length = fc.fl_av;
_busy_ns += (frame_length*1280 + 110500); // frame length + preamble
if(fc.mpdu_cnt == 0) {
if(_printed_stei[fc.stei] == 0) {
DEBUG_CHATTER("[MeasurementsPLC %s] Parsing PLC frame (MPDU 0, type 1) from new STEI %d (to %d), length %d, PLC-length %d, priority %d...",
_now.unparse().c_str(), (int) fc.stei, (int) fc.dtei, packet_len, (int) fc.fl_av, (int) fc.lid);
_printed_stei.set(fc.stei,1);
for(HashTable<int,Timestamp>::const_iterator it=_active_tokens.begin();it.live();it++) {
if(_delay_first_packet[it.key()] == Timestamp())
_delay_first_packet.set(it.key(),_now-it.value());
}
}
_stei_received[fc.stei]++;
_count_links[PLCLink((int)fc.stei, (int)fc.dtei)]++;
_count_mpdu0++;
_busy_ns += (110500+100000); // ack+cifs
_busy_ns += (2*35840); // 2*PRS
_nb_frames_empty_channel++;
// if((int) fc.lid == 2)
// DEBUG_CHATTER("[MeasurementsPLC %s] Parsing PLC frame (MPDU 0, type 1) from new STEI %d (to %d), length %d, PLC-length %d, priority %d...",
// _now.unparse().c_str(), (int) fc.stei, (int) fc.dtei, packet_len, (int) fc.fl_av, (int) fc.lid);
}
}
}
if( _save_ble) {
_count_ble++;
if(_count_ble >= _max_count_ble) {
_count_ble = 0;
_now.assign_now();
int len = _string_ble.length();
// Change format (in configure) if changing this line!!
String first;
if(len==0)
first="-";
else
first = "";
String str = "BLE "+(_now-_begin).unparse()+" "+String((int)fc.stei)+" "+String((int)fc.dtei)+" "+String((int)fc.del_type)+" "+String((int)fc.lid)+" "+String::make_numeric(static_cast<String::uintmax_t>((int)fc.ble),16,false);
_string_ble += (str+" "+first+"\n");
_count_str_ble++;
if(_count_str_ble >= 50 || _string_ble.length() == len) {
click_chatter(_string_ble.c_str());
_count_str_ble = 0;
if(_string_ble.length() == len)
_string_ble = str+" --\n";
else
_string_ble = "";
}
}
}
}
gamma_type
MeasurementsPLC::get_airtime(int token) {
return _airtime[token];
}
gamma_type
MeasurementsPLC::get_busytime_us(int token) {
return _busy[token];
}
void
MeasurementsPLC::init_airtime(int interval, int token) {
if(interval > 0) //interval > 0 not compatible with several tokens
token = 0;
_now.assign_now();
// check that tokens have not timeouted (2 seconds)
Vector<int> token_timeout;
for(HashTable<int,Timestamp>::iterator it=_active_tokens.begin();it.live();it++) {
if((_now-it.value()).sec() >= 2) {
DEBUG_CHATTER("[MeasurementsPLC %s] Token %d has expired", _now.unparse().c_str(), it.key());
token_timeout.push_back(it.key());
}
}
for(int i=0;i<token_timeout.size();i++)
clear_counters(token_timeout[i]);
if(_active_tokens.size() == 0)
reinitialize_counters();
reinitialize_counters(token);
if (interval > 0) // if interval == 0, compute_airtime() must be triggered
_get_airtime_timer.schedule_after_msec(interval);
_active_tokens.set(token,_now);
_last_interval = interval;
DEBUG_CHATTER("[MeasurementsPLC %s] Initialization of airtime for token %d (%d tokens active), timer will fire in %d ms...",
_active_tokens[token].unparse().c_str(), token, _active_tokens.size(), interval);
_init = true;
}
void
MeasurementsPLC::compute_airtime(int token) {
_now.assign_now();
Timestamp diff = (_now - _active_tokens[token]);
uint32_t diff_us = usec_timestamp(diff);
uint64_t busy_ns = _busy_ns - _busy_ns_init[token];
// add backoff
int nb_STAs = -1;
for (HashTable<uint8_t, uint64_t>::iterator it=_stei_received.begin();it != _stei_received.end();++it) {
if(it.value() > mymax((int64_t)1,int_divide(MIN_NB_PACKET_PERSEC*diff.msecval(),1000))) {
//DEBUG_CHATTER("[MeasurementsPLC %s] Station STEI %d contending (%s packets received)",
// _now.unparse().c_str(), (int) it.key(), String(it.value()).c_str());
nb_STAs++;
}
//else
// DEBUG_CHATTER("[MeasurementsPLC %s] For packets from STEI %d, only %s packets",
// _now.unparse().c_str(), (int) it.key(), String(it.value()).c_str());
}
String link_stats;
if(_debug) {
link_stats+="\n\t\tLinks used ";
for (HashTable<PLCLink, int>::iterator it=_count_links.begin();it != _count_links.end();++it) {
int value = it.value() - _count_links_init[token][it.key()];
if(value > 0)
link_stats+=(String(it.key()._src)+"->"+String(it.key()._dst)+":"+String(value)+" ");
}
}
if(nb_STAs <= 0)
nb_STAs = 0;
if(nb_STAs < MAX_NB_NGHBRS_BIANCHI)
busy_ns += int_divide((_count_mpdu0 - _count_mpdu0_init[token])*array_backoff_times_bianchi_plc[nb_STAs]*35840,100);
else
busy_ns += int_divide((_count_mpdu0 - _count_mpdu0_init[token])*array_backoff_times_bianchi_plc[MAX_NB_NGHBRS_BIANCHI - 1]*358400,100);
_busy[token] = (gamma_type) int_divide(GAMMA_SCALE*busy_ns,1000);
if(diff_us > 0)
_airtime[token] = (gamma_type) int_divide(GAMMA_SCALE*busy_ns,1000*diff_us);
DEBUG_CHATTER("[MeasurementsPLC %s] Received %d frames (first at %s, %d acks, %d beacons, %d w/ MPDU0) from %d stations (%d dropped). "
"Airtime for token %d is %s (busy %s ms, active %s ms), %d tokens still active.%s",
_now.unparse().c_str(), (_count_all - _count_all_init[token]), _delay_first_packet[token].unparse().c_str(), (_count_ack - _count_ack_init[token]), (_count_beacon - _count_beacon_init[token]),
(_count_mpdu0 - _count_mpdu0_init[token]), nb_STAs+1, (_count_dropped - _count_dropped_init[token]), token, String(_airtime[token]).c_str(),
String(int_divide(busy_ns,1000000)).c_str(), String(int_divide(diff_us,1000)).c_str(), _active_tokens.size()-1, link_stats.c_str());
clear_counters(token);
if(_active_tokens.size() == 0)
_init = false;
}
void
MeasurementsPLC::reinitialize_counters() {
_busy_ns = 0;
_count_all = 0;
_count_ack = 0;
_count_beacon = 0;
_count_mpdu0 = 0;
_count_dropped = 0;
_busy_ns_init.clear();
_count_all_init.clear();
_count_ack_init.clear();
_count_beacon_init.clear();
_count_mpdu0_init.clear();
_stei_received.clear();
_airtime.clear();
_busy.clear();
_count_links.clear();
_printed_stei.clear();
DEBUG_CHATTER("[MeasurementsPLC] Clearing all counters.");
}
void
MeasurementsPLC::reinitialize_counters(int token) {
_busy_ns_init[token] = _busy_ns;
_count_all_init[token] = _count_all;
_count_ack_init[token] = _count_ack;
_count_beacon_init[token] = _count_beacon;
_count_mpdu0_init[token] = _count_mpdu0;
_count_dropped_init[token] = _count_dropped;
_count_links_init[token] = HashTable<PLCLink, int>(_count_links);
_airtime[token] = -1;
_busy[token] = -1;
_printed_stei.clear();
_delay_first_packet.set(token, Timestamp());
}
void MeasurementsPLC::clear_counters(int token) {
_active_tokens.erase(token);
_delay_first_packet.erase(token);
}
// Handlers
static String
airtime_handler_read(Element *e, void *) {
MeasurementsPLC *elmt = (MeasurementsPLC *)e;
StringAccum str;
gamma_type airtime = elmt->get_airtime(0);
if(airtime == -1)
str << "Interval has not elapsed, airtime not ready\n";
else
str << airtime;
return str.take_string();
}
int
MeasurementsPLC::reset_handler(const String &, Element *e, void *, ErrorHandler *) {
MeasurementsPLC *elmt = (MeasurementsPLC *)e;
elmt->reinitialize_counters();
return 0;
}
int
MeasurementsPLC::debug_handler(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
MeasurementsPLC *elmt = (MeasurementsPLC *)e;
int debug;
if(!cp_integer(s, &debug))
return errh->error("Debug must be 0 or 1");
if (!(debug == 0 || debug == 1))
return errh->error("Debug must be 0 or 1");
if(((intptr_t) arg) == 0)
elmt->set_debug(debug==1);
if(((intptr_t) arg) == 1)
elmt->set_verb_debug(debug==1);
return 0;
}
int
MeasurementsPLC::airtime_handler_write(const String &s, Element *e, void *arg,
ErrorHandler *errh) {
MeasurementsPLC *elmt = (MeasurementsPLC *)e;
if((intptr_t)arg == 0) {
int interval;
if(!cp_integer(s, &interval))
return errh->error("Interval must be an integer (interval in ms)");
elmt->init_airtime(interval, 0);
}
else if ((intptr_t)arg == 1) {
elmt->compute_airtime(0);
}
}
static String
print_handler(Element *e, void *) {
MeasurementsPLC *elmt = (MeasurementsPLC *)e;
StringAccum str;
HashTable<uint8_t, uint64_t> steis = elmt->get_stei_hashtable();
for (HashTable<uint8_t, uint64_t>::iterator it=steis.begin();it != steis.end();++it) {
str << "for STEI " << String((int) it.key()) << ", " << String(it.value()) << " packets received\n";
}
return str.take_string();
}
void MeasurementsPLC::add_handlers() {
add_read_handler("get_airtime", airtime_handler_read,0);
add_read_handler("print_stats", print_handler,0);
add_write_handler("reset", reset_handler, 0);
add_write_handler("debug", debug_handler, 0);
add_write_handler("verb_debug", debug_handler, 1);
add_write_handler("init_airtime", airtime_handler_write, 0);
add_write_handler("compute_airtime", airtime_handler_write, 1);
}
EXPORT_ELEMENT(MeasurementsPLC)
CLICK_ENDDECLS

Event Timeline