/* Parts of this are originally from: * * FreeBob = Firewire (pro-)audio for linux * * http://freebob.sf.net * * Copyright (C) 2005,2006,2007 Pieter Palmers * * 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 #include #include #include #include #include #include #include // 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; }