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_symbol;
|
||||
gr_msg_queue_sptr d_queue;
|
||||
std::ostringstream d_payload;
|
||||
unsigned char d_lowconfbits[24];
|
||||
unsigned char d_data[14];
|
||||
|
||||
public:
|
||||
int work (int noutput_items,
|
||||
|
||||
@@ -24,20 +24,6 @@
|
||||
#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_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 {
|
||||
bool decision;
|
||||
|
||||
@@ -24,7 +24,4 @@
|
||||
#define INCLUDED_MODES_CRC_H
|
||||
extern const unsigned int modes_crc_table[112];
|
||||
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
|
||||
|
||||
@@ -78,20 +78,31 @@ static double correlate_preamble(const float *in, int samples_per_chip) {
|
||||
return corr;
|
||||
}
|
||||
|
||||
//todo: make it return a pair of some kind, otherwise you can lose precision
|
||||
static double tag_to_timestamp(gr_tag_t tstamp, uint64_t abs_sample_cnt, double secs_per_sample) {
|
||||
//takes an rx tag and issues a tag offset appropriately for the preamble
|
||||
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;
|
||||
double last_frac_stamp;
|
||||
|
||||
if(tstamp.key == NULL || pmt::pmt_symbol_to_string(tstamp.key) != "rx_time") return 0;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
double tstime = double(abs_sample_cnt * secs_per_sample) + last_whole_stamp + last_frac_stamp;
|
||||
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;
|
||||
return tstime;
|
||||
double fractime = double(abs_sample_cnt * secs_per_sample) + last_frac_stamp;
|
||||
last_whole_stamp += int(fractime);
|
||||
fractime -= int(fractime);
|
||||
|
||||
const pmt::pmt_t newval = pmt::pmt_make_tuple(
|
||||
pmt::pmt_from_uint64(last_whole_stamp),
|
||||
pmt::pmt_from_double(fractime)
|
||||
);
|
||||
|
||||
return newval;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
//get the timestamp of the preamble
|
||||
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
||||
|
||||
const pmt::pmt_t new_pmt = offset_stamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
|
||||
//now tag the preamble
|
||||
add_item_tag(0, //stream ID
|
||||
nitems_written(0), //sample
|
||||
d_key, //frame_info
|
||||
pmt::pmt_from_double(tstamp),
|
||||
d_me //block src id
|
||||
);
|
||||
nitems_written(0), //sample
|
||||
d_key, //frame_info
|
||||
new_pmt,
|
||||
d_me //block src id
|
||||
);
|
||||
|
||||
//std::cout << "PREAMBLE" << std::endl;
|
||||
|
||||
|
||||
@@ -112,84 +112,80 @@ int air_modes_slicer::work(int noutput_items,
|
||||
|
||||
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||
uint64_t i = tag_iter->offset - abs_sample_cnt;
|
||||
modes_packet rx_packet;
|
||||
|
||||
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
||||
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||
rx_packet.numlowconf = 0;
|
||||
memset(&d_data, 0x00, 14 * sizeof(unsigned char));
|
||||
memset(&d_lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||
unsigned int numlowconf = 0;
|
||||
|
||||
//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
|
||||
//through simple statistics, then take the median for your slice level
|
||||
//this won't improve decoding but will improve confidence
|
||||
rx_packet.reference_level = (in[i]
|
||||
+ in[i+2]
|
||||
+ in[i+7]
|
||||
+ in[i+9]) / 4.0;
|
||||
double reference_level = (in[i]
|
||||
+ in[i+2]
|
||||
+ in[i+7]
|
||||
+ in[i+9]) / 4.0;
|
||||
|
||||
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
|
||||
unsigned char pkt_hdr = 0;
|
||||
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(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) rx_packet.type = Long_Packet;
|
||||
else rx_packet.type = Short_Packet;
|
||||
int packet_length = (rx_packet.type == framer_packet_type(Short_Packet)) ? 56 : 112;
|
||||
framer_packet_type type;
|
||||
if(pkt_hdr == 16 or pkt_hdr == 17 or pkt_hdr == 20 or pkt_hdr == 21) type = Long_Packet;
|
||||
else type = Short_Packet;
|
||||
int packet_length = (type == Short_Packet) ? 56 : 112;
|
||||
|
||||
//it's slice time!
|
||||
//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++) {
|
||||
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
|
||||
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
|
||||
if(slice_result.confidence) {
|
||||
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
||||
//d_confidence[j/8] += 1 << (7-(j%8));
|
||||
} else {
|
||||
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
||||
if(numlowconf < 24) d_lowconfbits[numlowconf++] = j;
|
||||
}
|
||||
}
|
||||
|
||||
/******************** BEGIN TIMESTAMP BS ******************/
|
||||
rx_packet.timestamp = pmt_to_double(tag_iter->value);
|
||||
/******************* END TIMESTAMP BS *********************/
|
||||
|
||||
//increment for the next round
|
||||
|
||||
uint64_t timestamp_secs = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(tag_iter->value, 0));
|
||||
double timestamp_frac = pmt::pmt_to_double(pmt::pmt_tuple_ref(tag_iter->value, 1));
|
||||
|
||||
//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;
|
||||
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
|
||||
|
||||
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(rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) {continue;}
|
||||
if(type == Short_Packet && message_type != 11 && numlowconf > 0) {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
|
||||
//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
|
||||
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}
|
||||
|
||||
d_payload.str("");
|
||||
if(crc && (message_type == 11 || message_type == 17)) {continue;}
|
||||
std::ostringstream payload;
|
||||
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
|
||||
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
|
||||
gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
|
||||
payload << " " << std::setw(6) << crc << " " << std::dec << reference_level
|
||||
<< " " << timestamp_secs << " " << std::setprecision(20) << timestamp_frac;
|
||||
gr_message_sptr msg = gr_make_message_from_string(std::string(payload.str()));
|
||||
d_queue->handle(msg);
|
||||
}
|
||||
if(0) std::cout << "Slicer consumed " << size << ", returned " << size << std::endl;
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ class output_flightgear(air_modes.parse):
|
||||
self.sock.connect((self.hostname, self.port))
|
||||
|
||||
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))
|
||||
|
||||
try:
|
||||
|
||||
@@ -30,11 +30,11 @@ class output_print(air_modes.parse):
|
||||
air_modes.parse.__init__(self, mypos)
|
||||
|
||||
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)
|
||||
reference = float(reference)
|
||||
timestamp = float(timestamp)
|
||||
|
||||
if reference == 0.0:
|
||||
refdb = -150.0
|
||||
|
||||
@@ -103,7 +103,8 @@ class output_sbs1(air_modes.parse):
|
||||
def parse(self, 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))
|
||||
ecc = long(ecc, 16)
|
||||
|
||||
@@ -89,7 +89,8 @@ class output_sql(air_modes.parse):
|
||||
def make_insert_query(self, message):
|
||||
#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
|
||||
[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))
|
||||
ecc = long(ecc, 16)
|
||||
|
||||
Reference in New Issue
Block a user