Store computed reception time in the message struct so we don't rely on

the message being emitted immediately.

Fix computation of reception time so it's more sensible (the block timestamp
is some time after reception of the _end_ of the block, not the start) - this
means that message-emission times are always later than message-reception
times in SBS output, which is a bit more sensible.

Use clock_gettime in preference to ftime.
This commit is contained in:
Oliver Jowett 2015-02-08 17:46:01 +00:00
parent 1584955080
commit 4e177c2d64
7 changed files with 76 additions and 31 deletions

View file

@ -339,6 +339,11 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
{
mm.timestampMsg = Modes.timestampBlk + ((j+1) * 6);
// compute message receive time as block-start-time + difference in the 12MHz clock
mm.sysTimestampMsg = Modes.stSystemTimeBlk; // end of block time
mm.sysTimestampMsg.tv_nsec -= receiveclock_ns_elapsed(mm.timestampMsg, Modes.timestampBlk + MODES_ASYNC_BUF_SAMPLES * 6); // time until end of block
normalize_timespec(&mm.sysTimestampMsg);
// Decode the received message
decodeModeAMessage(&mm, ModeA);
@ -539,6 +544,12 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
// Set initial mm structure details
mm.timestampMsg = Modes.timestampBlk + (j*6);
// compute message receive time as block-start-time + difference in the 12MHz clock
mm.sysTimestampMsg = Modes.stSystemTimeBlk; // end of block time
mm.sysTimestampMsg.tv_nsec -= receiveclock_ns_elapsed(mm.timestampMsg, Modes.timestampBlk + MODES_ASYNC_BUF_SAMPLES * 6); // time until end of block
normalize_timespec(&mm.sysTimestampMsg);
mm.signalLevel = (365.0*60 + sigLevel + noiseLevel) * (365.0*60 + sigLevel + noiseLevel) / MAX_POWER / 60 / 60;
// Decode the received message

View file

@ -425,6 +425,12 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
// Set initial mm structure details
mm.timestampMsg = Modes.timestampBlk + (j*5) + bestphase;
// compute message receive time as block-start-time + difference in the 12MHz clock
mm.sysTimestampMsg = Modes.stSystemTimeBlk; // end of block time
mm.sysTimestampMsg.tv_nsec -= receiveclock_ns_elapsed(mm.timestampMsg, Modes.timestampBlk + MODES_ASYNC_BUF_SAMPLES * 5); // time until end of block
normalize_timespec(&mm.sysTimestampMsg);
mm.score = bestscore;
mm.bFlags = mm.correctedbits = 0;

View file

@ -173,7 +173,7 @@ void modesInit(void) {
{Modes.net_sndbuf_size = MODES_NET_SNDBUF_MAX;}
// Initialise the Block Timers to something half sensible
ftime(&Modes.stSystemTimeBlk);
clock_gettime(CLOCK_REALTIME, &Modes.stSystemTimeBlk);
for (i = 0; i < MODES_ASYNC_BUF_NUMBER; i++)
{Modes.stSystemTimeRTL[i] = Modes.stSystemTimeBlk;}
@ -357,7 +357,7 @@ void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
Modes.iDataIn &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase!!!
// Get the system time for this block
ftime(&Modes.stSystemTimeRTL[Modes.iDataIn]);
clock_gettime(CLOCK_REALTIME, &Modes.stSystemTimeRTL[Modes.iDataIn]);
if (len > MODES_ASYNC_BUF_SIZE) {len = MODES_ASYNC_BUF_SIZE;}
@ -430,7 +430,7 @@ void readDataFromFile(void) {
Modes.iDataIn &= (MODES_ASYNC_BUF_NUMBER-1); // Just incase!!!
// Get the system time for this block
ftime(&Modes.stSystemTimeRTL[Modes.iDataIn]);
clock_gettime(CLOCK_REALTIME, &Modes.stSystemTimeRTL[Modes.iDataIn]);
// Queue the new data
Modes.pData[Modes.iDataIn] = Modes.pFileData;

View file

@ -71,7 +71,6 @@
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <signal.h>
#include <fcntl.h>
#include <ctype.h>
@ -248,7 +247,7 @@ struct { // Internal state
pthread_mutex_t data_mutex; // Mutex to synchronize buffer access
pthread_cond_t data_cond; // Conditional variable associated
uint16_t *pData [MODES_ASYNC_BUF_NUMBER]; // Raw IQ sample buffers from RTL
struct timeb stSystemTimeRTL[MODES_ASYNC_BUF_NUMBER]; // System time when RTL passed us this block
struct timespec stSystemTimeRTL[MODES_ASYNC_BUF_NUMBER]; // System time when RTL passed us this block
int iDataIn; // Fifo input pointer
int iDataOut; // Fifo output pointer
int iDataReady; // Fifo content count
@ -260,7 +259,7 @@ struct { // Internal state
uint16_t *pFileData; // Raw IQ samples buffer (from a File)
uint16_t *magnitude; // Magnitude vector
uint64_t timestampBlk; // Timestamp of the start of the current block
struct timeb stSystemTimeBlk; // System time when RTL passed us currently processing this block
struct timespec stSystemTimeBlk; // System time when RTL passed us currently processing this block
int fd; // --ifile option file descriptor
uint16_t *maglut; // I/Q -> Magnitude lookup table
uint16_t *log10lut; // Magnitude -> log10 lookup table
@ -367,7 +366,8 @@ struct modesMessage {
uint32_t crc; // Message CRC
int correctedbits; // No. of bits corrected
uint32_t addr; // Address Announced
uint64_t timestampMsg; // Timestamp of the message
uint64_t timestampMsg; // Timestamp of the message (12MHz clock)
struct timespec sysTimestampMsg; // Timestamp of the message (system time)
int remote; // If set this message is from a remote station
double signalLevel; // RSSI, in the range [0..1], as a fraction of full-scale power
int score; // Scoring from scoreModesMessage, if used

View file

@ -347,19 +347,19 @@ void modesSendRawOutput(struct modesMessage *mm) {
// The message structure mm->bFlags tells us what has been updated by this message
//
void modesSendSBSOutput(struct modesMessage *mm) {
char *p = prepareWrite(&Modes.sbs_out, 200);
uint32_t offset;
struct timeb epocTime_receive, epocTime_now;
char *p;
struct timespec now;
struct tm stTime_receive, stTime_now;
int msgType;
if (!p)
return;
// For now, suppress non-ICAO addresses
if (mm->addr & MODES_NON_ICAO_ADDRESS)
return;
p = prepareWrite(&Modes.sbs_out, 200);
if (!p)
return;
//
// SBS BS style output checked against the following reference
// http://www.homepages.mcb.net/bones/SBS/Article/Barebones42_Socket_Data.htm - seems comprehensive
@ -407,32 +407,19 @@ void modesSendSBSOutput(struct modesMessage *mm) {
p += sprintf(p, "MSG,%d,111,11111,%06X,111111,", msgType, mm->addr);
// Find current system time
ftime(&epocTime_now); // get the current system time & date
stTime_now = *localtime(&epocTime_now.time);
clock_gettime(CLOCK_REALTIME, &now);
localtime_r(&now.tv_sec, &stTime_now);
// Find message reception time
if (mm->timestampMsg && !mm->remote) { // Make sure the records' timestamp is valid before using it
epocTime_receive = Modes.stSystemTimeBlk; // This is the time of the start of the Block we're processing
offset = (int) (mm->timestampMsg - Modes.timestampBlk); // This is the time (in 12Mhz ticks) into the Block
offset = offset / 12000; // convert to milliseconds
epocTime_receive.millitm += offset; // add on the offset time to the Block start time
if (epocTime_receive.millitm > 999) { // if we've caused an overflow into the next second...
epocTime_receive.millitm -= 1000;
epocTime_receive.time ++; // ..correct the overflow
}
stTime_receive = *localtime(&epocTime_receive.time);
} else {
epocTime_receive = epocTime_now; // We don't have a usable reception time; use the current system time
stTime_receive = stTime_now;
}
localtime_r(&mm->sysTimestampMsg.tv_sec, &stTime_receive);
// Fields 7 & 8 are the message reception time and date
p += sprintf(p, "%04d/%02d/%02d,", (stTime_receive.tm_year+1900),(stTime_receive.tm_mon+1), stTime_receive.tm_mday);
p += sprintf(p, "%02d:%02d:%02d.%03d,", stTime_receive.tm_hour, stTime_receive.tm_min, stTime_receive.tm_sec, epocTime_receive.millitm);
p += sprintf(p, "%02d:%02d:%02d.%03u,", stTime_receive.tm_hour, stTime_receive.tm_min, stTime_receive.tm_sec, (unsigned) (mm->sysTimestampMsg.tv_nsec / 1000000U));
// Fields 9 & 10 are the current time and date
p += sprintf(p, "%04d/%02d/%02d,", (stTime_now.tm_year+1900),(stTime_now.tm_mon+1), stTime_now.tm_mday);
p += sprintf(p, "%02d:%02d:%02d.%03d", stTime_now.tm_hour, stTime_now.tm_min, stTime_now.tm_sec, epocTime_now.millitm);
p += sprintf(p, "%02d:%02d:%02d.%03u", stTime_now.tm_hour, stTime_now.tm_min, stTime_now.tm_sec, (unsigned) (now.tv_nsec / 1000000U));
// Field 11 is the callsign (if we have it)
if (mm->bFlags & MODES_ACFLAGS_CALLSIGN_VALID) {p += sprintf(p, ",%s", mm->flight);}
@ -574,6 +561,9 @@ int decodeBinMessage(struct client *c, char *p) {
if (0x1A == ch) {p++;}
}
// record reception time as the time we read it.
clock_gettime(CLOCK_REALTIME, &mm.sysTimestampMsg);
ch = *p++; // Grab the signal level
mm.signalLevel = ((unsigned char)ch / 256.0);
mm.signalLevel = mm.signalLevel * mm.signalLevel + 1e-5;
@ -697,6 +687,9 @@ int decodeHexMessage(struct client *c, char *hex) {
msg[j/2] = (high << 4) | low;
}
// record reception time as the time we read it.
clock_gettime(CLOCK_REALTIME, &mm.sysTimestampMsg);
if (l == (MODEAC_MSG_BYTES * 2)) { // ModeA or ModeC
Modes.stats_current.remote_received_modeac++;
decodeModeAMessage(&mm, ((msg[0] << 8) | msg[1]));

22
util.c
View file

@ -62,3 +62,25 @@ uint64_t mstime(void)
mst += tv.tv_usec/1000;
return mst;
}
uint64_t receiveclock_ns_elapsed(uint64_t t1, uint64_t t2)
{
if (t2 < t1) {
// wrapped.
return (~(t1 - t2) + 1) * 1000U / 12U;
} else {
return (t2 - t1) * 1000U / 12U;
}
}
void normalize_timespec(struct timespec *ts)
{
if (ts->tv_nsec > 1000000000) {
ts->tv_sec += ts->tv_nsec / 1000000000;
ts->tv_nsec = ts->tv_nsec % 1000000000;
} else if (ts->tv_nsec < 0) {
long adjust = ts->tv_nsec / 1000000000 + 1;
ts->tv_sec -= adjust;
ts->tv_nsec = (ts->tv_nsec + 1000000000 * adjust) % 1000000000;
}
}

13
util.h
View file

@ -22,6 +22,19 @@
#include <stdint.h>
/* Returns system time in milliseconds */
uint64_t mstime(void);
/* Returns the time elapsed, in nanoseconds, from t1 to t2,
* where t1 and t2 are 12MHz counters,
* accounting for wrapping.
*/
uint64_t receiveclock_ns_elapsed(uint64_t t1, uint64_t t2);
/* Normalize the value in ts so that ts->nsec lies in
* [0,999999999]
*/
struct timespec;
void normalize_timespec(struct timespec *ts);
#endif