Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F120523358
measurementsplc.cc
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sat, Jul 5, 00:05
Size
14 KB
Mime Type
text/x-c
Expires
Mon, Jul 7, 00:05 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
27186296
Attached To
R6591 HyMAB
measurementsplc.cc
View Options
#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
Log In to Comment