Stefan Richter wrote:
Pieter Palmers wrote:
Stefan Richter wrote:
...
- Fix integer overflow.
I had to use 1000000ULL instead of USEC_PER_SEC to avoid weird behavior.
OK, I'll change that and will wait for...
I can't test it right now, but I'll report later.
...your and Dan's ACK before I commit the patch.
Stefan,
I tested the patches as posted on bugzilla, and it looks like it is
working fine.
I attached a test program I used while writing/debugging the patches.
Might be useful for other people to test if this works correctly.
Compile:
$ gcc -g -o ctr_test -lraw1394 ctr_test.c
Run:
$ ./ctr_test
libraw1394 Cycle Timer API test application
using port 0
init rate=24.5837
Local time: 1170593509294313us, 1170593509294.313ms (approx 38year,
20day since epoch)
CycleTimer: 67s, 2323cy, 1894ticks
rate: 24.583702ticks/usec
Local time: 1170593510294462us, 1170593510294.462ms (approx 38year,
20day since epoch)
CycleTimer: 68s, 2328cy, 2044ticks
rate: 24.587107ticks/usec
The rate should be something around 24.576.
Since epoch is somewhere around 1970, the approx 38 years looks rather
correct.
Greets,
Pieter
/* Parts of this are originally from:
*
* FreeBob = Firewire (pro-)audio for linux
*
* http://freebob.sf.net
*
* Copyright (C) 2005,2006,2007 Pieter Palmers <[email protected]>
*
* This program is free software {} you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation {} either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY {} without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program {} if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
compile:
gcc -g -o ctr_test -lraw1394 ctr_test.c
*/
#include <libraw1394/raw1394.h>
#include <stdio.h>
#include <errno.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <inttypes.h>
// Some configuration constants
#define CC_SLEEP_TIME_AFTER_DLL_UPDATE 2000
#define CC_DLL_COEFF (0.0001)
#define CC_INIT_MAX_TRIES 10
#define USECS_BETWEEN_PRINT (1000000LLU)
// Definitions and utility macro's to handle the ISO cycle timer
#define CYCLES_PER_SECOND 8000u
#define TICKS_PER_CYCLE 3072u
#define TICKS_PER_SECOND 24576000u
#define TICKS_PER_USEC (TICKS_PER_SECOND/1000000.0)
#define CYCLE_COUNTER_GET_SECS(x) ((((x) & 0xFE000000) >> 25))
#define CYCLE_COUNTER_GET_CYCLES(x) ((((x) & 0x01FFF000) >> 12))
#define CYCLE_COUNTER_GET_OFFSET(x) ((((x) & 0x00000FFF)))
#define CYCLE_COUNTER_TO_TICKS(x) ((CYCLE_COUNTER_GET_SECS(x) * TICKS_PER_SECOND) +\
(CYCLE_COUNTER_GET_CYCLES(x) * TICKS_PER_CYCLE ) +\
(CYCLE_COUNTER_GET_OFFSET(x) ))
#define CYCLE_COUNTER_UNWRAP_TICKS(x) ((x) \
+ (127 * TICKS_PER_SECOND) \
+ (CYCLES_PER_SECOND * TICKS_PER_CYCLE) \
+ (TICKS_PER_CYCLE) \
)
// globals
uint64_t m_lastmeas_usecs;
unsigned int m_cyclecounter_ticks;
double m_ticks_per_usec;
// signal handler
int keep_running=1;
static void sighandler (int sig)
{
keep_running = 0;
}
// DLL functions
int init_dll(uint64_t usecs1, unsigned int ticks1,
uint64_t usecs2, unsigned int ticks2) {
double rate=0.0;
unsigned int delta_ticks;
if (ticks2 > ticks1) {
delta_ticks=ticks2 - ticks1;
} else { // wraparound
delta_ticks=CYCLE_COUNTER_UNWRAP_TICKS(ticks2) - ticks1;
}
int delta_usecs=usecs2-usecs1;
rate=((double)delta_ticks/(double)delta_usecs);
// update the internal values
m_cyclecounter_ticks=ticks2;
m_lastmeas_usecs=usecs2;
m_ticks_per_usec=rate;
printf("init rate=%6.4f\n", rate);
}
int update_dll(uint64_t new_usecs, unsigned int new_ticks) {
uint64_t prev_usecs=m_lastmeas_usecs;
unsigned int prev_ticks=m_cyclecounter_ticks;
// the difference in system time
int delta_usecs=new_usecs-prev_usecs;
// the measured cycle counter difference
long unsigned int delta_ticks_meas;
if (new_ticks > prev_ticks) {
delta_ticks_meas=new_ticks - prev_ticks;
} else { // wraparound
delta_ticks_meas=CYCLE_COUNTER_UNWRAP_TICKS(new_ticks) - prev_ticks;
}
// the estimated cycle counter difference
unsigned int delta_ticks_est=(unsigned int)(m_ticks_per_usec * ((double)delta_usecs));
// the measured & estimated rate
double rate_meas=((double)delta_ticks_meas/(double)delta_usecs);
double rate_est=((double)m_ticks_per_usec);
int diff=(int)delta_ticks_est;
// calculate the difference in predicted ticks and
// measured ticks
diff -= delta_ticks_meas;
if (diff > 24000 || diff < -24000) { // approx +/-1 msec error
printf("Bad pred: diff=%d, dt_est=%u, dt_meas=%u, d=%dus, err=%fus\n",
diff, delta_ticks_est, delta_ticks_meas, delta_usecs, (((double)diff)/24.576)
);
}
// calculate the error
double err=rate_meas-rate_est;
// first order DLL update to obtain the rate.
m_ticks_per_usec += CC_DLL_COEFF*err;
// update the internal values
m_cyclecounter_ticks += delta_ticks_est;
// if we need to wrap, do it
if (m_cyclecounter_ticks > TICKS_PER_SECOND * 128) {
m_cyclecounter_ticks -= TICKS_PER_SECOND * 128;
}
m_lastmeas_usecs = new_usecs;
return 0;
}
// main
int32_t main(int32_t argc, char **argv)
{
int port=0;
raw1394handle_t handle;
uint64_t last_local_time=0;
struct raw1394_cycle_timer ctr;
struct raw1394_cycle_timer ctr2;
int err;
printf("libraw1394 Cycle Timer API test application\n");
if (argc==2) {
port = atoi(argv[1]);
}
printf("using port %d\n",port);
// get handle
handle = raw1394_new_handle_on_port(port);
if (handle == NULL) {
perror("raw1394_new_handle");
return -1;
}
// register signal handler
signal (SIGINT, sighandler);
signal (SIGPIPE, sighandler);
// init the DLL
err=raw1394_read_cycle_timer(handle, &ctr);
if(err) {
perror("raw1394_read_cycle_timer");
}
usleep(CC_SLEEP_TIME_AFTER_DLL_UPDATE);
err=raw1394_read_cycle_timer(handle, &ctr2);
if(err) {
perror("raw1394_read_cycle_timer");
}
init_dll(ctr.local_time,CYCLE_COUNTER_TO_TICKS(ctr.cycle_timer),
ctr2.local_time,CYCLE_COUNTER_TO_TICKS(ctr2.cycle_timer));
usleep(CC_SLEEP_TIME_AFTER_DLL_UPDATE);
printf("\n");
// start the monitor loop
while (keep_running) {
ctr.local_time=0;
err=raw1394_read_cycle_timer(handle, &ctr);
if(err) {
perror("raw1394_read_cycle_timer");
} else {
uint64_t local_time_usec=ctr.local_time;
double local_time_msec=(double)local_time_usec;
unsigned int offset=CYCLE_COUNTER_GET_OFFSET(ctr.cycle_timer);
unsigned int cycles=CYCLE_COUNTER_GET_CYCLES(ctr.cycle_timer);
unsigned int secs=CYCLE_COUNTER_GET_SECS(ctr.cycle_timer);
local_time_msec /= 1000.0;
update_dll(ctr.local_time,CYCLE_COUNTER_TO_TICKS(ctr.cycle_timer));
if ((ctr.local_time - last_local_time) > USECS_BETWEEN_PRINT) {
const uint64_t usecs_per_day=24LLU*60LLU*60LLU*1000000LLU;
const uint64_t usecs_per_year=356LLU*usecs_per_day;
uint64_t years=local_time_usec/usecs_per_year;
uint64_t days=local_time_usec%usecs_per_year;
days /= usecs_per_day;
printf("Local time: %16lluus, %16.3fms (approx %2lluyear, %3lluday since epoch)\n",
local_time_usec,local_time_msec, years, days);
printf("CycleTimer: %3us, %4ucy, %4uticks\n",secs,cycles,offset);
printf(" rate: %10.6fticks/usec\n\n",m_ticks_per_usec);
last_local_time=ctr.local_time;
}
}
usleep(CC_SLEEP_TIME_AFTER_DLL_UPDATE);
}
return 0;
}
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]