dump1090 bug fixes, working

bug_fixes_integration_tx
David Michaeli 2022-04-20 22:39:36 +03:00
rodzic adca66f611
commit 6a60ecbc31
6 zmienionych plików z 250 dodań i 196 usunięć

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -33,7 +33,7 @@ static void printBanner(void)
/***********************************************************************
* Find devices and print args
**********************************************************************/
static int findDevices(const std::string &argStr, const bool sparse)
static int findDevices(const std::string &argStr)
{
const auto results = SoapySDR::Device::enumerate(argStr);
std::cout << "Found " << results.size() << " devices" << std::endl;
@ -64,7 +64,41 @@ static void sigIntHandler(const int)
void onModeSMessage(mode_s_t *self, struct mode_s_msg *mm)
{
printf("Got message from flight %s at altitude %d\n", mm->flight, mm->altitude);
printf("Got message from flight %s\n", mm->flight);
printf(" HEADER: #Bits: %d, Type: %d, CRCOK: %d, ECC: %d, ICAO_ADDR:%02X%02X%02X, PHC: %d, CAP: %08X\n",
mm->msgbits, // Number of bits in message
mm->msgtype, // Downlink format #
mm->crcok, // True if CRC was valid
mm->errorbit, // Bit corrected. -1 if no bit corrected.
mm->aa1, mm->aa2, mm->aa3, // ICAO Address bytes 1 2 and 3
mm->phase_corrected, // True if phase correction was applied.
mm->ca); // Responder capabilities.
printf(" DATA1: MsgTp: %d, MsgSTp: %d, HdVld: %d, Hd: %d, AirCftTp:%d, FFlg: %d, UtcSync: %d, Lat: %d, Lon: %d, Dir W/S: %d/%d\n"
" DATA2: Vel (W/S): %d/%d, Vel: %d, VertRt (Src/Sgn/Rt): %d/%d/%d, Alt: %d, Stat: %d, Id: %08X, Unt: %d\n\n",
mm->metype, // Extended squitter message type.
mm->mesub, // Extended squitter message subtype.
mm->heading_is_valid, // heading_is_valid
mm->heading, // heading
mm->aircraft_type, // aircraft_type
mm->fflag, // 1 = Odd, 0 = Even CPR message.
mm->tflag, // UTC synchronized?
mm->raw_latitude, // Non decoded latitude
mm->raw_longitude, // Non decoded raw_longitude
mm->ew_dir, // 0 = East, 1 = West.
mm->ns_dir, // 0 = North, 1 = South.
mm->ew_velocity, // E/W velocity.
mm->ns_velocity, // N/S velocity.
mm->velocity,
mm->vert_rate_source, // Vertical rate source.
mm->vert_rate_sign, // Vertical rate sign.
mm->vert_rate, // // Vertical rate.
mm->altitude,
mm->fs, // Flight status for DF4,5,20,21
mm->identity, // 13 bits identity (Squawk).
mm->unit);
}
#define FILT_ORDER 6
@ -77,20 +111,18 @@ void makeFilter(double fs, double cutoff)
}
// Turn I/Q samples pointed by `data` into the magnitude vector pointed by `mag`
void MagnitudeVector(short *data, uint16_t *mag, uint32_t size)
void MagnitudeVectorDownSample(short *data, uint16_t *mag, uint32_t size)
{
uint32_t k;
float ii, qq, i, q;
float i, q;
int t = 0;
for (k=0; k<size; k+=2, t++)
{
float i = data[k];
float q = data[k+1];
float i = (float)data[k];
float q = (float)data[k+1];
//ii = filt.filter(i);
//qq = filt.filter(q);
mag[t]=(uint16_t)sqrt(ii*ii + qq*qq);
if (t & 0x1)
mag[t >> 1]=(uint16_t)sqrt(i*i + q*q);
}
}
@ -139,15 +171,10 @@ void runSoapyProcess(
}
// compute the magnitude of the signal
MagnitudeVector(buff, mag, ret);
for (int jjj = 0; jjj < numElems; jjj++)
{
printf("%d, ", buff[jjj*2]);
}
MagnitudeVectorDownSample(buff, mag, ret);
// detect Mode S messages in the signal and call on_msg with each message
mode_s_detect(&state, mag, ret, onModeSMessage);
mode_s_detect(&state, mag, ret/2, onModeSMessage);
}
device->deactivateStream(stream);
@ -159,29 +186,27 @@ void runSoapyProcess(
**********************************************************************/
int main(int argc, char *argv[])
{
SoapySDR::ModuleManager mm(false);
SoapySDR::ModuleManager mm(false);
SoapySDR::Device *device(nullptr);
std::vector<size_t> channels;
std::string argStr;
std::string argStr = "driver=Cariboulite,channel=HiF";
double fullScale = 0.0;
double freq = 1090.0e6;
//double freq = 1090e6;
printBanner();
//findDevices(argStr, false);
try
{
device = SoapySDR::Device::make(argStr);
// push the 6GHZ channel into the channel list
channels.push_back(1);
channels.push_back(0);
// set the sample rate
device->setSampleRate(SOAPY_SDR_RX, channels[0], 4e6);
device->setBandwidth(SOAPY_SDR_RX, channels[0], 2.5e6);
device->setBandwidth(SOAPY_SDR_RX, channels[0], 2500e5);
device->setGainMode(SOAPY_SDR_RX, channels[0], false);
device->setGain(SOAPY_SDR_RX, channels[0], 60);
device->setGain(SOAPY_SDR_RX, channels[0], 50);
device->setFrequency(SOAPY_SDR_RX, channels[0], freq);
//create the stream, use the native format

Wyświetl plik

@ -101,13 +101,16 @@ uint32_t mode_s_checksum(unsigned char *msg, int bits) {
// Given the Downlink Format (DF) of the message, return the message length in
// bits.
int mode_s_msg_len_by_type(int type) {
if (type == 16 || type == 17 ||
type == 19 || type == 20 ||
type == 21)
return MODE_S_LONG_MSG_BITS;
else
return MODE_S_SHORT_MSG_BITS;
int mode_s_msg_len_by_type(int type)
{
if (type == 16 || type == 17 ||
type == 19 || type == 20 ||
type == 21)
{
return MODE_S_LONG_MSG_BITS;
}
return MODE_S_SHORT_MSG_BITS;
}
// Try to fix single bit errors using the checksum. On success modifies the
@ -550,36 +553,39 @@ void apply_phase_correction(uint16_t *mag) {
// Detect a Mode S messages inside the magnitude buffer pointed by 'mag' and of
// size 'maglen' bytes. Every detected Mode S message is convert it into a
// stream of bits and passed to the function to display it.
void mode_s_detect(mode_s_t *self, uint16_t *mag, uint32_t maglen, mode_s_callback_t cb) {
unsigned char bits[MODE_S_LONG_MSG_BITS];
unsigned char msg[MODE_S_LONG_MSG_BITS/2];
uint16_t aux[MODE_S_LONG_MSG_BITS*2];
uint32_t j;
int use_correction = 0;
void mode_s_detect(mode_s_t *self, uint16_t *mag, uint32_t maglen, mode_s_callback_t cb)
{
unsigned char bits[MODE_S_LONG_MSG_BITS];
unsigned char msg[MODE_S_LONG_MSG_BITS/2];
uint16_t aux[MODE_S_LONG_MSG_BITS*2];
uint32_t j;
int use_correction = 0;
// The Mode S preamble is made of impulses of 0.5 microseconds at the
// following time offsets:
//
// 0 - 0.5 usec: first impulse.
// 1.0 - 1.5 usec: second impulse.
// 3.5 - 4 usec: third impulse.
// 4.5 - 5 usec: last impulse.
//
// Since we are sampling at 2 Mhz every sample in our magnitude vector is
// 0.5 usec, so the preamble will look like this, assuming there is an
// impulse at offset 0 in the array:
//
// 0 -----------------
// 1 -
// 2 ------------------
// 3 --
// 4 -
// 5 --
// 6 -
// 7 ------------------
// 8 --
// 9 -------------------
for (j = 0; j < maglen - MODE_S_FULL_LEN*2; j++) {
// The Mode S preamble is made of impulses of 0.5 microseconds at the
// following time offsets:
//
// 0 - 0.5 usec: first impulse.
// 1.0 - 1.5 usec: second impulse.
// 3.5 - 4 usec: third impulse.
// 4.5 - 5 usec: last impulse.
//
// Since we are sampling at 2 Mhz every sample in our magnitude vector is
// 0.5 usec, so the preamble will look like this, assuming there is an
// impulse at offset 0 in the array:
//
// 0 -----------------
// 1 -
// 2 ------------------
// 3 --
// 4 -
// 5 --
// 6 -
// 7 ------------------
// 8 --
// 9 -------------------
for (j = 0; j < maglen - MODE_S_FULL_LEN*2; j++)
{
int low, high, delta, i, errors;
int good_message = 0;
@ -660,72 +666,83 @@ good_preamble:
}
}
// Restore the original message if we used magnitude correction.
if (use_correction)
memcpy(mag+j+MODE_S_PREAMBLE_US*2, aux, sizeof(aux));
// Restore the original message if we used magnitude correction.
if (use_correction)
{
memcpy(mag+j+MODE_S_PREAMBLE_US*2, aux, sizeof(aux));
}
// Pack bits into bytes
for (i = 0; i < MODE_S_LONG_MSG_BITS; i += 8) {
msg[i/8] =
bits[i]<<7 |
bits[i+1]<<6 |
bits[i+2]<<5 |
bits[i+3]<<4 |
bits[i+4]<<3 |
bits[i+5]<<2 |
bits[i+6]<<1 |
bits[i+7];
}
// Pack bits into bytes
for (i = 0; i < MODE_S_LONG_MSG_BITS; i += 8)
{
msg[i/8] =
bits[i]<<7 |
bits[i+1]<<6 |
bits[i+2]<<5 |
bits[i+3]<<4 |
bits[i+4]<<3 |
bits[i+5]<<2 |
bits[i+6]<<1 |
bits[i+7];
}
int msgtype = msg[0]>>3;
int msglen = mode_s_msg_len_by_type(msgtype)/8;
int msgtype = msg[0]>>3;
int msglen = mode_s_msg_len_by_type(msgtype)/8;
// Last check, high and low bits are different enough in magnitude to
// mark this as real message and not just noise?
delta = 0;
for (i = 0; i < msglen*8*2; i += 2) {
delta += abs(mag[j+i+MODE_S_PREAMBLE_US*2]-
mag[j+i+MODE_S_PREAMBLE_US*2+1]);
}
delta /= msglen*4;
// Last check, high and low bits are different enough in magnitude to
// mark this as real message and not just noise?
delta = 0;
for (i = 0; i < msglen*8*2; i += 2)
{
delta += abs(mag[j+i+MODE_S_PREAMBLE_US*2]-
mag[j+i+MODE_S_PREAMBLE_US*2+1]);
}
delta /= msglen*4;
// Filter for an average delta of three is small enough to let almost
// every kind of message to pass, but high enough to filter some random
// noise.
if (delta < 10*255) {
use_correction = 0;
continue;
}
// Filter for an average delta of three is small enough to let almost
// every kind of message to pass, but high enough to filter some random
// noise.
if (delta < 10*255)
{
use_correction = 0;
continue;
}
// If we reached this point, and error is zero, we are very likely with
// a Mode S message in our hands, but it may still be broken and CRC
// may not be correct. This is handled by the next layer.
if (errors == 0 || (self->aggressive && errors < 3)) {
struct mode_s_msg mm;
// If we reached this point, and error is zero, we are very likely with
// a Mode S message in our hands, but it may still be broken and CRC
// may not be correct. This is handled by the next layer.
if (errors == 0 || (self->aggressive && errors < 3))
{
struct mode_s_msg mm;
// Decode the received message
mode_s_decode(self, &mm, msg);
// Decode the received message
mode_s_decode(self, &mm, msg);
// Skip this message if we are sure it's fine.
if (mm.crcok) {
j += (MODE_S_PREAMBLE_US+(msglen*8))*2;
good_message = 1;
if (use_correction)
mm.phase_corrected = 1;
}
// Skip this message if we are sure it's fine.
if (mm.crcok)
{
j += (MODE_S_PREAMBLE_US+(msglen*8))*2;
good_message = 1;
if (use_correction)
mm.phase_corrected = 1;
}
// Pass data to the next layer
if (self->check_crc == 0 || mm.crcok) {
cb(self, &mm);
}
}
// Pass data to the next layer
if (self->check_crc == 0 || mm.crcok)
{
cb(self, &mm);
}
}
// Retry with phase correction if possible.
if (!good_message && !use_correction) {
j--;
use_correction = 1;
} else {
use_correction = 0;
}
}
// Retry with phase correction if possible.
if (!good_message && !use_correction)
{
j--;
use_correction = 1;
}
else
{
use_correction = 0;
}
}
}

Wyświetl plik

@ -24,59 +24,61 @@ extern "C" {
#define MODE_S_UNIT_METERS 1
// Program state
typedef struct {
// Internal state
uint32_t icao_cache[sizeof(uint32_t)*MODE_S_ICAO_CACHE_LEN*2]; // Recently seen ICAO addresses cache
typedef struct
{
// Internal state
uint32_t icao_cache[sizeof(uint32_t)*MODE_S_ICAO_CACHE_LEN*2]; // Recently seen ICAO addresses cache
// Configuration
int fix_errors; // Single bit error correction if true
int aggressive; // Aggressive detection algorithm
int check_crc; // Only display messages with good CRC
// Configuration
int fix_errors; // Single bit error correction if true
int aggressive; // Aggressive detection algorithm
int check_crc; // Only display messages with good CRC
} mode_s_t;
// The struct we use to store information about a decoded message
struct mode_s_msg {
// Generic fields
unsigned char msg[MODE_S_LONG_MSG_BYTES]; // Binary message
int msgbits; // Number of bits in message
int msgtype; // Downlink format #
int crcok; // True if CRC was valid
uint32_t crc; // Message CRC
int errorbit; // Bit corrected. -1 if no bit corrected.
int aa1, aa2, aa3; // ICAO Address bytes 1 2 and 3
int phase_corrected; // True if phase correction was applied.
struct mode_s_msg
{
// Generic fields
unsigned char msg[MODE_S_LONG_MSG_BYTES]; // Binary message
int msgbits; // Number of bits in message
int msgtype; // Downlink format #
int crcok; // True if CRC was valid
uint32_t crc; // Message CRC
int errorbit; // Bit corrected. -1 if no bit corrected.
int aa1, aa2, aa3; // ICAO Address bytes 1 2 and 3
int phase_corrected; // True if phase correction was applied.
// DF 11
int ca; // Responder capabilities.
// DF 11
int ca; // Responder capabilities.
// DF 17
int metype; // Extended squitter message type.
int mesub; // Extended squitter message subtype.
int heading_is_valid;
int heading;
int aircraft_type;
int fflag; // 1 = Odd, 0 = Even CPR message.
int tflag; // UTC synchronized?
int raw_latitude; // Non decoded latitude
int raw_longitude; // Non decoded longitude
char flight[9]; // 8 chars flight number.
int ew_dir; // 0 = East, 1 = West.
int ew_velocity; // E/W velocity.
int ns_dir; // 0 = North, 1 = South.
int ns_velocity; // N/S velocity.
int vert_rate_source; // Vertical rate source.
int vert_rate_sign; // Vertical rate sign.
int vert_rate; // Vertical rate.
int velocity; // Computed from EW and NS velocity.
// DF 17
int metype; // Extended squitter message type.
int mesub; // Extended squitter message subtype.
int heading_is_valid;
int heading;
int aircraft_type;
int fflag; // 1 = Odd, 0 = Even CPR message.
int tflag; // UTC synchronized?
int raw_latitude; // Non decoded latitude
int raw_longitude; // Non decoded longitude
char flight[9]; // 8 chars flight number.
int ew_dir; // 0 = East, 1 = West.
int ew_velocity; // E/W velocity.
int ns_dir; // 0 = North, 1 = South.
int ns_velocity; // N/S velocity.
int vert_rate_source; // Vertical rate source.
int vert_rate_sign; // Vertical rate sign.
int vert_rate; // Vertical rate.
int velocity; // Computed from EW and NS velocity.
// DF4, DF5, DF20, DF21
int fs; // Flight status for DF4,5,20,21
int dr; // Request extraction of downlink request.
int um; // Request extraction of downlink request.
int identity; // 13 bits identity (Squawk).
// DF4, DF5, DF20, DF21
int fs; // Flight status for DF4,5,20,21
int dr; // Request extraction of downlink request.
int um; // Request extraction of downlink request.
int identity; // 13 bits identity (Squawk).
// Fields used by multiple message types.
int altitude, unit;
// Fields used by multiple message types.
int altitude, unit;
};
typedef void (*mode_s_callback_t)(mode_s_t *self, struct mode_s_msg *mm);

Wyświetl plik

@ -16,15 +16,15 @@ import SoapySDR
from SoapySDR import SOAPY_SDR_RX, SOAPY_SDR_TX, SOAPY_SDR_CS16
def setup_receiver(sdr, channel, freq_hz):
use_agc = False # Use or don't use the AGC
# The wide channel parameters
sdr.setGainMode(SOAPY_SDR_RX, channel, use_agc) # Set the gain mode
sdr.setGain(SOAPY_SDR_RX, channel, 0) # Set the gain
sdr.setFrequency(SOAPY_SDR_RX, channel, freq_hz) # Tune the LO
sdr.setBandwidth(SOAPY_SDR_RX, channel, 2500e5)
rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [channel]) # Setup data stream
return rx_stream
def setup_receiver(sdr, freq_hz):
use_agc = False
sdr.setGainMode(SOAPY_SDR_RX, 0, use_agc)
sdr.setGain(SOAPY_SDR_RX, 0, 50)
sdr.setBandwidth(SOAPY_SDR_RX, 0, 2500e5)
sdr.setFrequency(SOAPY_SDR_RX, 0, freq_hz)
rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CS16, [0])
return rx_stream
def update_receiver_freq(sdr, stream, channel, freq_hz):
sdr.setFrequency(SOAPY_SDR_RX, channel, freq_hz)
@ -35,14 +35,14 @@ def update_receiver_freq(sdr, stream, channel, freq_hz):
##
# Data and Source Configuration
rx_chan = 0 # 6G = 1
N = 16384 # Number of complex samples per transfer
Fs = 4e6
N = int(Fs/4) # Number of complex samples per transfer
rx_buff = np.empty(2 * N, np.int16) # Create memory buffer for data stream
freq = 915e6
freq = 1090e6
# Initialize CaribouLite Soapy
sdr = SoapySDR.Device(dict(driver="Cariboulite")) # Create Cariboulite
rx_stream = setup_receiver(sdr, rx_chan, freq)
sdr = SoapySDR.Device({"driver": "Cariboulite", "device_id": "1"})
rx_stream = setup_receiver(sdr, freq)
sdr.activateStream(rx_stream)
sr = sdr.readStream(rx_stream, [rx_buff], N, timeoutUs=int(5e6))
@ -52,29 +52,33 @@ if (rc != N):
print("Error Reading Samples from Device (error code = %d)!" % rc)
exit
s_real = rx_buff[::2].astype(np.float32)
s_imag = -rx_buff[1::2].astype(np.float32)
s_real = rx_buff[::2].astype(np.float32) / 4096.0
s_imag = rx_buff[1::2].astype(np.float32) / 4096.0
x = s_real + 1j*s_imag
## PSD
Fs = 4e6
#N = 2048
#x = x[0:N] # we will only take the FFT of the first 1024 samples, see text below
x = x * np.hamming(len(x)) # apply a Hamming window
#x = x * np.hamming(len(x)) # apply a Hamming window
PSD = (np.abs(np.fft.fft(x))/N)**2
PSD_log = 10.0*np.log10(PSD)
PSD_shifted = np.fft.fftshift(PSD_log)
#PSD = (np.abs(np.fft.fft(x))/N)**2
#PSD_log = 10.0*np.log10(PSD)
#PSD_shifted = np.fft.fftshift(PSD_log)
center_freq = freq
f = np.arange(Fs/-2.0, Fs/2.0, Fs/N) # start, stop, step. centered around 0 Hz
#center_freq = freq
#f = np.arange(Fs/-2.0, Fs/2.0, Fs/N) # start, stop, step. centered around 0 Hz
#f += center_freq # now add center frequency
fig = plt.figure()
plt.plot(f, PSD_shifted)
plt.show()
window_size = 2048
overlap = window_size - 64
fig = plt.figure()
plt.plot(s_real)
plt.plot(s_imag)
plt.show()
#plt.plot(f, PSD_shifted)
plt.specgram(x, NFFT=window_size, Fs=Fs, noverlap=overlap, mode='psd')
plt.show()
#fig = plt.figure()
#plt.plot(s_real)
#plt.plot(s_imag)
#plt.show()

Wyświetl plik

@ -68,7 +68,10 @@ SoapySDR::KwargsList findCariboulite(const SoapySDR::Kwargs &args)
}
// no filterring specified, return all results
if (args.count("serial") == 0 && args.count("label") == 0 && args.count("device_id") == 0) return results;
if (args.count("serial") == 0 &&
args.count("label") == 0 &&
args.count("device_id") == 0 &&
args.count("channel") == 0) return results;
// filter the return according to the "serial" or "label" or "device_id"
std::vector<SoapySDR::Kwargs> filteredResults;
@ -77,6 +80,7 @@ SoapySDR::KwargsList findCariboulite(const SoapySDR::Kwargs &args)
int req_dev_num = args.count("device_id") == 0 ? -1 : atoi(args.at("device_id").c_str());
std::string req_serial = args.count("serial") == 0 ? "" : args.at("serial");
std::string req_label = args.count("label") == 0 ? "" : args.at("label");
std::string req_channel = args.count("channel") == 0 ? "" : args.at("channel");
// search for the requested devNum within the un-filterred results
for (size_t i = 0; i < results.size(); i++)
@ -85,10 +89,12 @@ SoapySDR::KwargsList findCariboulite(const SoapySDR::Kwargs &args)
int curDevNum = atoi(curArgs.at("device_id").c_str());
std::string curSerial = curArgs.at("serial");
std::string curLabel = curArgs.at("label");
std::string curChannel = curArgs.at("channel");
if (curDevNum == req_dev_num ||
!curSerial.compare(req_serial) ||
!curLabel.compare(req_label))
!curLabel.compare(req_label) ||
!curChannel.compare(req_channel))
{
filteredResults.push_back(curArgs);
}