Code Search for Developers
 
 
  

misc_time.c from EmStar at Krugle


Show misc_time.c syntax highlighted

/*
 *
 * Copyright (c) 2003 The Regents of the University of California.  All 
 * rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Neither the name of the University nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
 

/*
 * time-related utilities
 *
 * part of libmisc
 *
 * $Id: misc_time.c,v 1.26 2005/10/29 23:15:30 cerpa Exp $
 */

char misc_time_c_cvsid[] = "$Id: misc_time.c,v 1.26 2005/10/29 23:15:30 cerpa Exp $";

#include "misc.h"
#include <time.h>

/* resolve seconds carry */
static inline void update_tv(struct timeval *t1)
{
  if (t1->tv_usec >= MILLION_I) {
    t1->tv_sec++;
    t1->tv_usec -= MILLION_I;
  }
  if (t1->tv_usec < 0) {
    t1->tv_sec--;
    t1->tv_usec += MILLION_I;
  }
}

//
//  struct timeval subtraction: t1 -= t2: negative values OK
//

void misc_tv_sub_neg(struct timeval *t1, const struct timeval *t2)
{
  t1->tv_sec -= t2->tv_sec;
  t1->tv_usec -= t2->tv_usec;
  update_tv(t1);
}



//
//  struct timeval subtraction: t1 -= t2: negative values turned into 0
//

int misc_tv_sub(struct timeval *t1, const struct timeval *t2)
{
  misc_tv_sub_neg(t1, t2);

  if (t1->tv_sec < 0) {
    t1->tv_sec = t1->tv_usec = 0;
    return 1;
  }

  return 0;
}



//
//  struct timeval comparison function
//


int misc_tv_cmp(struct timeval *t1, struct timeval *t2)
{
  int cmp = t1->tv_sec - t2->tv_sec;
  if (cmp) return cmp;
  return t1->tv_usec - t2->tv_usec;
}


static void copy_or_gettimeofday(struct timeval *dest, const struct timeval *src)
{
  if (src)
    memcpy(dest, src, sizeof(*dest));
  else
    gettimeofday(dest, NULL);
}

long misc_tv_offset_neg(const struct timeval *late,
			const struct timeval *early)
{
  struct timeval tmp;

  copy_or_gettimeofday(&tmp, late);
  misc_tv_sub_neg(&tmp, early);
  return tmp.tv_sec * MILLION_I + tmp.tv_usec;
}

int64_t misc_tv_offset_neg64(const struct timeval *late,
			     const struct timeval *early)
{
  struct timeval tmp;

  copy_or_gettimeofday(&tmp, late);
  return tv_to_ll(&tmp) - tv_to_ll(early);
}

unsigned long misc_tv_offset(const struct timeval *late,
			     const struct timeval *early)
{
  struct timeval tmp;

  copy_or_gettimeofday(&tmp, late);
  misc_tv_sub(&tmp, early);
  return tmp.tv_sec * MILLION_I + tmp.tv_usec;
}


long misc_tv_offset_neg_msec(const struct timeval *late,
			     const struct timeval *early)
{
  struct timeval tmp;

  copy_or_gettimeofday(&tmp, late);
  misc_tv_sub_neg(&tmp, early);
  return (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
}

unsigned long misc_tv_offset_msec(const struct timeval *late,
				  const struct timeval *early)
{
  struct timeval tmp;

  copy_or_gettimeofday(&tmp, late);
  misc_tv_sub(&tmp, early);
  return (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
}

//
// simple function for computing how many msec since the last time
// something happened -- but with protection for the clock going
// backwards.  if the result is negative *and* more than 1ms, a very 
// large positive number is returned, i.e. to make it look like the 
// event happened far in the past so it'll happen again.  If the 
// difference is negative but less than 2ms, we return zero.  The 
// reason here is that small time differences that do not really 
// account for events in the future but events that are very close in
// time that may have been scheduled in advance.  The prime example of
// this is the Emstar sim_radio, that may schedule recv_time of packet 
// arrival before it acutally happens.  We picked 2ms as a guard band.
// The last comment is a pseudo-hack!  The real fix would be to fix 
// this in the simulator.
//

unsigned long msec_since(const struct timeval *when)
{
  long elapsed = misc_tv_offset_neg_msec(NULL, when);

  if (elapsed < -2)
    return (1 << 30);
  if (elapsed < 0)
    return 0;
  else
    return elapsed;
}


//
//
///////// timeval addition ///////////
//
//


//
// timeval add: t1 += t2
//

void misc_tv_add(struct timeval *t1, struct timeval *t2)
{
  t1->tv_sec += t2->tv_sec;
  t1->tv_usec += t2->tv_usec;
  update_tv(t1);
}


/* add an int (milliseconds) to a timeval */
void misc_tv_addms(struct timeval *t1, long ms)
{
  t1->tv_sec += (ms / 1000);
  t1->tv_usec += 1000*(ms % 1000);
  update_tv(t1);
}


/* add an int (microseconds) to a timeval */
void misc_tv_addus(struct timeval *t1, long us)
{
  t1->tv_sec += us / MILLION_I;
  t1->tv_usec += us % MILLION_I;
  update_tv(t1);
}


int misc_tv_overlap(struct timeval *tv1, int ms_dur1, struct timeval *tv2, int ms_dur2,
		    struct timeval *end)
{
  struct timeval end1;
  struct timeval end2;
  
  memcpy(&end1, tv1, sizeof(end1));
  misc_tv_addms(&end1, ms_dur1);
  
  memcpy(&end2, tv2, sizeof(end2));
  misc_tv_addms(&end2, ms_dur2);
  
  // collision?
  if (((misc_tv_cmp(tv1, tv2) >= 0) &&
       (misc_tv_cmp(tv1, &end2) < 0)) ||
      ((misc_tv_cmp(tv2, tv1) >= 0) &&
       (misc_tv_cmp(tv2, &end1) < 0))) {
    
    if (end) {
      if (misc_tv_cmp(&end1, &end2) < 0) 
	memcpy(end, &end2, sizeof(*end));
      else
	memcpy(end, &end1, sizeof(*end));
    }
    
    return 1;
  }
  
  return 0;
}    


int misc_tv_overlap_us(struct timeval *tv1, int us_dur1, struct timeval *tv2, int us_dur2,
		       struct timeval *end)
{
  struct timeval end1;
  struct timeval end2;
  
  memcpy(&end1, tv1, sizeof(end1));
  misc_tv_addus(&end1, us_dur1);
  
  memcpy(&end2, tv2, sizeof(end2));
  misc_tv_addus(&end2, us_dur2);
  
  // collision?
  if (((misc_tv_cmp(tv1, tv2) >= 0) &&
       (misc_tv_cmp(tv1, &end2) < 0)) ||
      ((misc_tv_cmp(tv2, tv1) >= 0) &&
       (misc_tv_cmp(tv2, &end1) < 0))) {
    
    if (end) {
      if (misc_tv_cmp(&end1, &end2) < 0) 
	memcpy(end, &end2, sizeof(*end));
      else
	memcpy(end, &end1, sizeof(*end));
    }
    
    return 1;
  }
  
  return 0;
}    



/* Convert a timeval to microseconds as a long */
long misc_tv_usec_l(struct timeval *t)
{
  return ((long) t->tv_sec * MILLION_I) + t->tv_usec;
}

/* Convert a timeval to microseconds as a float */
float misc_tv_usec_f(struct timeval *t)
{
  return ((float) t->tv_sec * MILLION_F) + t->tv_usec;
}

/* Convert a timeval to milliseconds as a float */
float misc_tv_msec_f(struct timeval *t)
{
  return misc_tv_usec_f(t) / 1000.0;
}

/* Convert a timeval to seconds as a float */
float misc_tv_sec_f(struct timeval *t)
{
  return misc_tv_usec_f(t) / MILLION_F;
}



// convert a timeval to microseconds as a long
long misc_tv_usec_l(struct timeval *t);

// convert a timeval to seconds or milliseconds as a float
float misc_tv_msec_f(struct timeval *t);
float misc_tv_sec_f(struct timeval *t);



////////////////// Printing Functions /////////////////////////

//
// convert timeval to a string like  "Tue Jul 20 14:52:18 PDT 2004"
//
// this is basically an interface to asctime, but
// 1 -- it takes a timeval rather than an int
// 2 -- has a static buf ring so it can be called multiple times from
// printf without overwriting previous results
// 3 -- removes the trailing lf for you
//
char *misc_print_date(const struct timeval *tv)
{
  DECLARE_STATIC_BUF_RING(buf, 3, 32);

  if (tv->tv_sec == 0 && tv->tv_usec == 0)
    return "never";
  else {
    sprintf(buf, asctime(localtime(&tv->tv_sec)));
    misc_strip_trailing_crlfs(buf);
    return buf;
  }
}

// convert timeval to a localtime string like  "Tue Jul 20 14:52:18 PDT 2004"
// where format in this example is   "%a %b %e %T %Z %Y"
// see the strftime() function for more choices
char *misc_print_formated_date(const struct timeval *tv, const char *format) {
  DECLARE_STATIC_BUF_RING(buf, 3, 64);
  if (tv->tv_sec == 0 && tv->tv_usec == 0)
    return "never";
  else {
    strftime(buf, 64, format, localtime(&tv->tv_sec));
    misc_strip_trailing_crlfs(buf);
    return buf;
  }
}

// convert a timeval to a floating point-like string, e.g. "12345.006789"
char *misc_tv_to_str(const struct timeval *tv)
{
  DECLARE_STATIC_BUF_RING(buf, 3, 24);
  struct timeval tmp;

  if (tv) {
    memcpy(&tmp, tv, sizeof(tmp));

    /* this strangeness is to make negative numbers "look right": the
     * internal representation doesn't look the same as what we expect */
    if (tmp.tv_sec < 0 && tmp.tv_usec > 0) {
      tmp.tv_sec++;
      tmp.tv_usec = MILLION_I - tmp.tv_usec;
    }
    sprintf(buf, "%ld.%06ld", tmp.tv_sec, tmp.tv_usec);
    return buf;
  }
  return NULL;
}



char *misc_secs_to_str(int t)
{
  DECLARE_STATIC_BUF_RING(sbuf, 3, 32);
  buf_t *b = buf_new();
  int tmp;

  if (t == 0) {
    buf_free(b);
    return "0s";
  }

  if ((tmp = (t / 86400)) > 0) {
    bufprintf(b, " %dd", tmp);
    t %= 86400;
  }

  if ((tmp = (t / 3600)) > 0) {
    bufprintf(b, " %dh", tmp);
    t %= 3600;
  }

  if ((tmp = (t / 60)) > 0) {
    bufprintf(b, " %dm", tmp);
    t %= 60;
  }

  if (t)
    bufprintf(b, " %ds", t);

  strcpy(sbuf, b->buf+1);
  buf_free(b);
  return sbuf;
}


int64_t misc_timeval_to_int64(struct timeval *tv)
{
  int64_t clock = tv->tv_sec;
  clock *= MILLION_I;
  clock += tv->tv_usec;
  return clock;
}


void misc_int64_to_timeval(struct timeval *tv, int64_t index)
{
  tv->tv_usec = index % MILLION_I;
  tv->tv_sec = index / MILLION_I;
}

void misc_str_to_tv(char* time_str, struct timeval *tv)
{
  int i;
  int64_t time;
  double time2;
  char *decimal, intVal[30];

  if (time_str) {
    time = 0;
    time2 = 0;
    decimal = strpbrk(time_str, ".");

    /* Just get integer */
    for (i = 0; i < strcspn(time_str, ".") + 1; i++)
      intVal[i] = 0;

    strncpy(intVal, time_str, strcspn(time_str, "."));

    if (intVal[0] != 0) {
      time2 = atof(intVal);

      /* convert to micro-seconds */
      time = time2 * MILLION_F;
    }

    if (decimal) {

      /* conv decimal to usec */
      time2 = atof(decimal) * MILLION_F;
      time += time2;
    }

    /* Check for negative num, and if translated correctly */
    if (atof(time_str) < 0)
      time = time * (time < 0 ? 1 : -1);
  }

  else
    time = 0;

  misc_int64_to_timeval(tv, time);
}


static struct timeval elapsed_time = {};
static struct timeval sys_elapsed_time = {};


/* returns current elapsed time since start of program */
uint64_t misc_time_elapsed()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  misc_tv_sub_neg(&tv, &elapsed_time);
  return misc_timeval_to_int64(&tv);
}


/* returns current elapsed time since start of system (from emrun) */
uint64_t misc_time_elapsed_sys()
{
  struct timeval tv;
  gettimeofday(&tv, NULL);
  misc_tv_sub_neg(&tv, &sys_elapsed_time);
  return misc_timeval_to_int64(&tv);
}


void misc_time_get_start(struct timeval *tv)
{
  *tv = elapsed_time;
}

int64_t misc_time_get_sys_start64()
{
  return misc_timeval_to_int64(&sys_elapsed_time);
}

int64_t misc_time_get_start64()
{
  return misc_timeval_to_int64(&elapsed_time);
}



/* resets the start time -- called by misc_init() */
void misc_time_set_start(struct timeval *tv)
{
  if (tv)
    elapsed_time = *tv;
  else 
    gettimeofday(&elapsed_time, NULL);
}

/* resets the start time -- called by emrun_init() */
void misc_time_set_sys_start(struct timeval *tv)
{
  sys_elapsed_time = *tv;
}


#define MAX_BUSYWAIT  10000

void misc_busy_wait(int microseconds)
{
  struct timeval start;
  gettimeofday(&start, NULL);
  while (1) {
    struct timeval now;
    gettimeofday(&now, NULL);
    long int micros = misc_tv_offset_neg(&now, &start);
    if (micros < 0) {
      elog(LOG_WARNING, "Time went backwards??");
      return;
    }
    if (micros > microseconds)
      return;
    if ((microseconds - micros) > MAX_BUSYWAIT)
      usleep((microseconds - micros) - MAX_BUSYWAIT);
  }      
}


void misc_busy_wait_until(struct timeval *tv)
{
  while (1) {
    struct timeval now;
    gettimeofday(&now, NULL);
    if (misc_tv_cmp(&now, tv) > 0) return;
    uint64_t micros = tv_to_ll(tv) - tv_to_ll(&now);
    if (micros > MILLION_I)
      sleep(micros/MILLION_I);
    else
      if (micros > MAX_BUSYWAIT)
	usleep(micros - MAX_BUSYWAIT);
  }      
}




See more files for this project here

EmStar

EmStar is a software system for developing and deploying wireless sensor networks involving Linux-based platforms. As the wireless sensor network community has attempted to deploy more complex designs---large-scale, long-lived systems that need self-organization and adaptivity---a number of difficult software design issues have arisen. Advances in software design have not kept pace with the capabilities of hardware. This is because designing for an adaptive, efficient, and useful sensor network has turned out to be surprisingly complex and difficult. EmStar is a Linux-based software framework, whose goal is to dramatically reduce this complexity, enabling work to be shared and reused, and simplifying and speeding the design of new sensor network applications.

Project homepage: http://cvs.cens.ucla.edu/emstar/
Programming language(s): C,Shell Script
License: other

  elog.c
  elog_emit.c
  file.c
  misc_angles.c
  misc_buf.c
  misc_crc32.c
  misc_filename.c
  misc_hash.c
  misc_init.c
  misc_lock.c
  misc_math.c
  misc_namelist.c
  misc_network.c
  misc_nmea.c
  misc_opt.c
  misc_parse.c
  misc_proc.c
  misc_random.c
  misc_ringbuff.c
  misc_serial.c
  misc_signals.c
  misc_sim.c
  misc_time.c
  misc_types.c
  misc_version.c
  string.c