Features:

- initial support for multiples tracks simulation

Enhancements:
- code profiling and optimization
 - faster lookup table based ppm + IQ generation
 - faster CRC24 computations
 - frame encoding

Bug fixes:
- callsign encoding
- typos
This commit is contained in:
Mathieu Peyréga
2022-03-15 20:23:40 +01:00
parent 5642c6564e
commit bc9687feb9
21 changed files with 645 additions and 292 deletions

View File

@@ -21,10 +21,10 @@ You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
"""
import time
import time, datetime
import abc
import threading
from CustomDecorators import *
from ModeS import ModeS
class AbstractTrajectorySimulatorBase(threading.Thread,abc.ABC):
@@ -38,60 +38,120 @@ class AbstractTrajectorySimulatorBase(threading.Thread,abc.ABC):
self._do_stop = False
self._position_message_period_us = 150000 # max should be 0.2s
self._velocity_message_period_us = 1200000 # max should be 1.3s
self._identitification_message_period_us = 10000000 # max should be 15s
self._squawk_message_period_us = 800000 # TODO : specs says that interval should be randomized between [0.7s;0.9s] and max is 1.0s
self._startruntime = None
self._simstep = 0
# Thread core function
def run(self):
is_first_step = True
while not self._do_stop:
encoder_changed = False
# check if modeS encoder needs update
if self._aircraftinfos.icao_changed or self._aircraftinfos.capability_changed or is_first_step:
self._modeSencoder.icao = self._aircraftinfos.icao
self._modeSencoder.ca = self._aircraftinfos.capability
encoder_changed = True
now = datetime.datetime.now(datetime.timezone.utc)
if (not self._startruntime or (now - self._startruntime).total_seconds() >= self._simstep*self.refresh_delay()):
self._simstep += 1
encoder_changed = False
if encoder_changed or self._aircraftinfos.callsign_changed:
self.df_callsign = self._modeSencoder.callsign_encode(self._aircraftinfos.callsign)
self._broadcast_thread.replace_message("identification",self.df_callsign)
#self._broadcast_thread.getMutex().acquire()
# check if modeS encoder needs update
if self._aircraftinfos.icao_changed or self._aircraftinfos.capability_changed or not self._startruntime:
self._modeSencoder.icao = self._aircraftinfos.icao
self._modeSencoder.ca = self._aircraftinfos.capability
encoder_changed = True
if encoder_changed or self._aircraftinfos.squawk_changed:
self.frame_6116 = self._modeSencoder.modaA_encode(self._aircraftinfos.squawk)
self._broadcast_thread.replace_message("register_6116",self.frame_6116)
if encoder_changed or self._aircraftinfos.callsign_changed:
self.df_callsign = self._modeSencoder.callsign_encode(self._aircraftinfos.callsign)
self._broadcast_thread.replace_message("identification",self.df_callsign)
# message generation only if needed
if encoder_changed or self._aircraftinfos.on_surface_changed \
or self._aircraftinfos.lat_changed or self._aircraftinfos.lon_changed or self._aircraftinfos.alt_msl_changed \
or self._aircraftinfos.type_code_changed or self._aircraftinfos.surveillance_status_changed or self._aircraftinfos.nicsupb_changed \
or self._aircraftinfos.timesync_changed:
if not self._aircraftinfos.on_surface:
(self.df_pos_even, self.df_pos_odd) = self._modeSencoder.df_encode_airborne_position(self._aircraftinfos.lat_deg, self._aircraftinfos.lon_deg, self._aircraftinfos.alt_msl_ft, \
self._aircraftinfos.type_code, self._aircraftinfos.surveillance_status, self._aircraftinfos.nicsupb, self._aircraftinfos.timesync)
self._broadcast_thread.replace_message("airborne_position",self.df_pos_even,self.df_pos_odd)
self._broadcast_thread.replace_message("surface_position",[], [])
else:
(self.df_pos_even, self.df_pos_odd) = self._modeSencoder.df_encode_surface_position(self._aircraftinfos.lat_deg, self._aircraftinfos.lon_deg, self._aircraftinfos.alt_msl_ft, \
self._aircraftinfos.type_code, self._aircraftinfos.surveillance_status, self._aircraftinfos.nicsupb, self._aircraftinfos.timesync)
self._broadcast_thread.replace_message("surface_position",self.df_pos_even,self.df_pos_odd)
self._broadcast_thread.replace_message("airborne_position",[], [])
if encoder_changed or self._aircraftinfos.squawk_changed:
self.frame_6116 = self._modeSencoder.modaA_encode(self._aircraftinfos.squawk)
self._broadcast_thread.replace_message("register_6116",self.frame_6116)
if encoder_changed or self._aircraftinfos.speed_changed or self._aircraftinfos.track_angle_changed or self._aircraftinfos.vspeed_changed:
self.df_velocity = self._modeSencoder.df_encode_ground_velocity(self._aircraftinfos.speed_kt, self._aircraftinfos.track_angle_deg, self._aircraftinfos.vspeed_ftpmin)
self._broadcast_thread.replace_message("airborne_velocity",self.df_velocity)
# message generation only if needed
if encoder_changed or self._aircraftinfos.on_surface_changed \
or self._aircraftinfos.lat_changed or self._aircraftinfos.lon_changed or self._aircraftinfos.alt_msl_changed \
or self._aircraftinfos.type_code_changed or self._aircraftinfos.surveillance_status_changed or self._aircraftinfos.nicsupb_changed \
or self._aircraftinfos.timesync_changed:
if not self._aircraftinfos.on_surface:
(self.df_pos_even, self.df_pos_odd) = self._modeSencoder.df_encode_airborne_position(self._aircraftinfos.lat_deg, self._aircraftinfos.lon_deg, self._aircraftinfos.alt_msl_ft, \
self._aircraftinfos.type_code, self._aircraftinfos.surveillance_status, self._aircraftinfos.nicsupb, self._aircraftinfos.timesync)
self._broadcast_thread.replace_message("airborne_position",self.df_pos_even,self.df_pos_odd)
self._broadcast_thread.replace_message("surface_position",[], [])
else:
(self.df_pos_even, self.df_pos_odd) = self._modeSencoder.df_encode_surface_position(self._aircraftinfos.lat_deg, self._aircraftinfos.lon_deg, self._aircraftinfos.alt_msl_ft, \
self._aircraftinfos.type_code, self._aircraftinfos.surveillance_status, self._aircraftinfos.nicsupb, self._aircraftinfos.timesync)
self._broadcast_thread.replace_message("surface_position",self.df_pos_even,self.df_pos_odd)
self._broadcast_thread.replace_message("airborne_position",[], [])
is_first_step = False
self.update_aircraftinfos() # update_aircraftinfos() : abstract method that need to be implemented i nderived classes
time.sleep(self.refresh_delay()) # refresh_delay() : abstract method that need to be implemented i nderived classes
if encoder_changed or self._aircraftinfos.speed_changed or self._aircraftinfos.track_angle_changed or self._aircraftinfos.vspeed_changed:
self.df_velocity = self._modeSencoder.df_encode_ground_velocity(self._aircraftinfos.speed_kt, self._aircraftinfos.track_angle_deg, self._aircraftinfos.vspeed_ftpmin)
self._broadcast_thread.replace_message("airborne_velocity",self.df_velocity)
#self._broadcast_thread.getMutex().release()
if not self._startruntime:
self._startruntime = now
self.update_aircraftinfos() # update_aircraftinfos() : abstract method that need to be implemented in derived classes
#elapsed = (datetime.datetime.now(datetime.timezone.utc) - now).total_seconds()
#sleep_time = self.refresh_delay() - elapsed
#if sleep_time < 0.0:
# sleep_time = 0.0
time.sleep(0.05*self.refresh_delay()) # refresh_delay() : abstract method that need to be implemented in derived classes
# upon exit, reset _do_stop flag in case there is a new start
self._do_stop = False
def stop(self):
self._do_stop = True
@abc.abstractmethod
def refresh_delay(self):
...
@abc.abstractmethod
def update_aircraftinfos(self):
...
...
def stop(self):
self._do_stop = True
@property
def elapsed_sim_time(self):
return self._simstep*self.refresh_delay()
@property
def aircraftinfos(self):
return self._aircraftinfos
@property
def position_message_period_us(self):
return self._position_message_period_us
@position_message_period_us.setter
def position_message_period_us(self,value):
self._position_message_period_us = value
@property
def velocity_message_period_us(self):
return self._velocity_message_period_us
@velocity_message_period_us.setter
def velocity_message_period_us(self,value):
self._velocity_message_period_us = value
@property
def identitification_message_period_us(self):
return self._identitification_message_period_us
@identitification_message_period_us.setter
def identitification_message_period_us(self,value):
self._identitification_message_period_us = value
@property
def squawk_message_period_us(self):
return self._squawk_message_period_us
@squawk_message_period_us.setter
def squawk_message_period_us(self,value):
self._squawk_message_period_us = value