Split the int timestamp from frac timestamp so you don't lose precision when using, say, UTC time. Cleaned up some cruft while I was at it. This also allows devices which don't have timestamps to tag based on samples elapsed since the flowgraph started.
This commit is contained in:
@@ -47,7 +47,8 @@ private:
|
|||||||
int d_samples_per_chip;
|
int d_samples_per_chip;
|
||||||
int d_samples_per_symbol;
|
int d_samples_per_symbol;
|
||||||
gr_msg_queue_sptr d_queue;
|
gr_msg_queue_sptr d_queue;
|
||||||
std::ostringstream d_payload;
|
unsigned char d_lowconfbits[24];
|
||||||
|
unsigned char d_data[14];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int work (int noutput_items,
|
int work (int noutput_items,
|
||||||
|
|||||||
@@ -24,20 +24,6 @@
|
|||||||
#define AIR_MODES_TYPES_H
|
#define AIR_MODES_TYPES_H
|
||||||
|
|
||||||
typedef enum { No_Packet = 0, Short_Packet = 1, Fruited_Packet = 2, Long_Packet = 3 } framer_packet_type;
|
typedef enum { No_Packet = 0, Short_Packet = 1, Fruited_Packet = 2, Long_Packet = 3 } framer_packet_type;
|
||||||
typedef enum { No_Error = 0, Solution_Found, Too_Many_LCBs, No_Solution, Multiple_Solutions } bruteResultTypeDef;
|
|
||||||
|
|
||||||
struct modes_packet {
|
|
||||||
unsigned char data[14];
|
|
||||||
// unsigned char confidence[14]; //112 bits of boolean high/low confidence data for each bit
|
|
||||||
unsigned char lowconfbits[24]; //positions of low confidence bits within the packet
|
|
||||||
|
|
||||||
unsigned long crc;
|
|
||||||
unsigned int numlowconf;
|
|
||||||
framer_packet_type type; //what length packet are we
|
|
||||||
unsigned int message_type;
|
|
||||||
float reference_level;
|
|
||||||
double timestamp;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct slice_result_t {
|
struct slice_result_t {
|
||||||
bool decision;
|
bool decision;
|
||||||
|
|||||||
@@ -24,7 +24,4 @@
|
|||||||
#define INCLUDED_MODES_CRC_H
|
#define INCLUDED_MODES_CRC_H
|
||||||
extern const unsigned int modes_crc_table[112];
|
extern const unsigned int modes_crc_table[112];
|
||||||
int modes_check_crc(unsigned char data[], int length);
|
int modes_check_crc(unsigned char data[], int length);
|
||||||
bruteResultTypeDef modes_ec_brute(modes_packet &err_packet);
|
|
||||||
unsigned next_set_of_n_elements(unsigned x);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+26
-17
@@ -78,20 +78,31 @@ static double correlate_preamble(const float *in, int samples_per_chip) {
|
|||||||
return corr;
|
return corr;
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: make it return a pair of some kind, otherwise you can lose precision
|
//takes an rx tag and issues a tag offset appropriately for the preamble
|
||||||
static double tag_to_timestamp(gr_tag_t tstamp, uint64_t abs_sample_cnt, double secs_per_sample) {
|
static const pmt::pmt_t offset_stamp(const gr_tag_t &tstamp, const uint64_t abs_sample_cnt, const double secs_per_sample) {
|
||||||
uint64_t ts_sample, last_whole_stamp;
|
uint64_t ts_sample, last_whole_stamp;
|
||||||
double last_frac_stamp;
|
double last_frac_stamp;
|
||||||
|
|
||||||
if(tstamp.key == NULL || pmt::pmt_symbol_to_string(tstamp.key) != "rx_time") return 0;
|
if(tstamp.key == NULL || pmt::pmt_symbol_to_string(tstamp.key) != "rx_time") {
|
||||||
|
last_whole_stamp = 0;
|
||||||
|
last_frac_stamp = 0;
|
||||||
|
ts_sample = 0;
|
||||||
|
} else {
|
||||||
|
last_whole_stamp = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tstamp.value, 0));
|
||||||
|
last_frac_stamp = pmt::pmt_to_double(pmt::pmt_tuple_ref(tstamp.value, 1));
|
||||||
|
ts_sample = tstamp.offset;
|
||||||
|
}
|
||||||
|
|
||||||
last_whole_stamp = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tstamp.value, 0));
|
double fractime = double(abs_sample_cnt * secs_per_sample) + last_frac_stamp;
|
||||||
last_frac_stamp = pmt::pmt_to_double(pmt::pmt_tuple_ref(tstamp.value, 1));
|
last_whole_stamp += int(fractime);
|
||||||
ts_sample = tstamp.offset;
|
fractime -= int(fractime);
|
||||||
|
|
||||||
double tstime = double(abs_sample_cnt * secs_per_sample) + last_whole_stamp + last_frac_stamp;
|
const pmt::pmt_t newval = pmt::pmt_make_tuple(
|
||||||
if(0) std::cout << "HEY WE GOT A STAMP AT " << tstime << " TICKS AT SAMPLE " << ts_sample << " ABS SAMPLE CNT IS " << abs_sample_cnt << std::endl;
|
pmt::pmt_from_uint64(last_whole_stamp),
|
||||||
return tstime;
|
pmt::pmt_from_double(fractime)
|
||||||
|
);
|
||||||
|
|
||||||
|
return newval;
|
||||||
}
|
}
|
||||||
|
|
||||||
int air_modes_preamble::general_work(int noutput_items,
|
int air_modes_preamble::general_work(int noutput_items,
|
||||||
@@ -186,16 +197,14 @@ int air_modes_preamble::general_work(int noutput_items,
|
|||||||
integrate_and_dump(out, &in[i], 240, d_samples_per_chip);
|
integrate_and_dump(out, &in[i], 240, d_samples_per_chip);
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the timestamp of the preamble
|
const pmt::pmt_t new_pmt = offset_stamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
||||||
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
|
||||||
|
|
||||||
//now tag the preamble
|
//now tag the preamble
|
||||||
add_item_tag(0, //stream ID
|
add_item_tag(0, //stream ID
|
||||||
nitems_written(0), //sample
|
nitems_written(0), //sample
|
||||||
d_key, //frame_info
|
d_key, //frame_info
|
||||||
pmt::pmt_from_double(tstamp),
|
new_pmt,
|
||||||
d_me //block src id
|
d_me //block src id
|
||||||
);
|
);
|
||||||
|
|
||||||
//std::cout << "PREAMBLE" << std::endl;
|
//std::cout << "PREAMBLE" << std::endl;
|
||||||
|
|
||||||
|
|||||||
+30
-34
@@ -112,84 +112,80 @@ int air_modes_slicer::work(int noutput_items,
|
|||||||
|
|
||||||
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||||
uint64_t i = tag_iter->offset - abs_sample_cnt;
|
uint64_t i = tag_iter->offset - abs_sample_cnt;
|
||||||
modes_packet rx_packet;
|
|
||||||
|
|
||||||
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
memset(&d_data, 0x00, 14 * sizeof(unsigned char));
|
||||||
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
memset(&d_lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||||
rx_packet.numlowconf = 0;
|
unsigned int numlowconf = 0;
|
||||||
|
|
||||||
//let's use the preamble to get a reference level for the packet
|
//let's use the preamble to get a reference level for the packet
|
||||||
//fixme: a better thing to do is create a bi-level avg 1 and avg 0
|
//fixme: a better thing to do is create a bi-level avg 1 and avg 0
|
||||||
//through simple statistics, then take the median for your slice level
|
//through simple statistics, then take the median for your slice level
|
||||||
//this won't improve decoding but will improve confidence
|
//this won't improve decoding but will improve confidence
|
||||||
rx_packet.reference_level = (in[i]
|
double reference_level = (in[i]
|
||||||
+ in[i+2]
|
+ in[i+2]
|
||||||
+ in[i+7]
|
+ in[i+7]
|
||||||
+ in[i+9]) / 4.0;
|
+ in[i+9]) / 4.0;
|
||||||
|
|
||||||
i += 16; //move on up to the first bit of the packet data
|
i += 16; //move on up to the first bit of the packet data
|
||||||
//now let's slice the header so we can determine if it's a short pkt or a long pkt
|
//now let's slice the header so we can determine if it's a short pkt or a long pkt
|
||||||
unsigned char pkt_hdr = 0;
|
unsigned char pkt_hdr = 0;
|
||||||
for(int j=0; j < 5; j++) {
|
for(int j=0; j < 5; j++) {
|
||||||
slice_result_t slice_result = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
slice_result_t slice_result = slicer(in[i+j*2], in[i+j*2+1], reference_level);
|
||||||
if(slice_result.decision) pkt_hdr += 1 << (4-j);
|
if(slice_result.decision) pkt_hdr += 1 << (4-j);
|
||||||
}
|
}
|
||||||
if(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) rx_packet.type = Long_Packet;
|
framer_packet_type type;
|
||||||
else rx_packet.type = Short_Packet;
|
if(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) type = Long_Packet;
|
||||||
int packet_length = (rx_packet.type == framer_packet_type(Short_Packet)) ? 56 : 112;
|
else type = Short_Packet;
|
||||||
|
int packet_length = (type == Short_Packet) ? 56 : 112;
|
||||||
|
|
||||||
//it's slice time!
|
//it's slice time!
|
||||||
//TODO: don't repeat your work here, you already have the first 5 bits
|
//TODO: don't repeat your work here, you already have the first 5 bits
|
||||||
|
slice_result_t slice_result;
|
||||||
for(int j = 0; j < packet_length; j++) {
|
for(int j = 0; j < packet_length; j++) {
|
||||||
slice_result_t slice_result = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
slice_result = slicer(in[i+j*2], in[i+j*2+1], reference_level);
|
||||||
|
|
||||||
//put the data into the packet
|
//put the data into the packet
|
||||||
if(slice_result.decision) {
|
if(slice_result.decision) {
|
||||||
rx_packet.data[j/8] += 1 << (7-(j%8));
|
d_data[j/8] += 1 << (7-(j%8));
|
||||||
}
|
}
|
||||||
//put the confidence decision into the packet
|
//put the confidence decision into the packet
|
||||||
if(slice_result.confidence) {
|
if(slice_result.confidence) {
|
||||||
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
//d_confidence[j/8] += 1 << (7-(j%8));
|
||||||
} else {
|
} else {
|
||||||
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
if(numlowconf < 24) d_lowconfbits[numlowconf++] = j;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************** BEGIN TIMESTAMP BS ******************/
|
uint64_t timestamp_secs = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tag_iter->value, 0));
|
||||||
rx_packet.timestamp = pmt_to_double(tag_iter->value);
|
double timestamp_frac = pmt::pmt_to_double(pmt::pmt_tuple_ref(tag_iter->value, 1));
|
||||||
/******************* END TIMESTAMP BS *********************/
|
|
||||||
|
|
||||||
//increment for the next round
|
|
||||||
|
|
||||||
//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
|
//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
|
||||||
bool zeroes = 1;
|
bool zeroes = 1;
|
||||||
for(int m = 0; m < 14; m++) {
|
for(int m = 0; m < 14; m++) {
|
||||||
if(rx_packet.data[m]) zeroes = 0;
|
if(d_data[m]) zeroes = 0;
|
||||||
}
|
}
|
||||||
if(zeroes) {continue;} //toss it
|
if(zeroes) {continue;} //toss it
|
||||||
|
|
||||||
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type to make decisions on ECC methods
|
unsigned int message_type = (d_data[0] >> 3) & 0x1F; //get the message type to make decisions on ECC methods
|
||||||
|
|
||||||
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf > 0) {continue;}
|
if(type == Short_Packet && message_type != 11 && numlowconf > 0) {continue;}
|
||||||
if(rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) {continue;}
|
if(message_type == 11 && numlowconf >= 10) {continue;}
|
||||||
|
|
||||||
rx_packet.crc = modes_check_crc(rx_packet.data, packet_length);
|
unsigned long crc = modes_check_crc(d_data, packet_length);
|
||||||
|
|
||||||
//crc for packets that aren't type 11 or type 17 is encoded with the transponder ID, which we don't know
|
//crc for packets that aren't type 11 or type 17 is encoded with the transponder ID, which we don't know
|
||||||
//therefore we toss 'em if there's syndrome
|
//therefore we toss 'em if there's syndrome
|
||||||
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
|
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
|
||||||
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
|
if(crc && (message_type == 11 || message_type == 17)) {continue;}
|
||||||
|
std::ostringstream payload;
|
||||||
d_payload.str("");
|
|
||||||
for(int m = 0; m < packet_length/8; m++) {
|
for(int m = 0; m < packet_length/8; m++) {
|
||||||
d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(d_data[m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
|
payload << " " << std::setw(6) << crc << " " << std::dec << reference_level
|
||||||
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
<< " " << timestamp_secs << " " << std::setprecision(20) << timestamp_frac;
|
||||||
gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
|
gr_message_sptr msg = gr_make_message_from_string(std::string(payload.str()));
|
||||||
d_queue->handle(msg);
|
d_queue->handle(msg);
|
||||||
}
|
}
|
||||||
if(0) std::cout << "Slicer consumed " << size << ", returned " << size << std::endl;
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ class output_flightgear(air_modes.parse):
|
|||||||
self.sock.connect((self.hostname, self.port))
|
self.sock.connect((self.hostname, self.port))
|
||||||
|
|
||||||
def output(self, message):
|
def output(self, message):
|
||||||
[data, ecc, reference, timestamp] = message.split()
|
[data, ecc, reference, timestamp_int, timestamp_frac] = message.split()
|
||||||
|
timestamp = int(timestamp_int) + float(timestamp_frac)
|
||||||
data = air_modes.modes_reply(long(data, 16))
|
data = air_modes.modes_reply(long(data, 16))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
+2
-2
@@ -30,11 +30,11 @@ class output_print(air_modes.parse):
|
|||||||
air_modes.parse.__init__(self, mypos)
|
air_modes.parse.__init__(self, mypos)
|
||||||
|
|
||||||
def parse(self, message):
|
def parse(self, message):
|
||||||
[data, ecc, reference, timestamp] = message.split()
|
[data, ecc, reference, timestamp_int, timestamp_frac] = message.split()
|
||||||
|
timestamp = int(timestamp_int) + float(timestamp_frac)
|
||||||
|
|
||||||
ecc = long(ecc, 16)
|
ecc = long(ecc, 16)
|
||||||
reference = float(reference)
|
reference = float(reference)
|
||||||
timestamp = float(timestamp)
|
|
||||||
|
|
||||||
if reference == 0.0:
|
if reference == 0.0:
|
||||||
refdb = -150.0
|
refdb = -150.0
|
||||||
|
|||||||
+2
-1
@@ -103,7 +103,8 @@ class output_sbs1(air_modes.parse):
|
|||||||
def parse(self, message):
|
def parse(self, message):
|
||||||
#assembles a SBS-1-style output string from the received message
|
#assembles a SBS-1-style output string from the received message
|
||||||
|
|
||||||
[data, ecc, reference, timestamp] = message.split()
|
[data, ecc, reference, timestamp_int, timestamp_frac] = message.split()
|
||||||
|
timestamp = int(timestamp_int) + float(timestamp_frac)
|
||||||
|
|
||||||
data = air_modes.modes_reply(long(data, 16))
|
data = air_modes.modes_reply(long(data, 16))
|
||||||
ecc = long(ecc, 16)
|
ecc = long(ecc, 16)
|
||||||
|
|||||||
+2
-1
@@ -89,7 +89,8 @@ class output_sql(air_modes.parse):
|
|||||||
def make_insert_query(self, message):
|
def make_insert_query(self, message):
|
||||||
#assembles a SQL query tailored to our database
|
#assembles a SQL query tailored to our database
|
||||||
#this version ignores anything that isn't Type 17 for now, because we just don't care
|
#this version ignores anything that isn't Type 17 for now, because we just don't care
|
||||||
[data, ecc, reference, timestamp] = message.split()
|
[data, ecc, reference, timestamp_int, timestamp_frac] = message.split()
|
||||||
|
timestamp = int(timestamp_int) + float(timestamp_frac)
|
||||||
|
|
||||||
data = air_modes.modes_reply(long(data, 16))
|
data = air_modes.modes_reply(long(data, 16))
|
||||||
ecc = long(ecc, 16)
|
ecc = long(ecc, 16)
|
||||||
|
|||||||
Reference in New Issue
Block a user