/*
 * timedsink.{cc,hh} -- element creates packets, pushes them periodically
 * Eddie Kohler
 *
 * Copyright (c) 1999-2000 Massachusetts Institute of Technology
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, subject to the conditions
 * listed in the Click LICENSE file. These conditions include: you must
 * preserve this copyright notice, and you cannot mention the copyright
 * holders in advertising related to the Software without their permission.
 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
 * notice is a summary of the Click LICENSE file; the license in that file is
 * legally binding.
 */

#include <click/config.h>
#include "timedsource.hh"
#include <click/confparse.hh>
#include <click/error.hh>
#include <click/glue.hh>
#include <click/router.hh>
CLICK_DECLS

TimedSource::TimedSource()
  : _packet(0), _timer(this)
{
}

TimedSource::~TimedSource()
{
}

int
TimedSource::configure(Vector<String> &conf, ErrorHandler *errh)
{
  String data = "Random bullshit in a packet, at least 64 bytes long. Well, now it is.";
  int limit = -1;
  int interval = 500;
  bool active = true, stop = false;

  if (cp_va_parse(conf, this, errh,
		  cpOptional,
		  cpSecondsAsMilli, "packet generation interval", &interval,
		  cpString, "packet data", &data,
		  cpKeywords,
		  "DATA", cpString, "packet data", &data,
		  "INTERVAL", cpSecondsAsMilli, "packet generation interval", &interval,
		  "LIMIT", cpInteger, "total packet count", &limit,
		  "ACTIVE", cpBool, "active?", &active,
		  "STOP", cpBool, "stop driver when done?", &stop,
		  cpEnd) < 0)
    return -1;

  _data = data;
  _interval = interval;
  _limit = limit;
  _count = 0;
  _active = active;
  _stop = stop;
  if (_packet) _packet->kill();
  _packet = Packet::make(_data.data(), _data.length());
  return 0;
}

int
TimedSource::initialize(ErrorHandler *)
{
  _timer.initialize(this);
  if (_active)
    _timer.schedule_after_msec(_interval);
  return 0;
}

void
TimedSource::cleanup(CleanupStage)
{
  if (_packet)
    _packet->kill();
  _packet = 0;
}

void
TimedSource::run_timer(Timer *)
{
    if (!_active)
	return;
    if (_limit < 0 || _count < _limit) {
	Packet *p = _packet->clone();
	p->timestamp_anno().set_now();
	output(0).push(p);
	_count++;
	_timer.reschedule_after_msec(_interval);
    } else if (_stop)
	router()->please_stop_driver();
}

String
TimedSource::read_param(Element *e, void *vparam)
{
  TimedSource *ts = (TimedSource *)e;
  switch ((intptr_t)vparam) {
   case 0:			// data
    return ts->_data;
   case 1:			// limit
    return String(ts->_limit);
   case 2:			// interval
    return cp_unparse_milliseconds(ts->_interval);
   case 3:			// active
    return cp_unparse_bool(ts->_active);
   case 4:			// count
    return String(ts->_count);
   default:
    return "";
  }
}

int
TimedSource::change_param(const String &in_s, Element *e, void *vparam,
			  ErrorHandler *errh)
{
  TimedSource *ts = (TimedSource *)e;
  String s = cp_uncomment(in_s);
  switch ((intptr_t)vparam) {

  case 0:			// data
      ts->_data = in_s;
      if (ts->_packet)
	  ts->_packet->kill();
      ts->_packet = Packet::make(ts->_data.data(), ts->_data.length());
      break;
   
   case 1: {			// limit
     int limit;
     if (!cp_integer(s, &limit))
       return errh->error("limit parameter must be integer");
     ts->_limit = limit;
     break;
   }
   
   case 2: {			// interval
     uint32_t interval;
     if (!cp_seconds_as_milli(s, &interval) || interval < 1)
       return errh->error("interval parameter must be integer >= 1");
     ts->_interval = interval;
     break;
   }
   
   case 3: {			// active
     bool active;
     if (!cp_bool(s, &active))
       return errh->error("active parameter must be boolean");
     ts->_active = active;
     if (!ts->_timer.scheduled() && active)
       ts->_timer.schedule_now();
     break;
   }

   case 5: {			// reset
     ts->_count = 0;
     if (!ts->_timer.scheduled() && ts->_active)
       ts->_timer.schedule_now();
     break;
   }

  }
  return 0;
}

void
TimedSource::add_handlers()
{
  add_read_handler("data", read_param, (void *)0);
  add_write_handler("data", change_param, (void *)0);
  set_handler_flags("data", Handler::RAW);
  add_read_handler("limit", read_param, (void *)1);
  add_write_handler("limit", change_param, (void *)1);
  add_read_handler("interval", read_param, (void *)2);
  add_write_handler("interval", change_param, (void *)2);
  add_read_handler("active", read_param, (void *)3);
  add_write_handler("active", change_param, (void *)3);
  add_read_handler("count", read_param, (void *)4);
  add_write_handler("reset", change_param, (void *)5);
}

CLICK_ENDDECLS
EXPORT_ELEMENT(TimedSource)
ELEMENT_MT_SAFE(TimedSource)


syntax highlighted by Code2HTML, v. 0.9.1