diff --git a/.gitignore b/.gitignore index 03d9374..3d4eb7b 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ build dist *.so test*.sh +.idea/* +.idea/ diff --git a/ac_decoder.cpp b/ac_decoder.cpp new file mode 100755 index 0000000..52aa576 --- /dev/null +++ b/ac_decoder.cpp @@ -0,0 +1,226 @@ +#include "ac_decoder.h" +#include +#include +#include + +ac_decoder::ac_decoder() + :check_stat_interval(10) +{ + next_check_time = time(NULL) + check_stat_interval ; +} + +ac_decode_result_t ac_decoder::decode(unsigned char ac[2] ) +{ + ac_decode_result_t result ; + memset(&result ,0 ,sizeof(ac_decode_result_t)); + + result.type = AC_MODE_NA ; + + time_t now = time(NULL) ; + if(now > next_check_time) + { + commit_ac_mode_stat() ; + next_check_time = now + check_stat_interval ; + } + + if(ac[0]+ac[1]==0) + return result; + + if(ac[1]&0x40) + return result; + + unsigned short modeac = + ((ac[0] & 0x10) ? 0x0010 : 0) | // C1 + ((ac[0] & 0x08) ? 0x1000 : 0) | // A1 + ((ac[0] & 0x04) ? 0x0020 : 0) | // C2 + ((ac[0] & 0x02) ? 0x2000 : 0) | // A2 + ((ac[0] & 0x01) ? 0x0040 : 0) | // C4 + ((ac[1] & 0x80) ? 0x4000 : 0) | // A4 + ((ac[1] & 0x20) ? 0x0100 : 0) | // B1 + ((ac[1] & 0x10) ? 0x0001 : 0) | // D1 + ((ac[1] & 0x08) ? 0x0200 : 0) | // B2 + ((ac[1] & 0x04) ? 0x0002 : 0) | // D2 + ((ac[1] & 0x02) ? 0x0400 : 0) | // B4 + ((ac[1] & 0x01) ? 0x0004 : 0) | // D4 + ((ac[0] & 0x80) ? 0x0080 : 0); // SPI + + int ac_type = get_ac_type(modeac) ; + if(ac_type == AC_MODE_NA) + { + return result ; + } + else if(ac_type == AC_MODE_A) + { + result.type = AC_MODE_A ; + result.squawk = modeac & 0x7777 ; + result.is_spi = modeac & 0x0080?true:false ; + return result ; + } + else + { + result.type = AC_MODE_C ; + int alt = modeA2modeC(modeac) ; + result.altitude = (alt==AC_INVALID_ALTITUDE)?AC_INVALID_ALTITUDE:(alt*100); + return result ; + } + +} + +int ac_decoder::get_ac_type(unsigned short modeac ) +{ + +#define MIN_AC_COUNT 3 + + if(modeac&0x0080) + { + return AC_MODE_A ; + } + + unsigned short squawk = modeac&0x7777 ; + if(squawk ==0x7500 || + squawk ==0x7600 || + squawk == 0x7700) + return AC_MODE_A ; + + int cvalue = (modeac>>4)&0x0007 ; + int dvalue = modeac&0x0007; + + if((cvalue==0 || + cvalue==5 || + cvalue==7)|| + (dvalue==1 || + dvalue==2 || + dvalue==3 || + dvalue==5 || + dvalue==6 || + dvalue==7) + ) + { + int counted =get_mode_count_stat(a_mode_stat , modeac); + inc_mode_stat(a_mode_stat,modeac); + if(counted ==-1 || counted >MIN_AC_COUNT) + { + return AC_MODE_A ; + } + else + { + return AC_MODE_NA ; + } + } + + int counted =get_mode_count_stat(na_mode_stat ,modeac); + if(counted >MIN_AC_COUNT) + { + int altitude = AC_INVALID_ALTITUDE ; + int modeC = modeA2modeC(modeac); + if (modeC != AC_INVALID_ALTITUDE) + { + altitude = modeC * 100; + if(altitude >=16700 && altitude <=48900) + { + return AC_MODE_C ; + } + else + { + inc_mode_stat(a_mode_stat , modeac); + return AC_MODE_A ; + } + } + else + { + inc_mode_stat(a_mode_stat , modeac); + return AC_MODE_A ; + } + + } + + inc_mode_stat(na_mode_stat , modeac); + return AC_MODE_NA; +} +int ac_decoder::modeA2modeC(unsigned int modea) +{ + unsigned int FiveHundreds = 0; + unsigned int OneHundreds = 0; + + if ((modea & 0xFFFF8889) != 0 || // check zero bits are zero, D1 set is illegal + (modea & 0x000000F0) == 0) { // C1,,C4 cannot be Zero + return AC_INVALID_ALTITUDE; + } + + if (modea & 0x0010) {OneHundreds ^= 0x007;} // C1 + if (modea & 0x0020) {OneHundreds ^= 0x003;} // C2 + if (modea & 0x0040) {OneHundreds ^= 0x001;} // C4 + + // Remove 7s from OneHundreds (Make 7->5, snd 5->7). + if ((OneHundreds & 5) == 5) {OneHundreds ^= 2;} + + // Check for invalid codes, only 1 to 5 are valid + if (OneHundreds > 5) { + return AC_INVALID_ALTITUDE; + } + + //if (ModeA & 0x0001) {FiveHundreds ^= 0x1FF;} // D1 never used for altitude + if (modea & 0x0002) {FiveHundreds ^= 0x0FF;} // D2 + if (modea & 0x0004) {FiveHundreds ^= 0x07F;} // D4 + + if (modea & 0x1000) {FiveHundreds ^= 0x03F;} // A1 + if (modea & 0x2000) {FiveHundreds ^= 0x01F;} // A2 + if (modea & 0x4000) {FiveHundreds ^= 0x00F;} // A4 + + if (modea & 0x0100) {FiveHundreds ^= 0x007;} // B1 + if (modea & 0x0200) {FiveHundreds ^= 0x003;} // B2 + if (modea & 0x0400) {FiveHundreds ^= 0x001;} // B4 + + // Correct order of OneHundreds. + if (FiveHundreds & 1) {OneHundreds = 6 - OneHundreds;} + + return ((FiveHundreds * 5) + OneHundreds - 13); +} + + int ac_decoder::get_mode_count_stat(ac_count_stat_t& which , unsigned short modea) +{ + ac_count_stat_t::const_iterator it = which.find(modea); + return (it==which.end())?-1:(it->second.counted) ; +} + +void ac_decoder::inc_mode_stat(ac_count_stat_t& which , unsigned short modea ) +{ + //printf("which = %d\r\n" , which.size()); + ac_count_stat_t::iterator it = which.find(modea); + if(it== which.end()) { + ac_count_stat_item_t item = {0,1 }; + which.insert(std::make_pair(modea , item)); + } + else + { + it->second.counting++ ; + } +} + +void ac_decoder::commit_ac_mode_stat() +{ + ac_count_stat_t ::iterator it =a_mode_stat.begin(); + for(; it!=a_mode_stat.end(); ++it) + { + it->second.counted = it->second.counting ; + it->second.counting = 0 ; + } + + it =na_mode_stat.begin(); + for(; it!=na_mode_stat.end(); ++it) + { + it->second.counted = it->second.counting ; + it->second.counting = 0 ; + } +} + + + +ac_decoder* global_ac_decoder_ptr = NULL ; + ac_decode_resultd ac_decode(unsigned char ac[2]) +{ + if(global_ac_decoder_ptr == NULL) + global_ac_decoder_ptr = new ac_decoder() ; + + return global_ac_decoder_ptr->decode(ac); +} diff --git a/ac_decoder.h b/ac_decoder.h new file mode 100755 index 0000000..bdc0cd9 --- /dev/null +++ b/ac_decoder.h @@ -0,0 +1,35 @@ +#ifndef __AC_DECODER_INCLUDE__ +#define __AC_DECODER_INCLUDE__ +#include +#include +#include "ac_decoder_c.h" + + + +class ac_decoder +{ +public: + ac_decoder() ; + ac_decode_result_t decode(unsigned char ac[2]) ; +private: + typedef struct ac_count_stat_item + { + int counted; + int counting ; + }ac_count_stat_item_t; + typedef std::map ac_count_stat_t ; +private: + int get_ac_type(unsigned short modeac) ; + int get_mode_count_stat(ac_count_stat_t& which , unsigned short modea); + void inc_mode_stat(ac_count_stat_t& which ,unsigned short modea); + void commit_ac_mode_stat(); + int modeA2modeC(unsigned int modea) ; + +private: + time_t next_check_time ; + const int check_stat_interval ; + ac_count_stat_t a_mode_stat ; + ac_count_stat_t na_mode_stat ; +} ; + +#endif diff --git a/ac_decoder_c.h b/ac_decoder_c.h new file mode 100644 index 0000000..77fb28c --- /dev/null +++ b/ac_decoder_c.h @@ -0,0 +1,28 @@ +#ifndef __AC_DECODER_INCLUDE_C_INCLUDE_ +#define __AC_DECODER_INCLUDE_C_INCLUDE_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ac_decode_resultd +{ + int type ; + unsigned short squawk ; + int is_spi ; + int altitude ; +}ac_decode_result_t ; + +#define AC_MODE_A 1 +#define AC_MODE_C 2 +#define AC_MODE_NA 0 +#define AC_INVALID_ALTITUDE -1 + + +ac_decode_result_t ac_decode(unsigned char ac[2]) ; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/mlat/client/coordinator.py b/mlat/client/coordinator.py index fcab6ad..8e5353b 100644 --- a/mlat/client/coordinator.py +++ b/mlat/client/coordinator.py @@ -50,7 +50,7 @@ class Coordinator: update_interval = 5.0 report_interval = 30.0 stats_interval = 900.0 - position_expiry_age = 30.0 + position_expiry_age = 5.0 expiry_age = 60.0 def __init__(self, receiver, server, outputs, freq, allow_anon, allow_modeac): @@ -352,8 +352,8 @@ def received_df_misc(self, message, now): return # Candidate for MLAT - if now - ac.last_position_time < self.position_expiry_age: - return # reported position recently, no need for mlat + #if now - ac.last_position_time < self.position_expiry_age: + # return # reported position recently, no need for mlat self.server.send_mlat(message) def received_df11(self, message, now): @@ -376,8 +376,8 @@ def received_df11(self, message, now): return # Candidate for MLAT - if now - ac.last_position_time < self.position_expiry_age: - return # reported position recently, no need for mlat + #if now - ac.last_position_time < self.position_expiry_age: + # return # reported position recently, no need for mlat self.server.send_mlat(message) def received_df17(self, message, now): @@ -430,9 +430,31 @@ def received_df17(self, message, now): # this is a useful reference message pair self.server.send_sync(ac.even_message, ac.odd_message) + self.server.send_mlat(message) def received_modeac(self, message, now): - if message.address not in self.requested_modeac: + #AC Mode + + #print("received_modeac : " ,message.address ) + ac = self.aircraft.get(message.address) + if not ac: + ac = Aircraft(message.address) + ac.requested = (message.address in self.requested_traffic) + ac.messages += 1 + ac.last_message_time = now + ac.rate_measurement_start = now + self.aircraft[message.address] = ac + return # wait for more messages + + ac.messages += 1 + ac.last_message_time = now + if ac.messages < 10: + return + + ac.recent_adsb_positions += 1 + #if message.address not in self.requested_modeac: + # return + if not ac.requested: return self.server.send_mlat(message) diff --git a/mlat/client/jsonclient.py b/mlat/client/jsonclient.py index 60572ba..d961704 100644 --- a/mlat/client/jsonclient.py +++ b/mlat/client/jsonclient.py @@ -36,7 +36,7 @@ from mlat.client.util import log, monotonic_time from mlat.client.stats import global_stats -DEBUG = False +DEBUG = True # UDP protocol submessages diff --git a/modes_message.c b/modes_message.c index 724fab8..13c6fc1 100644 --- a/modes_message.c +++ b/modes_message.c @@ -17,6 +17,7 @@ */ #include "_modes.h" +#include "ac_decoder_c.h" /* methods / type behaviour */ static PyObject *modesmessage_new(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -112,11 +113,14 @@ static PyTypeObject modesmessageType = { modesmessage_new, /* tp_new */ }; + /* * module setup */ int modesmessage_module_init(PyObject *m) { + + if (PyType_Ready(&modesmessageType) < 0) return -1; @@ -381,13 +385,29 @@ static int decode(modesmessage *self) Py_CLEAR(self->address); Py_CLEAR(self->altitude); + if (self->datalen == 2) { - self->df = DF_MODEAC; - self->address = PyLong_FromLong((self->data[0] << 8) | self->data[1]); - self->valid = 1; - return 0; + //AC Message decode , A Mode Start With 0xFFXXXX + + unsigned char ac[2] ; + memcpy(ac , self->data , 2); + ac_decode_result_t ac_ret = ac_decode(ac) ; + if(ac_ret.type == AC_MODE_A) + { + self->df = DF_MODEAC; + int ac_fix_icao = 0x00FF0000 | ac_ret.squawk ; + self->address = PyLong_FromLong(ac_fix_icao) ; + self->valid = 1; + return 0; + } + else + { + self->valid = 0; + } + } + self->df = (self->data[0] >> 3) & 31; if ((self->df < 16 && self->datalen != 7) || (self->df >= 16 && self->datalen != 14)) { diff --git a/modes_reader.c b/modes_reader.c index 1257ee4..d5c8138 100644 --- a/modes_reader.c +++ b/modes_reader.c @@ -1384,17 +1384,28 @@ static int filter_message(modesreader *self, PyObject *o) modesmessage *message = (modesmessage *)o; if (message->df == DF_MODEAC) { - if (self->modeac_filter != NULL && self->modeac_filter != Py_None) { - return PySequence_Contains(self->modeac_filter, message->address); - } + if (self->seen != NULL && self->seen != Py_None) + { + if (PySet_Add(self->seen, message->address) < 0) { + return -1; + } + } - return 1; + + // if (self->modeac_filter != NULL && self->modeac_filter != Py_None) { + // return PySequence_Contains(self->modeac_filter, message->address); + // } + // return -1; + + return 1 ; } - if (!message->valid) { + + if (!message->valid) { return self->want_invalid_messages; /* don't process further, contents are dubious */ } + if (self->seen != NULL && self->seen != Py_None) { if (message->df == 11 || message->df == 17 || message->df == 18) { /* note that we saw this aircraft, even if the message is filtered. diff --git a/nogps.sh b/nogps.sh new file mode 100755 index 0000000..e68eec4 --- /dev/null +++ b/nogps.sh @@ -0,0 +1 @@ +mlat-client --input-type sbs --input-connect 10.1.1.172:10001 --server 127.0.0.1:12590 --lon 121.429367 --lat 37.525049 --alt 35 --user SHDL diff --git a/setup.py b/setup.py index 92de640..bc622cc 100755 --- a/setup.py +++ b/setup.py @@ -25,13 +25,14 @@ more_warnings = False extra_compile_args = [] -if more_warnings and get_default_compiler() == 'unix': +#if more_warnings and get_default_compiler() == 'unix': # let's assume this is GCC - extra_compile_args.append('-Wpointer-arith') +# extra_compile_args.append('-Wpointer-arith') +# include_dirs=['/usr/include/x86_64-linux-gnu/c++/6'] modes_ext = Extension('_modes', - sources=['_modes.c', 'modes_reader.c', 'modes_message.c', 'modes_crc.c'], - extra_compile_args=extra_compile_args) + sources=['ac_decoder.cpp' ,'_modes.c', 'modes_reader.c', 'modes_message.c', 'modes_crc.c' ], + extra_compile_args=extra_compile_args ) setup(name='MlatClient', version=CLIENT_VERSION, diff --git a/version.txt b/version.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1