All tags, all the time. Still some weirdness with set_history() that requires using the check widths in the framer & slicer.
This commit is contained in:
parent
cd394e1863
commit
f8966f0d10
@ -40,7 +40,7 @@ air_modes_framer_sptr air_make_modes_framer(int channel_rate)
|
|||||||
air_modes_framer::air_modes_framer(int channel_rate) :
|
air_modes_framer::air_modes_framer(int channel_rate) :
|
||||||
gr_sync_block ("modes_framer",
|
gr_sync_block ("modes_framer",
|
||||||
gr_make_io_signature (1, 1, sizeof(float)), //stream 0 is received data
|
gr_make_io_signature (1, 1, sizeof(float)), //stream 0 is received data
|
||||||
gr_make_io_signature (1, 1, sizeof(unsigned char))) //output is [0, 1, 2]: [no frame, short frame, long frame]
|
gr_make_io_signature (1, 1, sizeof(float))) //raw samples passed back out
|
||||||
{
|
{
|
||||||
//initialize private data here
|
//initialize private data here
|
||||||
d_chip_rate = 2000000; //2Mchips per second
|
d_chip_rate = 2000000; //2Mchips per second
|
||||||
@ -49,6 +49,11 @@ air_modes_framer::air_modes_framer(int channel_rate) :
|
|||||||
d_check_width = 120 * d_samples_per_symbol; //gotta be able to look at two long frame lengths at a time
|
d_check_width = 120 * d_samples_per_symbol; //gotta be able to look at two long frame lengths at a time
|
||||||
//in the event that FRUIT occurs near the end of the first frame
|
//in the event that FRUIT occurs near the end of the first frame
|
||||||
//set_history(d_check_width*2);
|
//set_history(d_check_width*2);
|
||||||
|
|
||||||
|
std::stringstream str;
|
||||||
|
str << name() << unique_id();
|
||||||
|
d_me = pmt::pmt_string_to_symbol(str.str());
|
||||||
|
d_key = pmt::pmt_string_to_symbol("frame_info");
|
||||||
}
|
}
|
||||||
|
|
||||||
int air_modes_framer::work(int noutput_items,
|
int air_modes_framer::work(int noutput_items,
|
||||||
@ -57,8 +62,8 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
{
|
{
|
||||||
//do things!
|
//do things!
|
||||||
const float *inraw = (const float *) input_items[0];
|
const float *inraw = (const float *) input_items[0];
|
||||||
//float *outraw = (float *) output_items[0];
|
float *outraw = (float *) output_items[0];
|
||||||
unsigned char *outattrib = (unsigned char *) output_items[0];
|
//unsigned char *outattrib = (unsigned char *) output_items[0];
|
||||||
int size = noutput_items - d_check_width*2;
|
int size = noutput_items - d_check_width*2;
|
||||||
float reference_level;
|
float reference_level;
|
||||||
framer_packet_type packet_attrib;
|
framer_packet_type packet_attrib;
|
||||||
@ -68,7 +73,7 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::pmt_string_to_symbol("preamble_found"));
|
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::pmt_string_to_symbol("preamble_found"));
|
||||||
std::vector<pmt::pmt_t>::iterator tag_iter;
|
std::vector<pmt::pmt_t>::iterator tag_iter;
|
||||||
|
|
||||||
memset(outattrib, 0x00, size * sizeof(unsigned char));
|
memcpy(outraw, inraw, size * sizeof(float));
|
||||||
|
|
||||||
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 = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
||||||
@ -106,7 +111,13 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
get_tags_in_range(fruit_tags, 0, abs_sample_cnt+i+1, abs_sample_cnt+i+lookahead, pmt::pmt_string_to_symbol("preamble_found"));
|
get_tags_in_range(fruit_tags, 0, abs_sample_cnt+i+1, abs_sample_cnt+i+lookahead, pmt::pmt_string_to_symbol("preamble_found"));
|
||||||
if(fruit_tags.size() > 0) packet_attrib = Fruited_Packet;
|
if(fruit_tags.size() > 0) packet_attrib = Fruited_Packet;
|
||||||
|
|
||||||
outattrib[i] = packet_attrib;
|
//insert tag here
|
||||||
|
add_item_tag(0, //stream ID
|
||||||
|
nitems_written(0)+i, //sample
|
||||||
|
d_key, //preamble_found
|
||||||
|
pmt::pmt_from_long((long)packet_attrib),
|
||||||
|
d_me //block src id
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -44,6 +44,7 @@ private:
|
|||||||
int d_chip_rate;
|
int d_chip_rate;
|
||||||
int d_samples_per_chip;
|
int d_samples_per_chip;
|
||||||
int d_samples_per_symbol;
|
int d_samples_per_symbol;
|
||||||
|
pmt::pmt_t d_me, d_key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int work (int noutput_items,
|
int work (int noutput_items,
|
||||||
|
@ -51,7 +51,7 @@ air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) :
|
|||||||
str << name() << unique_id();
|
str << name() << unique_id();
|
||||||
d_me = pmt::pmt_string_to_symbol(str.str());
|
d_me = pmt::pmt_string_to_symbol(str.str());
|
||||||
d_key = pmt::pmt_string_to_symbol("preamble_found");
|
d_key = pmt::pmt_string_to_symbol("preamble_found");
|
||||||
//set_history(d_check_width);
|
set_history(d_check_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
int air_modes_preamble::work(int noutput_items,
|
int air_modes_preamble::work(int noutput_items,
|
||||||
@ -64,7 +64,7 @@ int air_modes_preamble::work(int noutput_items,
|
|||||||
|
|
||||||
float *outraw = (float *) output_items[0];
|
float *outraw = (float *) output_items[0];
|
||||||
|
|
||||||
int size = noutput_items - d_check_width;
|
int size = noutput_items;// - d_check_width;
|
||||||
int pulse_offsets[4];
|
int pulse_offsets[4];
|
||||||
float bit_energies[4];
|
float bit_energies[4];
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ air_modes_slicer_sptr air_make_modes_slicer(int channel_rate, gr_msg_queue_sptr
|
|||||||
|
|
||||||
air_modes_slicer::air_modes_slicer(int channel_rate, gr_msg_queue_sptr queue) :
|
air_modes_slicer::air_modes_slicer(int channel_rate, gr_msg_queue_sptr queue) :
|
||||||
gr_sync_block ("modes_slicer",
|
gr_sync_block ("modes_slicer",
|
||||||
gr_make_io_signature2 (2, 2, sizeof(float), sizeof(unsigned char)), //stream 0 is received data, stream 1 is binary preamble detector output
|
gr_make_io_signature (1, 1, sizeof(float)), //stream 0 is received data, stream 1 is binary preamble detector output
|
||||||
gr_make_io_signature (0, 0, 0) )
|
gr_make_io_signature (0, 0, 0) )
|
||||||
{
|
{
|
||||||
//initialize private data here
|
//initialize private data here
|
||||||
@ -74,222 +74,222 @@ int air_modes_slicer::work(int noutput_items,
|
|||||||
{
|
{
|
||||||
//do things!
|
//do things!
|
||||||
const float *inraw = (const float *) input_items[0];
|
const float *inraw = (const float *) input_items[0];
|
||||||
const unsigned char *inattrib = (const unsigned char *) input_items[1];
|
|
||||||
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < size; i++) {
|
std::vector<pmt::pmt_t> tags;
|
||||||
if(inattrib[i] == framer_packet_type(Short_Packet) || inattrib[i] == framer_packet_type(Long_Packet)) { //if there's a packet starting here....
|
uint64_t abs_sample_cnt = nitems_read(0);
|
||||||
modes_packet rx_packet;
|
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::pmt_string_to_symbol("frame_info"));
|
||||||
|
std::vector<pmt::pmt_t>::iterator tag_iter;
|
||||||
|
|
||||||
int packet_length = 112;
|
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||||
if(inattrib[i] == framer_packet_type(Short_Packet)) packet_length = 56;
|
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
||||||
|
modes_packet rx_packet;
|
||||||
|
framer_packet_type packet_type = framer_packet_type(pmt::pmt_to_long(gr_tags::get_value(*tag_iter)));
|
||||||
|
|
||||||
rx_packet.type = framer_packet_type(inattrib[i]);
|
int packet_length;
|
||||||
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
packet_length = packet_type == framer_packet_type(Short_Packet) ? 56 : 112;
|
||||||
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
|
||||||
rx_packet.numlowconf = 0;
|
rx_packet.type = packet_type;
|
||||||
|
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
||||||
|
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||||
|
rx_packet.numlowconf = 0;
|
||||||
|
|
||||||
//let's use the preamble marker to get a reference level for the packet
|
//let's use the preamble marker to get a reference level for the packet
|
||||||
rx_packet.reference_level = (bit_energy(&inraw[i], d_samples_per_chip)
|
rx_packet.reference_level = (bit_energy(&inraw[i], d_samples_per_chip)
|
||||||
+ bit_energy(&inraw[i+int(1.0*d_samples_per_symbol)], d_samples_per_chip)
|
+ bit_energy(&inraw[i+int(1.0*d_samples_per_symbol)], d_samples_per_chip)
|
||||||
+ bit_energy(&inraw[i+int(3.5*d_samples_per_symbol)], d_samples_per_chip)
|
+ bit_energy(&inraw[i+int(3.5*d_samples_per_symbol)], d_samples_per_chip)
|
||||||
+ bit_energy(&inraw[i+int(4.5*d_samples_per_symbol)], d_samples_per_chip)) / 4;
|
+ bit_energy(&inraw[i+int(4.5*d_samples_per_symbol)], d_samples_per_chip)) / 4;
|
||||||
|
|
||||||
i += 8 * d_samples_per_symbol; //move to the center of the first bit of the data
|
i += 8 * d_samples_per_symbol; //move to the center of the first bit of the data
|
||||||
|
|
||||||
//here we calculate the total energy contained in each chip of the symbol
|
//here we calculate the total energy contained in each chip of the symbol
|
||||||
for(int j = 0; j < packet_length; j++) {
|
for(int j = 0; j < packet_length; j++) {
|
||||||
int firstchip = i+j*d_samples_per_symbol;
|
int firstchip = i+j*d_samples_per_symbol;
|
||||||
int secondchip = firstchip + d_samples_per_chip;
|
int secondchip = firstchip + d_samples_per_chip;
|
||||||
bool slice, confidence;
|
bool slice, confidence;
|
||||||
float firstchip_energy=0, secondchip_energy=0;
|
float firstchip_energy=0, secondchip_energy=0;
|
||||||
|
|
||||||
firstchip_energy = bit_energy(&inraw[firstchip], d_samples_per_chip);
|
firstchip_energy = bit_energy(&inraw[firstchip], d_samples_per_chip);
|
||||||
secondchip_energy = bit_energy(&inraw[secondchip], d_samples_per_chip);
|
secondchip_energy = bit_energy(&inraw[secondchip], d_samples_per_chip);
|
||||||
|
|
||||||
//3dB limits for bit slicing and confidence measurement
|
//3dB limits for bit slicing and confidence measurement
|
||||||
float highlimit=rx_packet.reference_level*2;
|
float highlimit=rx_packet.reference_level*2;
|
||||||
float lowlimit=rx_packet.reference_level*0.5;
|
float lowlimit=rx_packet.reference_level*0.5;
|
||||||
bool firstchip_inref = ((firstchip_energy > lowlimit) && (firstchip_energy < highlimit));
|
bool firstchip_inref = ((firstchip_energy > lowlimit) && (firstchip_energy < highlimit));
|
||||||
bool secondchip_inref = ((secondchip_energy > lowlimit) && (secondchip_energy < highlimit));
|
bool secondchip_inref = ((secondchip_energy > lowlimit) && (secondchip_energy < highlimit));
|
||||||
|
|
||||||
//these two lines for a super simple naive slicer.
|
//these two lines for a super simple naive slicer.
|
||||||
// slice = firstchip_energy > secondchip_energy;
|
// slice = firstchip_energy > secondchip_energy;
|
||||||
// confidence = bool(int(firstchip_inref) + int(secondchip_inref)); //one and only one chip in the reference zone
|
// confidence = bool(int(firstchip_inref) + int(secondchip_inref)); //one and only one chip in the reference zone
|
||||||
|
|
||||||
//below is the Lincoln Labs slicer. it may produce greater bit errors. supposedly it is more resistant to mode A/C FRUIT.
|
//below is the Lincoln Labs slicer. it may produce greater bit errors. supposedly it is more resistant to mode A/C FRUIT.
|
||||||
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
||||||
if(firstchip_inref && !secondchip_inref) {
|
if(firstchip_inref && !secondchip_inref) {
|
||||||
slice = 1;
|
slice = 1;
|
||||||
confidence = 1;
|
confidence = 1;
|
||||||
}
|
}
|
||||||
else if(secondchip_inref && !firstchip_inref) {
|
else if(secondchip_inref && !firstchip_inref) {
|
||||||
slice = 0;
|
slice = 0;
|
||||||
confidence = 1;
|
confidence = 1;
|
||||||
}
|
}
|
||||||
else if(firstchip_inref && secondchip_inref) {
|
else if(firstchip_inref && secondchip_inref) {
|
||||||
slice = firstchip_energy > secondchip_energy;
|
slice = firstchip_energy > secondchip_energy;
|
||||||
confidence = 0;
|
confidence = 0;
|
||||||
}
|
}
|
||||||
else if(!firstchip_inref && !secondchip_inref) { //in this case, we determine the bit by whichever is larger, and we determine high confidence if the low chip is 6dB below reference.
|
else if(!firstchip_inref && !secondchip_inref) { //in this case, we determine the bit by whichever is larger, and we determine high confidence if the low chip is 6dB below reference.
|
||||||
slice = firstchip_energy > secondchip_energy;
|
slice = firstchip_energy > secondchip_energy;
|
||||||
if(slice) {
|
|
||||||
if(secondchip_energy < lowlimit * 0.5) confidence = 1;
|
|
||||||
else confidence = 0;
|
|
||||||
} else {
|
|
||||||
if(firstchip_energy < lowlimit * 0.5) confidence = 1;
|
|
||||||
else confidence = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//put the data into the packet
|
|
||||||
if(slice) {
|
if(slice) {
|
||||||
rx_packet.data[j/8] += 1 << (7-(j%8));
|
if(secondchip_energy < lowlimit * 0.5) confidence = 1;
|
||||||
}
|
else confidence = 0;
|
||||||
//put the confidence decision into the packet
|
|
||||||
if(confidence) {
|
|
||||||
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
|
||||||
} else {
|
} else {
|
||||||
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
if(firstchip_energy < lowlimit * 0.5) confidence = 1;
|
||||||
|
else confidence = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//put the data into the packet
|
||||||
|
if(slice) {
|
||||||
|
rx_packet.data[j/8] += 1 << (7-(j%8));
|
||||||
|
}
|
||||||
|
//put the confidence decision into the packet
|
||||||
|
if(confidence) {
|
||||||
|
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
||||||
|
} else {
|
||||||
|
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************** BEGIN TIMESTAMP BS ******************/
|
/******************** BEGIN TIMESTAMP BS ******************/
|
||||||
rx_packet.timestamp_secs = 0;
|
rx_packet.timestamp_secs = 0;
|
||||||
rx_packet.timestamp_frac = 0;
|
rx_packet.timestamp_frac = 0;
|
||||||
|
|
||||||
uint64_t abs_sample_cnt = nitems_read(0);
|
uint64_t abs_sample_cnt = nitems_read(0);
|
||||||
std::vector<pmt::pmt_t> tags;
|
std::vector<pmt::pmt_t> tags;
|
||||||
uint64_t timestamp_secs, timestamp_sample, timestamp_delta;
|
uint64_t timestamp_secs, timestamp_sample, timestamp_delta;
|
||||||
double timestamp_frac;
|
double timestamp_frac;
|
||||||
|
|
||||||
pmt::pmt_t timestamp;
|
pmt::pmt_t timestamp;
|
||||||
|
|
||||||
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + i, pmt::pmt_string_to_symbol("packet_time_stamp"));
|
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + i, pmt::pmt_string_to_symbol("packet_time_stamp"));
|
||||||
//tags.back() is the most recent timestamp, then.
|
//tags.back() is the most recent timestamp, then.
|
||||||
if(tags.size() > 0) {
|
if(tags.size() > 0) {
|
||||||
//if nobody but the USRP is producing timestamps this isn't necessary
|
//if nobody but the USRP is producing timestamps this isn't necessary
|
||||||
//std::sort(tags.begin(), tags.end(), pmtcompare);
|
//std::sort(tags.begin(), tags.end(), pmtcompare);
|
||||||
timestamp = tags.back();
|
timestamp = tags.back();
|
||||||
|
|
||||||
timestamp_secs = pmt_to_uint64(pmt_tuple_ref(gr_tags::get_value(timestamp), 0));
|
timestamp_secs = pmt_to_uint64(pmt_tuple_ref(gr_tags::get_value(timestamp), 0));
|
||||||
timestamp_frac = pmt_to_double(pmt_tuple_ref(gr_tags::get_value(timestamp), 1));
|
timestamp_frac = pmt_to_double(pmt_tuple_ref(gr_tags::get_value(timestamp), 1));
|
||||||
timestamp_sample = gr_tags::get_nitems(timestamp);
|
timestamp_sample = gr_tags::get_nitems(timestamp);
|
||||||
//now we have to offset the timestamp based on the current sample number
|
//now we have to offset the timestamp based on the current sample number
|
||||||
timestamp_delta = (abs_sample_cnt + i) - timestamp_sample;
|
timestamp_delta = (abs_sample_cnt + i) - timestamp_sample;
|
||||||
|
|
||||||
timestamp_frac += timestamp_delta * d_secs_per_sample;
|
timestamp_frac += timestamp_delta * d_secs_per_sample;
|
||||||
if(timestamp_frac > 1.0) {
|
if(timestamp_frac > 1.0) {
|
||||||
timestamp_frac -= 1.0;
|
timestamp_frac -= 1.0;
|
||||||
timestamp_secs++;
|
timestamp_secs++;
|
||||||
}
|
|
||||||
|
|
||||||
rx_packet.timestamp_secs = timestamp_secs;
|
|
||||||
rx_packet.timestamp_frac = timestamp_frac;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************* END TIMESTAMP BS *********************/
|
rx_packet.timestamp_secs = timestamp_secs;
|
||||||
|
rx_packet.timestamp_frac = timestamp_frac;
|
||||||
|
}
|
||||||
|
|
||||||
//increment for the next round
|
/******************* END TIMESTAMP BS *********************/
|
||||||
i += packet_length * d_samples_per_symbol;
|
|
||||||
|
|
||||||
//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.
|
//increment for the next round
|
||||||
bool zeroes = 1;
|
|
||||||
for(int m = 0; m < 14; m++) {
|
//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.
|
||||||
if(rx_packet.data[m]) zeroes = 0;
|
bool zeroes = 1;
|
||||||
|
for(int m = 0; m < 14; m++) {
|
||||||
|
if(rx_packet.data[m]) zeroes = 0;
|
||||||
|
}
|
||||||
|
if(zeroes) continue; //toss it
|
||||||
|
|
||||||
|
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type for the parser to conveniently use, and to make decisions on ECC methods
|
||||||
|
|
||||||
|
//we note that short packets other than type 11 CANNOT be reliably decoded, since the a/c address is encoded with the parity bits.
|
||||||
|
//mode S in production ATC use relies on the fact that these short packets are reply squitters to transponder requests,
|
||||||
|
//and so the radar should already know the expected a/c reply address. so, error-correction makes no sense on short packets (other than type 11)
|
||||||
|
//this means two things: first, we will DROP short packets (other than type 11) with ANY low-confidence bits, since we can't be confident that we're seeing real data
|
||||||
|
//second, we will only perform error correction on LONG type S packets.
|
||||||
|
|
||||||
|
//the limitation on short packets means in practice a short packet has to be at least 6dB above the noise floor in order to be output. long packets can theoretically
|
||||||
|
//be decoded at the 3dB SNR point. below that and the preamble detector won't fire.
|
||||||
|
|
||||||
|
//in practice, this limitation causes you to see a HUGE number of type 11 packets which pass CRC through random luck.
|
||||||
|
//these packets necessarily have large numbers of low-confidence bits, so we toss them with an arbitrary limit of 10.
|
||||||
|
//that's a pretty dang low threshold so i don't think we'll drop many legit packets
|
||||||
|
|
||||||
|
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf != 0) continue;
|
||||||
|
if(rx_packet.type == Short_Packet && rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) continue;
|
||||||
|
|
||||||
|
|
||||||
|
//if(rx_packet.numlowconf >= 24) continue; //don't even try, this is the maximum number of errors ECC could possibly correct
|
||||||
|
//the above line should be part of ECC, and only checked if the message has parity errors
|
||||||
|
|
||||||
|
rx_packet.parity = modes_check_parity(rx_packet.data, packet_length);
|
||||||
|
|
||||||
|
if(rx_packet.parity && rx_packet.type == Long_Packet) {
|
||||||
|
// long before = rx_packet.parity;
|
||||||
|
bruteResultTypeDef bruteResult = modes_ec_brute(rx_packet);
|
||||||
|
|
||||||
|
if(bruteResult == No_Solution) {
|
||||||
|
//printf("No solution!\n");
|
||||||
|
continue;
|
||||||
|
} else if(bruteResult == Multiple_Solutions) {
|
||||||
|
// printf("Multiple solutions!\n");
|
||||||
|
continue;
|
||||||
|
} else if(bruteResult == Too_Many_LCBs) {
|
||||||
|
//printf("Too many LCBs (%i)!\n", rx_packet.numlowconf);
|
||||||
|
continue;
|
||||||
|
} else if(bruteResult == No_Error) {
|
||||||
|
// printf("No error!\n");
|
||||||
|
} else if(bruteResult == Solution_Found) {
|
||||||
|
// printf("Solution found for %i LCBs!\n", rx_packet.numlowconf);
|
||||||
}
|
}
|
||||||
if(zeroes) continue; //toss it
|
// rx_packet.parity = modes_check_parity(rx_packet.data, packet_length);
|
||||||
|
// if(rx_packet.parity) printf("Error: packet fails parity check after correction, was %x, now %x\n", before, rx_packet.parity);
|
||||||
|
}
|
||||||
|
|
||||||
rx_packet.message_type = (rx_packet.data[0] >> 3) & 0x1F; //get the message type for the parser to conveniently use, and to make decisions on ECC methods
|
// if(rx_packet.parity && rx_packet.type == Long_Packet) printf("Error! Bad packet forwarded to the queue.\n");
|
||||||
|
//now we have a complete packet with confidence data, let's print it to the message queue
|
||||||
|
//here, rather than send the entire packet, since we've already done parity checking and ECC in C++, we'll
|
||||||
|
//send just the data (no confidence bits), separated into fields for easier parsing.
|
||||||
|
//we'll replicate some data by sending the message type as the first field, followed by the first 8+24=32 bits of the packet, followed by
|
||||||
|
//56 long packet data bits if applicable (zero-padded if not), followed by parity
|
||||||
|
|
||||||
//we note that short packets other than type 11 CANNOT be reliably decoded, since the a/c address is encoded with the parity bits.
|
d_payload.str("");
|
||||||
//mode S in production ATC use relies on the fact that these short packets are reply squitters to transponder requests,
|
|
||||||
//and so the radar should already know the expected a/c reply address. so, error-correction makes no sense on short packets (other than type 11)
|
|
||||||
//this means two things: first, we will DROP short packets (other than type 11) with ANY low-confidence bits, since we can't be confident that we're seeing real data
|
|
||||||
//second, we will only perform error correction on LONG type S packets.
|
|
||||||
|
|
||||||
//the limitation on short packets means in practice a short packet has to be at least 6dB above the noise floor in order to be output. long packets can theoretically
|
d_payload << std::dec << std::setw(2) << std::setfill('0') << rx_packet.message_type << std::hex << " ";
|
||||||
//be decoded at the 3dB SNR point. below that and the preamble detector won't fire.
|
|
||||||
|
|
||||||
//in practice, this limitation causes you to see a HUGE number of type 11 packets which pass CRC through random luck.
|
for(int m = 0; m < 4; m++) {
|
||||||
//these packets necessarily have large numbers of low-confidence bits, so we toss them with an arbitrary limit of 10.
|
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||||
//that's a pretty dang low threshold so i don't think we'll drop many legit packets
|
}
|
||||||
|
d_payload << " ";
|
||||||
if(rx_packet.type == Short_Packet && rx_packet.message_type != 11 && rx_packet.numlowconf != 0) continue;
|
if(packet_length == 112) {
|
||||||
if(rx_packet.type == Short_Packet && rx_packet.message_type == 11 && rx_packet.numlowconf >= 10) continue;
|
for(int m = 4; m < 11; m++) {
|
||||||
|
|
||||||
|
|
||||||
//if(rx_packet.numlowconf >= 24) continue; //don't even try, this is the maximum number of errors ECC could possibly correct
|
|
||||||
//the above line should be part of ECC, and only checked if the message has parity errors
|
|
||||||
|
|
||||||
rx_packet.parity = modes_check_parity(rx_packet.data, packet_length);
|
|
||||||
|
|
||||||
if(rx_packet.parity && rx_packet.type == Long_Packet) {
|
|
||||||
// long before = rx_packet.parity;
|
|
||||||
bruteResultTypeDef bruteResult = modes_ec_brute(rx_packet);
|
|
||||||
|
|
||||||
if(bruteResult == No_Solution) {
|
|
||||||
//printf("No solution!\n");
|
|
||||||
continue;
|
|
||||||
} else if(bruteResult == Multiple_Solutions) {
|
|
||||||
// printf("Multiple solutions!\n");
|
|
||||||
continue;
|
|
||||||
} else if(bruteResult == Too_Many_LCBs) {
|
|
||||||
//printf("Too many LCBs (%i)!\n", rx_packet.numlowconf);
|
|
||||||
continue;
|
|
||||||
} else if(bruteResult == No_Error) {
|
|
||||||
// printf("No error!\n");
|
|
||||||
} else if(bruteResult == Solution_Found) {
|
|
||||||
// printf("Solution found for %i LCBs!\n", rx_packet.numlowconf);
|
|
||||||
}
|
|
||||||
// rx_packet.parity = modes_check_parity(rx_packet.data, packet_length);
|
|
||||||
// if(rx_packet.parity) printf("Error: packet fails parity check after correction, was %x, now %x\n", before, rx_packet.parity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if(rx_packet.parity && rx_packet.type == Long_Packet) printf("Error! Bad packet forwarded to the queue.\n");
|
|
||||||
//now we have a complete packet with confidence data, let's print it to the message queue
|
|
||||||
//here, rather than send the entire packet, since we've already done parity checking and ECC in C++, we'll
|
|
||||||
//send just the data (no confidence bits), separated into fields for easier parsing.
|
|
||||||
|
|
||||||
//we'll replicate some data by sending the message type as the first field, followed by the first 8+24=32 bits of the packet, followed by
|
|
||||||
//56 long packet data bits if applicable (zero-padded if not), followed by parity
|
|
||||||
|
|
||||||
d_payload.str("");
|
|
||||||
|
|
||||||
d_payload << std::dec << std::setw(2) << std::setfill('0') << rx_packet.message_type << std::hex << " ";
|
|
||||||
|
|
||||||
for(int m = 0; m < 4; m++) {
|
|
||||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||||
}
|
}
|
||||||
d_payload << " ";
|
d_payload << " ";
|
||||||
if(packet_length == 112) {
|
for(int m = 11; m < 14; m++) {
|
||||||
for(int m = 4; m < 11; m++) {
|
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
}
|
||||||
}
|
} else {
|
||||||
d_payload << " ";
|
for(int m = 4; m < 11; m++) {
|
||||||
for(int m = 11; m < 14; m++) {
|
d_payload << std::setw(2) << std::setfill('0') << unsigned(0);
|
||||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
}
|
||||||
}
|
d_payload << " ";
|
||||||
} else {
|
for(int m = 4; m < 7; m++) {
|
||||||
for(int m = 4; m < 11; m++) {
|
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
||||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(0);
|
|
||||||
}
|
|
||||||
d_payload << " ";
|
|
||||||
for(int m = 4; m < 7; m++) {
|
|
||||||
d_payload << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d_payload << " " << std::setw(6) << rx_packet.parity << " " << std::dec << rx_packet.reference_level
|
|
||||||
<< " " << rx_packet.timestamp_secs
|
|
||||||
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp_frac;
|
|
||||||
|
|
||||||
gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
|
|
||||||
d_queue->handle(msg);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d_payload << " " << std::setw(6) << rx_packet.parity << " " << std::dec << rx_packet.reference_level
|
||||||
|
<< " " << rx_packet.timestamp_secs
|
||||||
|
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp_frac;
|
||||||
|
gr_message_sptr msg = gr_make_message_from_string(std::string(d_payload.str()));
|
||||||
|
d_queue->handle(msg);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
|
@ -97,27 +97,12 @@ class adsb_rx_block (gr.top_block):
|
|||||||
self.framer = air.modes_framer(rate)
|
self.framer = air.modes_framer(rate)
|
||||||
self.slicer = air.modes_slicer(rate, queue)
|
self.slicer = air.modes_slicer(rate, queue)
|
||||||
|
|
||||||
#self.nullsink = gr.file_sink(gr.sizeof_gr_complex, "/dev/null")
|
|
||||||
|
|
||||||
#self.connect(self.u, self.nullsink)
|
|
||||||
|
|
||||||
# self.connect(self.u, self.demod, self.filter)
|
|
||||||
# self.connect(self.filter, self.avg)
|
|
||||||
# self.connect(self.filter, (self.preamble, 0))
|
|
||||||
# self.connect(self.avg, (self.preamble, 1))
|
|
||||||
# self.connect(self.filter, (self.framer, 0))
|
|
||||||
# self.connect(self.preamble, (self.framer, 1))
|
|
||||||
# self.connect(self.filter, (self.slicer, 0))
|
|
||||||
# self.connect(self.framer, (self.slicer, 1))
|
|
||||||
|
|
||||||
#use this flowgraph instead to omit the filter
|
|
||||||
self.connect(self.u, self.demod)
|
self.connect(self.u, self.demod)
|
||||||
self.connect(self.demod, self.avg)
|
self.connect(self.demod, self.avg)
|
||||||
self.connect(self.demod, (self.preamble, 0))
|
self.connect(self.demod, (self.preamble, 0))
|
||||||
self.connect(self.avg, (self.preamble, 1))
|
self.connect(self.avg, (self.preamble, 1))
|
||||||
self.connect((self.preamble, 0), (self.framer, 0))
|
self.connect((self.preamble, 0), (self.framer, 0))
|
||||||
self.connect(self.demod, (self.slicer, 0))
|
self.connect(self.framer, self.slicer)
|
||||||
self.connect(self.framer, (self.slicer, 1))
|
|
||||||
|
|
||||||
def tune(self, freq):
|
def tune(self, freq):
|
||||||
result = self.u.set_center_freq(freq, 0)
|
result = self.u.set_center_freq(freq, 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user