Merge branch 'testing' into experimental

pull/164/head
Mark Jessop 2019-04-14 14:48:22 +09:30
commit 01e8ded044
7 zmienionych plików z 292 dodań i 166 usunięć

Wyświetl plik

@ -61,6 +61,10 @@ exporter_objects = [] # This list will hold references to each exporter instan
exporter_functions = [] # This list will hold references to the exporter add functions, which will be passed onto the decoders. exporter_functions = [] # This list will hold references to the exporter add functions, which will be passed onto the decoders.
# Temporary frequency block list
# This contains frequncies that should be blocked for a short amount of time.
temporary_block_list = {}
# Scan Result Queue # Scan Result Queue
# Scan results are processed asynchronously from the main scanner object. # Scan results are processed asynchronously from the main scanner object.
@ -96,7 +100,7 @@ def allocate_sdr(check_only = False, task_description = ""):
def start_scanner(): def start_scanner():
""" Start a scanner thread on the first available SDR """ """ Start a scanner thread on the first available SDR """
global config, scan_results, RS_PATH global config, scan_results, RS_PATH, temporary_block_list
if 'SCAN' in autorx.task_list: if 'SCAN' in autorx.task_list:
# Already a scanner running! Return. # Already a scanner running! Return.
@ -136,7 +140,9 @@ def start_scanner():
gain = autorx.sdr_list[_device_idx]['gain'], gain = autorx.sdr_list[_device_idx]['gain'],
ppm = autorx.sdr_list[_device_idx]['ppm'], ppm = autorx.sdr_list[_device_idx]['ppm'],
bias = autorx.sdr_list[_device_idx]['bias'], bias = autorx.sdr_list[_device_idx]['bias'],
save_detection_audio = config['save_detection_audio'] save_detection_audio = config['save_detection_audio'],
temporary_block_list = temporary_block_list,
temporary_block_time = config['temporary_block_time']
) )
# Add a reference into the sdr_list entry # Add a reference into the sdr_list entry
@ -174,7 +180,19 @@ def start_decoder(freq, sonde_type):
sonde_type (str): The radiosonde type ('RS41', 'RS92', 'DFM', 'M10, 'iMet') sonde_type (str): The radiosonde type ('RS41', 'RS92', 'DFM', 'M10, 'iMet')
""" """
global config, RS_PATH, exporter_functions, rs92_ephemeris global config, RS_PATH, exporter_functions, rs92_ephemeris, temporary_block_list
# Check the frequency is not in our temporary block list
# (This may happen from time-to-time depending on the timing of the scan thread)
if freq in temporary_block_list.keys():
if temporary_block_list[freq] > (time.time()-config['temporary_block_time']*60):
logging.error("Task Manager - Attempted to start a decoder on a temporarily blocked frequency (%.3f MHz)" % (freq/1e6))
return
else:
# This frequency should not be blocked any more, remove it from the block list.
logging.info("Task Manager - Removed %.3f MHz from temporary block list." % (freq/1e6))
temporary_block_list.pop(freq)
# Allocate a SDR. # Allocate a SDR.
_device_idx = allocate_sdr(task_description="Decoder (%s, %.3f MHz)" % (sonde_type, freq/1e6)) _device_idx = allocate_sdr(task_description="Decoder (%s, %.3f MHz)" % (sonde_type, freq/1e6))
@ -250,6 +268,7 @@ def handle_scan_results():
# Break if we don't support this sonde type. # Break if we don't support this sonde type.
if (_check_type not in VALID_SONDE_TYPES): if (_check_type not in VALID_SONDE_TYPES):
logging.error("Unsupported sonde type: %s" % _check_type) logging.error("Unsupported sonde type: %s" % _check_type)
# TODO - Potentially add the frequency of the unsupported sonde to the temporary block list?
continue continue
if allocate_sdr(check_only=True) is not None : if allocate_sdr(check_only=True) is not None :
@ -277,19 +296,40 @@ def clean_task_list():
try: try:
_running = autorx.task_list[_key]['task'].running() _running = autorx.task_list[_key]['task'].running()
_task_sdr = autorx.task_list[_key]['device_idx'] _task_sdr = autorx.task_list[_key]['device_idx']
_exit_state = autorx.task_list[_key]['task'].exit_state
except Exception as e: except Exception as e:
logging.error("Task Manager - Error getting task %s state - %s" % (str(_key),str(e))) logging.error("Task Manager - Error getting task %s state - %s" % (str(_key),str(e)))
continue continue
if _running == False: if _running == False:
# This task has stopped. Release its associated SDR. # This task has stopped.
# Check the exit state of the task for any abnormalities:
if _exit_state == "Encrypted":
# This task was a decoder, and it has encountered an encrypted sonde.
logging.info("Task Manager - Adding temporary block for frequency %.3f MHz" % (_key/1e6))
# Add the sonde's frequency to the global temporary block-list
temporary_block_list[_key] = time.time()
# If there is a scanner currently running, add it to the scanners internal block list.
if 'SCAN' in autorx.task_list:
auto_rx.task_list['SCAN']['task'].add_temporary_block(_key)
# Release its associated SDR.
autorx.sdr_list[_task_sdr]['in_use'] = False autorx.sdr_list[_task_sdr]['in_use'] = False
autorx.sdr_list[_task_sdr]['task'] = None autorx.sdr_list[_task_sdr]['task'] = None
# Pop the task from the task list. # Pop the task from the task list.
autorx.task_list.pop(_key) autorx.task_list.pop(_key)
# Indicate to the web client that the task list has been updated. # Indicate to the web client that the task list has been updated.
flask_emit_event('task_event') flask_emit_event('task_event')
# Clean out the temporary block list of old entries.
for _freq in temporary_block_list.keys():
if temporary_block_list[_freq] < (time.time() - config['temporary_block_time']*60):
temporary_block_list.pop(_freq)
logging.info("Task Manager - Removed %.3f MHz from temporary block list." % (_freq/1e6))
# Check if there is a scanner thread still running. If not, and if there is a SDR free, start one up again. # Check if there is a scanner thread still running. If not, and if there is a SDR free, start one up again.
if ('SCAN' not in autorx.task_list) and (allocate_sdr(check_only=True) is not None): if ('SCAN' not in autorx.task_list) and (allocate_sdr(check_only=True) is not None):
# We have a SDR free, and we are not running a scan thread. Start one. # We have a SDR free, and we are not running a scan thread. Start one.

Wyświetl plik

@ -11,7 +11,7 @@
# MINOR - New sonde type support, other fairly big changes that may result in telemetry or config file incompatability issus. # MINOR - New sonde type support, other fairly big changes that may result in telemetry or config file incompatability issus.
# PATCH - Small changes, or minor feature additions. # PATCH - Small changes, or minor feature additions.
__version__ = "1.1.1-experimental" __version__ = "1.1.2-experimental"
# Global Variables # Global Variables

Wyświetl plik

@ -100,7 +100,8 @@ def read_auto_rx_config(filename):
'scan_dwell_time' : 20, 'scan_dwell_time' : 20,
'detect_dwell_time' : 5, 'detect_dwell_time' : 5,
'scan_delay' : 10, 'scan_delay' : 10,
'payload_id_valid' : 5, 'payload_id_valid' : 5,
'temporary_block_time' : 60,
# Rotator Settings # Rotator Settings
'enable_rotator': False, 'enable_rotator': False,
'rotator_update_rate': 30, 'rotator_update_rate': 30,
@ -245,6 +246,12 @@ def read_auto_rx_config(filename):
except: except:
logging.error("Config - Could not find station_code field, using default.") logging.error("Config - Could not find station_code field, using default.")
# New temporary block time - added 2019-04-14
try:
auto_rx_config['temporary_block_time'] = config.getint('advanced', 'temporary_block_time')
except:
logging.error("Config - New advanced settings missing, using defaults.")
# Now we attempt to read in the individual SDR parameters. # Now we attempt to read in the individual SDR parameters.
auto_rx_config['sdr_settings'] = {} auto_rx_config['sdr_settings'] = {}

Wyświetl plik

@ -142,6 +142,8 @@ class SondeDecoder(object):
# This will become our decoder thread. # This will become our decoder thread.
self.decoder = None self.decoder = None
self.exit_state = "OK"
# Detect if we have an 'inverted' sonde. # Detect if we have an 'inverted' sonde.
if self.sonde_type.startswith('-'): if self.sonde_type.startswith('-'):
self.inverted = True self.inverted = True
@ -407,6 +409,7 @@ class SondeDecoder(object):
if time.time() > (_last_packet + self.timeout): if time.time() > (_last_packet + self.timeout):
# If we have not seen data for a while, break. # If we have not seen data for a while, break.
self.log_error("RX Timed out.") self.log_error("RX Timed out.")
self.exit_state = "Timeout"
break break
else: else:
# Otherwise, sleep for a short time. # Otherwise, sleep for a short time.
@ -486,9 +489,12 @@ class SondeDecoder(object):
if _field not in _telemetry: if _field not in _telemetry:
_telemetry[_field] = self.DECODER_OPTIONAL_FIELDS[_field] _telemetry[_field] = self.DECODER_OPTIONAL_FIELDS[_field]
_telemetry['encrypted'] = True
# Check for an encrypted flag (this indicates a sonde that we cannot decode telemetry from.) # Check for an encrypted flag (this indicates a sonde that we cannot decode telemetry from.)
if 'encrypted' in _telemetry: if 'encrypted' in _telemetry:
self.log_error("Radiosonde %s has encrypted telemetry (possible RS41-SGM)! We cannot decode this, closing decoder." % _telemetry['id']) self.log_error("Radiosonde %s has encrypted telemetry (possible RS41-SGM)! We cannot decode this, closing decoder." % _telemetry['id'])
self.exit_state = "Encrypted"
self.decoder_running = False self.decoder_running = False
return False return False

Wyświetl plik

@ -13,7 +13,7 @@ import platform
import subprocess import subprocess
import time import time
import traceback import traceback
from threading import Thread from threading import Thread, Lock
from types import FunctionType, MethodType from types import FunctionType, MethodType
from .utils import detect_peaks, rtlsdr_test, reset_rtlsdr_by_serial, reset_all_rtlsdrs, peak_decimation from .utils import detect_peaks, rtlsdr_test, reset_rtlsdr_by_serial, reset_all_rtlsdrs, peak_decimation
try: try:
@ -358,7 +358,9 @@ class SondeScanner(object):
gain = -1, gain = -1,
ppm = 0, ppm = 0,
bias = False, bias = False,
save_detection_audio = False): save_detection_audio = False,
temporary_block_list = {},
temporary_block_time = 60):
""" Initialise a Sonde Scanner Object. """ Initialise a Sonde Scanner Object.
Apologies for the huge number of args... Apologies for the huge number of args...
@ -390,6 +392,8 @@ class SondeScanner(object):
gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC. gain (int): SDR Gain setting, in dB. A gain setting of -1 enables the RTLSDR AGC.
bias (bool): If True, enable the bias tee on the SDR. bias (bool): If True, enable the bias tee on the SDR.
save_detection_audio (bool): Save the audio used in each detecton to detect_<device_idx>.wav save_detection_audio (bool): Save the audio used in each detecton to detect_<device_idx>.wav
temporary_block_list (dict): A dictionary where each attribute represents a frequency that should be blacklisted for a set time.
temporary_block_time (int): How long (minutes) frequencies in the temporary block list should remain blocked for.
""" """
# Thread flag. This is set to True when a scan is running. # Thread flag. This is set to True when a scan is running.
@ -420,6 +424,14 @@ class SondeScanner(object):
self.callback = callback self.callback = callback
self.save_detection_audio = save_detection_audio self.save_detection_audio = save_detection_audio
# Temporary block list.
self.temporary_block_list = temporary_block_list.copy()
self.temporary_block_list_lock = Lock()
self.temporary_block_time = temporary_block_time
# Alert the user if there are temporary blocks in place.
if len(self.temporary_block_list.keys())>0:
self.log_info("Temporary blocks in place for frequencies: %s" % str(self.temporary_block_list.keys()))
# Error counter. # Error counter.
self.error_retries = 0 self.error_retries = 0
@ -439,8 +451,11 @@ class SondeScanner(object):
if not _rtlsdr_ok: if not _rtlsdr_ok:
self.log_error("RTLSDR #%s non-functional - exiting." % device_idx) self.log_error("RTLSDR #%s non-functional - exiting." % device_idx)
self.sonde_scanner_running = False self.sonde_scanner_running = False
self.exit_state = "Failed SDR"
return return
self.exit_state = "OK"
if auto_start: if auto_start:
self.start() self.start()
@ -611,6 +626,7 @@ class SondeScanner(object):
_, peak_idx = np.unique(peak_frequencies, return_index=True) _, peak_idx = np.unique(peak_frequencies, return_index=True)
peak_frequencies = peak_frequencies[np.sort(peak_idx)] peak_frequencies = peak_frequencies[np.sort(peak_idx)]
# Remove any frequencies in the blacklist. # Remove any frequencies in the blacklist.
for _frequency in np.array(self.blacklist)*1e6: for _frequency in np.array(self.blacklist)*1e6:
_index = np.argwhere(peak_frequencies==_frequency) _index = np.argwhere(peak_frequencies==_frequency)
@ -623,6 +639,25 @@ class SondeScanner(object):
# Append on any frequencies in the supplied greylist # Append on any frequencies in the supplied greylist
peak_frequencies = np.append(np.array(self.greylist)*1e6, peak_frequencies) peak_frequencies = np.append(np.array(self.greylist)*1e6, peak_frequencies)
# Remove any frequencies in the temporary block list
self.temporary_block_list_lock.acquire()
for _frequency in self.temporary_block_list.keys():
# Check the time the block was added.
if self.temporary_block_list[_frequency] > (time.time()-self.temporary_block_time*60):
# We should still be blocking this frequency, so remove any peaks with this frequency.
_index = np.argwhere(peak_frequencies==_frequency)
peak_frequencies = np.delete(peak_frequencies, _index)
if len(_index) > 0:
self.log_debug("Peak on %.3f MHz was removed due to temporary block." % (_frequency/1e6))
else:
# This frequency doesn't need to be blocked any more, remove it from the block list.
self.temporary_block_list.pop(_frequency)
self.log_info("Removed %.3f MHz from temporary block list." % (_frequency/1e6))
self.temporary_block_list_lock.release()
# Get the level of our peak search results, to send to the web client. # Get the level of our peak search results, to send to the web client.
# This is actually a bit of a pain to do... # This is actually a bit of a pain to do...
_peak_freq = [] _peak_freq = []
@ -734,6 +769,20 @@ class SondeScanner(object):
return self.sonde_scanner_running return self.sonde_scanner_running
def add_temporary_block(self, frequency):
""" Add a frequency to the temporary block list.
Args:
frequency (float): Frequency to be blocked, in Hz
"""
# Acquire a lock on the block list, so we don't accidentally modify it
# while it is being used in a scan.
self.temporary_block_list_lock.acquire()
self.temporary_block_list[frequency] = time.time()
self.temporary_block_list_lock.release()
self.log_info("Adding temporary block for frequency %.3f MHz." % (frequency/1e6))
def log_debug(self, line): def log_debug(self, line):
""" Helper function to log a debug message with a descriptive heading. """ Helper function to log a debug message with a descriptive heading.
Args: Args:

Wyświetl plik

@ -335,6 +335,8 @@ detect_dwell_time = 5
scan_delay = 10 scan_delay = 10
# Quantize search results to x Hz steps. Useful as most sondes are on 10 kHz frequency steps. # Quantize search results to x Hz steps. Useful as most sondes are on 10 kHz frequency steps.
quantization = 10000 quantization = 10000
# Temporary Block Time (minutes) - How long to block encrypted or otherwise non-decodable sondes for.
temporary_block_time = 60
# Upload when (seconds_since_utc_epoch%upload_rate) == 0. Otherwise just delay upload_rate seconds between uploads. # Upload when (seconds_since_utc_epoch%upload_rate) == 0. Otherwise just delay upload_rate seconds between uploads.
# Setting this to True with multple uploaders should give a higher chance of all uploaders uploading the same frame, # Setting this to True with multple uploaders should give a higher chance of all uploaders uploading the same frame,
# however the upload_rate should not be set too low, else there may be a chance of missing upload slots. # however the upload_rate should not be set too low, else there may be a chance of missing upload slots.

Wyświetl plik

@ -82,8 +82,7 @@ typedef struct {
int wday; int wday;
int std; int min; float sek; int std; int min; float sek;
double lat; double lon; double alt; double lat; double lon; double alt;
double vN; double vE; double vU; double vH; double vD; double vV;
double vH; double vD; double vD2;
float T; float RH; float T; float RH;
ui32_t crc; ui32_t crc;
ui8_t frame[FRAME_LEN]; ui8_t frame[FRAME_LEN];
@ -96,12 +95,12 @@ typedef struct {
float ptu_co2[3]; // { -243.911 , 0.187654 , 8.2e-06 } float ptu_co2[3]; // { -243.911 , 0.187654 , 8.2e-06 }
float ptu_calT2[3]; // calibration T2-Hum float ptu_calT2[3]; // calibration T2-Hum
float ptu_calH[2]; // calibration Hum float ptu_calH[2]; // calibration Hum
ui32_t freq; // freq/kHz
ui16_t conf_fw; // firmware ui16_t conf_fw; // firmware
ui8_t conf_cd; // kill countdown (sec) (kt or bt)
ui16_t conf_kt; // kill timer (sec) ui16_t conf_kt; // kill timer (sec)
ui16_t conf_bt; // burst timer (sec) ui16_t conf_bt; // burst timer (sec)
ui8_t conf_bk; // burst kill ui8_t conf_bk; // burst kill
ui32_t freq; // freq/kHz ui8_t conf_cd; // kill countdown (sec) (kt or bt)
char rstyp[9]; // RS41-SG, RS41-SGP char rstyp[9]; // RS41-SG, RS41-SGP
int aux; int aux;
char xdata[XDATA_LEN+16]; // xdata: aux_str1#aux_str2 ... char xdata[XDATA_LEN+16]; // xdata: aux_str1#aux_str2 ...
@ -248,6 +247,7 @@ static int crc16(gpx_t *gpx, int start, int len) {
static int check_CRC(gpx_t *gpx, ui32_t pos, ui32_t pck) { static int check_CRC(gpx_t *gpx, ui32_t pos, ui32_t pck) {
ui32_t crclen = 0, ui32_t crclen = 0,
crcdat = 0; crcdat = 0;
// check only pck_type (variable len pcks 0x76, 0x7E)
if (((pck>>8) & 0xFF) != gpx->frame[pos]) return -1; if (((pck>>8) & 0xFF) != gpx->frame[pos]) return -1;
crclen = gpx->frame[pos+1]; crclen = gpx->frame[pos+1];
if (pos + crclen + 4 > FRAME_LEN) return -1; if (pos + crclen + 4 > FRAME_LEN) return -1;
@ -273,62 +273,62 @@ GPS chip: ublox UBX-G6010-ST
0x12B: 7Exx AUX-xdata 0x12B: 7Exx AUX-xdata
*/ */
#define crc_FRAME (1<<0) #define crc_FRAME (1<<0)
#define xor_FRAME 0x1713 // ^0x6E3B=0x7928 #define xor_FRAME 0x1713 // ^0x6E3B=0x7928
#define pck_FRAME 0x7928 #define pck_FRAME 0x7928
#define pos_FRAME 0x039 #define pos_FRAME 0x039
#define pos_FrameNb 0x03B // 2 byte #define pos_FrameNb 0x03B // 2 byte
#define pos_SondeID 0x03D // 8 byte #define pos_SondeID 0x03D // 8 byte
#define pos_CalData 0x052 // 1 byte, counter 0x00..0x32 #define pos_CalData 0x052 // 1 byte, counter 0x00..0x32
#define pos_Calfreq 0x055 // 2 byte, calfr 0x00 #define pos_Calfreq 0x055 // 2 byte, calfr 0x00
#define pos_Calburst 0x05E // 1 byte, calfr 0x02 #define pos_Calburst 0x05E // 1 byte, calfr 0x02
// ? #define pos_Caltimer 0x05A // 2 byte, calfr 0x02 ? // ? #define pos_Caltimer 0x05A // 2 byte, calfr 0x02 ?
#define pos_CalRSTyp 0x05B // 8 byte, calfr 0x21 (+2 byte in 0x22?) #define pos_CalRSTyp 0x05B // 8 byte, calfr 0x21 (+2 byte in 0x22?)
// weitere chars in calfr 0x22/0x23; weitere ID // weitere chars in calfr 0x22/0x23; weitere ID
#define crc_PTU (1<<1) #define crc_PTU (1<<1)
#define xor_PTU 0xE388 // ^0x99A2=0x0x7A2A #define xor_PTU 0xE388 // ^0x99A2=0x0x7A2A
#define pck_PTU 0x7A2A // PTU #define pck_PTU 0x7A2A // PTU
#define pos_PTU 0x065 #define pos_PTU 0x065
#define crc_GPS1 (1<<2) #define crc_GPS1 (1<<2)
#define xor_GPS1 0x9667 // ^0xEA79=0x7C1E #define xor_GPS1 0x9667 // ^0xEA79=0x7C1E
#define pck_GPS1 0x7C1E // RXM-RAW (0x02 0x10) #define pck_GPS1 0x7C1E // RXM-RAW (0x02 0x10)
#define pos_GPS1 0x093 #define pos_GPS1 0x093
#define pos_GPSweek 0x095 // 2 byte #define pos_GPSweek 0x095 // 2 byte
#define pos_GPSiTOW 0x097 // 4 byte #define pos_GPSiTOW 0x097 // 4 byte
#define pos_satsN 0x09B // 12x2 byte (1: SV, 1: quality,strength) #define pos_satsN 0x09B // 12x2 byte (1: SV, 1: quality,strength)
#define crc_GPS2 (1<<3) #define crc_GPS2 (1<<3)
#define xor_GPS2 0xD7AD // ^0xAAF4=0x7D59 #define xor_GPS2 0xD7AD // ^0xAAF4=0x7D59
#define pck_GPS2 0x7D59 // RXM-RAW (0x02 0x10) #define pck_GPS2 0x7D59 // RXM-RAW (0x02 0x10)
#define pos_GPS2 0x0B5 #define pos_GPS2 0x0B5
#define pos_minPR 0x0B7 // 4 byte #define pos_minPR 0x0B7 // 4 byte
#define pos_FF 0x0BB // 1 byte #define pos_FF 0x0BB // 1 byte
#define pos_dataSats 0x0BC // 12x(4+3) byte (4: pseudorange, 3: doppler) #define pos_dataSats 0x0BC // 12x(4+3) byte (4: pseudorange, 3: doppler)
#define crc_GPS3 (1<<4) #define crc_GPS3 (1<<4)
#define xor_GPS3 0xB9FF // ^0xC2EA=0x7B15 #define xor_GPS3 0xB9FF // ^0xC2EA=0x7B15
#define pck_GPS3 0x7B15 // NAV-SOL (0x01 0x06) #define pck_GPS3 0x7B15 // NAV-SOL (0x01 0x06)
#define pos_GPS3 0x112 #define pos_GPS3 0x112
#define pos_GPSecefX 0x114 // 4 byte #define pos_GPSecefX 0x114 // 4 byte
#define pos_GPSecefY 0x118 // 4 byte #define pos_GPSecefY 0x118 // 4 byte
#define pos_GPSecefZ 0x11C // 4 byte #define pos_GPSecefZ 0x11C // 4 byte
#define pos_GPSecefV 0x120 // 3*2 byte #define pos_GPSecefV 0x120 // 3*2 byte
#define pos_numSats 0x126 // 1 byte #define pos_numSats 0x126 // 1 byte
#define pos_sAcc 0x127 // 1 byte #define pos_sAcc 0x127 // 1 byte
#define pos_pDOP 0x128 // 1 byte #define pos_pDOP 0x128 // 1 byte
#define crc_AUX (1<<5) #define crc_AUX (1<<5)
#define pck_AUX 0x7E00 // LEN variable #define pck_AUX 0x7E00 // LEN variable
#define pos_AUX 0x12B #define pos_AUX 0x12B
#define crc_ZERO (1<<6) // LEN variable #define crc_ZERO (1<<6) // LEN variable
#define pck_ZERO 0x7600 #define pck_ZERO 0x7600
#define pck_ZEROstd 0x7611 // NDATA std-frm, no aux #define pck_ZEROstd 0x7611 // NDATA std-frm, no aux
#define pos_ZEROstd 0x12B // pos_AUX(0) #define pos_ZEROstd 0x12B // pos_AUX(0)
#define pck_ENCRYPTED 0x80 // Packet type for an Encrypted payload #define pck_ENCRYPTED 0x8000 // Packet type for an Encrypted payload
/* /*
frame[pos_FRAME-1] == 0x0F: len == NDATA_LEN(320) frame[pos_FRAME-1] == 0x0F: len == NDATA_LEN(320)
@ -344,72 +344,6 @@ static int frametype(gpx_t *gpx) { // -4..+4: 0xF0 -> -4 , 0x0F -> +4
return ft; return ft;
} }
const double c = 299.792458e6;
const double L1 = 1575.42e6;
static int get_SatData(gpx_t *gpx) {
int i, n;
int sv;
ui32_t minPR;
int numSV;
double pDOP, sAcc;
fprintf(stdout, "[%d]\n", u2(gpx->frame+pos_FrameNb));
fprintf(stdout, "iTOW: 0x%08X", u4(gpx->frame+pos_GPSiTOW));
fprintf(stdout, " week: 0x%04X", u2(gpx->frame+pos_GPSweek));
fprintf(stdout, "\n");
minPR = u4(gpx->frame+pos_minPR);
fprintf(stdout, "minPR: %d", minPR);
fprintf(stdout, "\n");
for (i = 0; i < 12; i++) {
n = i*7;
sv = gpx->frame[pos_satsN+2*i];
if (sv == 0xFF) break;
fprintf(stdout, " SV: %2d ", sv);
//fprintf(stdout, " (%02x) ", gpx->frame[pos_satsN+2*i+1]);
fprintf(stdout, "# ");
fprintf(stdout, "prMes: %.1f", u4(gpx->frame+pos_dataSats+n)/100.0 + minPR);
fprintf(stdout, " ");
fprintf(stdout, "doMes: %.1f", -i3(gpx->frame+pos_dataSats+n+4)/100.0*L1/c);
fprintf(stdout, "\n");
}
fprintf(stdout, "ECEF-POS: (%d,%d,%d)\n",
(i32_t)u4(gpx->frame+pos_GPSecefX),
(i32_t)u4(gpx->frame+pos_GPSecefY),
(i32_t)u4(gpx->frame+pos_GPSecefZ));
fprintf(stdout, "ECEF-VEL: (%d,%d,%d)\n",
(i16_t)u2(gpx->frame+pos_GPSecefV+0),
(i16_t)u2(gpx->frame+pos_GPSecefV+2),
(i16_t)u2(gpx->frame+pos_GPSecefV+4));
numSV = gpx->frame[pos_numSats];
sAcc = gpx->frame[pos_sAcc]/10.0; if (gpx->frame[pos_sAcc] == 0xFF) sAcc = -1.0;
pDOP = gpx->frame[pos_pDOP]/10.0; if (gpx->frame[pos_pDOP] == 0xFF) pDOP = -1.0;
fprintf(stdout, "numSatsFix: %2d sAcc: %.1f pDOP: %.1f\n", numSV, sAcc, pDOP);
fprintf(stdout, "CRC: ");
fprintf(stdout, " %04X", pck_GPS1);
if (check_CRC(gpx, pos_GPS1, pck_GPS1)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS1, pck_GPS1));
fprintf(stdout, " %04X", pck_GPS2);
if (check_CRC(gpx, pos_GPS2, pck_GPS2)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS2, pck_GPS2));
fprintf(stdout, " %04X", pck_GPS3);
if (check_CRC(gpx, pos_GPS3, pck_GPS3)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS3, pck_GPS3));
fprintf(stdout, "\n");
fprintf(stdout, "\n");
return 0;
}
static int get_FrameNb(gpx_t *gpx) { static int get_FrameNb(gpx_t *gpx) {
int i; int i;
unsigned byte; unsigned byte;
@ -442,16 +376,20 @@ static int get_SondeID(gpx_t *gpx, int crc) {
if ( strncmp(gpx->id, sondeid_bytes, 8) != 0 ) { if ( strncmp(gpx->id, sondeid_bytes, 8) != 0 ) {
//for (i = 0; i < 51; i++) gpx->calfrchk[i] = 0; //for (i = 0; i < 51; i++) gpx->calfrchk[i] = 0;
memset(gpx->calfrchk, 0, 51); memset(gpx->calfrchk, 0, 51);
memcpy(gpx->id, sondeid_bytes, 8); // reset conf data
gpx->id[8] = '\0'; memset(gpx->rstyp, 0, 9);
// conf data gpx->freq = 0;
gpx->conf_fw = 0; gpx->conf_fw = 0;
gpx->conf_cd = -1;
gpx->conf_kt = -1;
gpx->conf_bt = 0; gpx->conf_bt = 0;
gpx->conf_bk = 0; gpx->conf_bk = 0;
gpx->freq = 0; gpx->conf_cd = -1;
memset(gpx->rstyp, 0, 9); gpx->conf_kt = -1;
// don't reset gpx->frame[] !
// gpx->T = -273.15;
// gpx->RH = -1.0;
// new ID:
memcpy(gpx->id, sondeid_bytes, 8);
gpx->id[8] = '\0';
} }
} }
@ -467,8 +405,8 @@ static int get_FrameConf(gpx_t *gpx) {
if (crc) gpx->crc |= crc_FRAME; if (crc) gpx->crc |= crc_FRAME;
err = crc; err = crc;
err |= get_FrameNb(gpx);
err |= get_SondeID(gpx, crc); err |= get_SondeID(gpx, crc);
err |= get_FrameNb(gpx);
if (crc == 0) { if (crc == 0) {
calfr = gpx->frame[pos_CalData]; calfr = gpx->frame[pos_CalData];
@ -636,10 +574,10 @@ static int get_PTU(gpx_t *gpx) {
printf(" Tc:%.2f ", Tc); printf(" Tc:%.2f ", Tc);
printf(" RH:%.1f ", RH); printf(" RH:%.1f ", RH);
printf(" TH:%.2f ", TH); printf(" TH:%.2f ", TH);
} }
printf("\n"); printf("\n");
if (gpx->alt > -400.0) //if (gpx->alt > -400.0)
{ {
printf(" %9.2f ; %6.1f ; %6.1f ", gpx->alt, gpx->ptu_Rf1, gpx->ptu_Rf2); printf(" %9.2f ; %6.1f ; %6.1f ", gpx->alt, gpx->ptu_Rf1, gpx->ptu_Rf2);
printf("; %10.6f ; %10.6f ; %10.6f ", gpx->ptu_calT1[0], gpx->ptu_calT1[1], gpx->ptu_calT1[2]); printf("; %10.6f ; %10.6f ; %10.6f ", gpx->ptu_calT1[0], gpx->ptu_calT1[1], gpx->ptu_calT1[2]);
@ -657,6 +595,82 @@ static int get_PTU(gpx_t *gpx) {
return err; return err;
} }
const double c = 299.792458e6;
const double L1 = 1575.42e6;
static int get_SatData(gpx_t *gpx) {
int i, n;
int sv;
ui32_t minPR;
int numSV;
double pDOP, sAcc;
int err = 0;
if ( ((gpx->frame[pos_GPS1]<<8) | gpx->frame[pos_GPS1+1]) != pck_GPS1 ) return -1;
if ( ((gpx->frame[pos_GPS2]<<8) | gpx->frame[pos_GPS2+1]) != pck_GPS2 ) return -2;
if ( ((gpx->frame[pos_GPS3]<<8) | gpx->frame[pos_GPS3+1]) != pck_GPS3 ) return -3;
err = get_FrameConf(gpx);
if (!err) {
fprintf(stdout, "[%5d] ", gpx->frnr);
fprintf(stdout, "(%s) ", gpx->id);
fprintf(stdout, "\n");
}
fprintf(stdout, "iTOW: 0x%08X", u4(gpx->frame+pos_GPSiTOW));
fprintf(stdout, " week: 0x%04X", u2(gpx->frame+pos_GPSweek));
fprintf(stdout, "\n");
minPR = u4(gpx->frame+pos_minPR);
fprintf(stdout, "minPR: %d", minPR);
fprintf(stdout, "\n");
for (i = 0; i < 12; i++) {
n = i*7;
sv = gpx->frame[pos_satsN+2*i];
if (sv == 0xFF) break;
fprintf(stdout, " SV: %2d ", sv);
//fprintf(stdout, " (%02x) ", gpx->frame[pos_satsN+2*i+1]);
fprintf(stdout, "# ");
fprintf(stdout, "prMes: %.1f", u4(gpx->frame+pos_dataSats+n)/100.0 + minPR);
fprintf(stdout, " ");
fprintf(stdout, "doMes: %.1f", -i3(gpx->frame+pos_dataSats+n+4)/100.0*L1/c);
fprintf(stdout, "\n");
}
fprintf(stdout, "ECEF-POS: (%d,%d,%d)\n",
(i32_t)u4(gpx->frame+pos_GPSecefX),
(i32_t)u4(gpx->frame+pos_GPSecefY),
(i32_t)u4(gpx->frame+pos_GPSecefZ));
fprintf(stdout, "ECEF-VEL: (%d,%d,%d)\n",
(i16_t)u2(gpx->frame+pos_GPSecefV+0),
(i16_t)u2(gpx->frame+pos_GPSecefV+2),
(i16_t)u2(gpx->frame+pos_GPSecefV+4));
numSV = gpx->frame[pos_numSats];
sAcc = gpx->frame[pos_sAcc]/10.0; if (gpx->frame[pos_sAcc] == 0xFF) sAcc = -1.0;
pDOP = gpx->frame[pos_pDOP]/10.0; if (gpx->frame[pos_pDOP] == 0xFF) pDOP = -1.0;
fprintf(stdout, "numSatsFix: %2d sAcc: %.1f pDOP: %.1f\n", numSV, sAcc, pDOP);
fprintf(stdout, "CRC: ");
fprintf(stdout, " %04X", pck_GPS1);
if (check_CRC(gpx, pos_GPS1, pck_GPS1)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS1, pck_GPS1));
fprintf(stdout, " %04X", pck_GPS2);
if (check_CRC(gpx, pos_GPS2, pck_GPS2)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS2, pck_GPS2));
fprintf(stdout, " %04X", pck_GPS3);
if (check_CRC(gpx, pos_GPS3, pck_GPS3)==0) fprintf(stdout, "[OK]"); else fprintf(stdout, "[NO]");
//fprintf(stdout, "[%+d]", check_CRC(gpx, pos_GPS3, pck_GPS3));
fprintf(stdout, "\n");
fprintf(stdout, "\n");
return 0;
}
static int get_GPSweek(gpx_t *gpx) { static int get_GPSweek(gpx_t *gpx) {
int i; int i;
unsigned byte; unsigned byte;
@ -714,15 +728,16 @@ static int get_GPStime(gpx_t *gpx) {
static int get_GPS1(gpx_t *gpx) { static int get_GPS1(gpx_t *gpx) {
int err=0; int err=0;
// ((gpx->frame[pos_GPS1]<<8) | gpx->frame[pos_GPS1+1]) != pck_GPS1 ? // gpx->frame[pos_GPS1+1] != (pck_GPS1 & 0xFF) ?
if ( gpx->frame[pos_GPS1] != ((pck_GPS1>>8) & 0xFF) ) { err = check_CRC(gpx, pos_GPS1, pck_GPS1);
if (err) {
gpx->crc |= crc_GPS1; gpx->crc |= crc_GPS1;
// reset GPS1-data (json)
gpx->jahr = 0; gpx->monat = 0; gpx->tag = 0;
gpx->std = 0; gpx->min = 0; gpx->sek = 0.0;
return -1; return -1;
} }
err = check_CRC(gpx, pos_GPS1, pck_GPS1);
if (err) gpx->crc |= crc_GPS1;
err |= get_GPSweek(gpx); // no plausibility-check err |= get_GPSweek(gpx); // no plausibility-check
err |= get_GPStime(gpx); // no plausibility-check err |= get_GPStime(gpx); // no plausibility-check
@ -732,6 +747,7 @@ static int get_GPS1(gpx_t *gpx) {
static int get_GPS2(gpx_t *gpx) { static int get_GPS2(gpx_t *gpx) {
int err=0; int err=0;
// gpx->frame[pos_GPS2+1] != (pck_GPS2 & 0xFF) ?
err = check_CRC(gpx, pos_GPS2, pck_GPS2); err = check_CRC(gpx, pos_GPS2, pck_GPS2);
if (err) gpx->crc |= crc_GPS2; if (err) gpx->crc |= crc_GPS2;
@ -775,7 +791,9 @@ static int get_GPSkoord(gpx_t *gpx) {
double X[3], lat, lon, alt; double X[3], lat, lon, alt;
ui8_t gpsVel_bytes[2]; ui8_t gpsVel_bytes[2];
short vel16; // 16bit short vel16; // 16bit
double V[3], phi, lam, dir; double V[3];
double phi, lam, dir;
double vN; double vE; double vU;
for (k = 0; k < 3; k++) { for (k = 0; k < 3; k++) {
@ -809,12 +827,12 @@ static int get_GPSkoord(gpx_t *gpx) {
// ECEF-Vel -> NorthEastUp // ECEF-Vel -> NorthEastUp
phi = lat*M_PI/180.0; phi = lat*M_PI/180.0;
lam = lon*M_PI/180.0; lam = lon*M_PI/180.0;
gpx->vN = -V[0]*sin(phi)*cos(lam) - V[1]*sin(phi)*sin(lam) + V[2]*cos(phi); vN = -V[0]*sin(phi)*cos(lam) - V[1]*sin(phi)*sin(lam) + V[2]*cos(phi);
gpx->vE = -V[0]*sin(lam) + V[1]*cos(lam); vE = -V[0]*sin(lam) + V[1]*cos(lam);
gpx->vU = V[0]*cos(phi)*cos(lam) + V[1]*cos(phi)*sin(lam) + V[2]*sin(phi); vU = V[0]*cos(phi)*cos(lam) + V[1]*cos(phi)*sin(lam) + V[2]*sin(phi);
// NEU -> HorDirVer // NEU -> HorDirVer
gpx->vH = sqrt(gpx->vN*gpx->vN+gpx->vE*gpx->vE); gpx->vH = sqrt(vN*vN+vE*vE);
/* /*
double alpha; double alpha;
alpha = atan2(gpx->vN, gpx->vE)*180/M_PI; // ComplexPlane (von x-Achse nach links) - GeoMeteo (von y-Achse nach rechts) alpha = atan2(gpx->vN, gpx->vE)*180/M_PI; // ComplexPlane (von x-Achse nach links) - GeoMeteo (von y-Achse nach rechts)
@ -822,10 +840,12 @@ static int get_GPSkoord(gpx_t *gpx) {
if (dir < 0) dir += 360; // atan2(y,x)=atan(y/x)=pi/2-atan(x/y) , atan(1/t) = pi/2 - atan(t) if (dir < 0) dir += 360; // atan2(y,x)=atan(y/x)=pi/2-atan(x/y) , atan(1/t) = pi/2 - atan(t)
gpx->vD2 = dir; gpx->vD2 = dir;
*/ */
dir = atan2(gpx->vE, gpx->vN) * 180 / M_PI; dir = atan2(vE, vN) * 180 / M_PI;
if (dir < 0) dir += 360; if (dir < 0) dir += 360;
gpx->vD = dir; gpx->vD = dir;
gpx->vV = vU;
gpx->numSV = gpx->frame[pos_numSats]; gpx->numSV = gpx->frame[pos_numSats];
return 0; return 0;
@ -834,15 +854,17 @@ static int get_GPSkoord(gpx_t *gpx) {
static int get_GPS3(gpx_t *gpx) { static int get_GPS3(gpx_t *gpx) {
int err=0; int err=0;
// ((gpx->frame[pos_GPS3]<<8) | gpx->frame[pos_GPS3+1]) != pck_GPS3 ? // gpx->frame[pos_GPS3+1] != (pck_GPS3 & 0xFF) ?
if ( gpx->frame[pos_GPS3] != ((pck_GPS3>>8) & 0xFF) ) { err = check_CRC(gpx, pos_GPS3, pck_GPS3);
if (err) {
gpx->crc |= crc_GPS3; gpx->crc |= crc_GPS3;
// reset GPS3-data (json)
gpx->lat = 0.0; gpx->lon = 0.0; gpx->alt = 0.0;
gpx->vH = 0.0; gpx->vD = 0.0; gpx->vV = 0.0;
gpx->numSV = 0;
return -1; return -1;
} }
err = check_CRC(gpx, pos_GPS3, pck_GPS3);
if (err) gpx->crc |= crc_GPS3;
err |= get_GPSkoord(gpx); // plausibility-check: altitude, if ecef=(0,0,0) err |= get_GPSkoord(gpx); // plausibility-check: altitude, if ecef=(0,0,0)
return err; return err;
@ -891,7 +913,7 @@ static int get_Aux(gpx_t *gpx) {
} }
gpx->xdata[n] = '\0'; gpx->xdata[n] = '\0';
i = check_CRC(gpx, pos7E, 0x7600); // 0x76xx: 00-padding block i = check_CRC(gpx, pos7E, pck_ZERO); // 0x76xx: 00-padding block
if (i) gpx->crc |= crc_ZERO; if (i) gpx->crc |= crc_ZERO;
return count7E; return count7E;
@ -1080,20 +1102,20 @@ static int print_position(gpx_t *gpx, int ec) {
int i; int i;
int err, err0, err1, err2, err3; int err, err0, err1, err2, err3;
int output, out_mask; int output, out_mask;
int encrypted; int encrypted = 0;
gpx->out = 0; gpx->out = 0;
gpx->aux = 0; gpx->aux = 0;
err = get_FrameConf(gpx);
// Quick check for an encrypted packet (RS41-SGM) // Quick check for an encrypted packet (RS41-SGM)
// These sondes have a type 0x80 packet in place of the regular PTU packet. // These sondes have a type 0x80 packet in place of the regular PTU packet.
if (gpx->frame[pos_PTU] == pck_ENCRYPTED){ if (check_CRC(gpx, pos_PTU, pck_ENCRYPTED)==0) { // frame[pos_PTU] == pck_ENCRYPTED>>8
encrypted = 1; encrypted = 1; // and CRC-OK
// Continue with the rest of the extraction (which will result in null data) // Continue with the rest of the extraction
} }
err = get_FrameConf(gpx);
err1 = get_GPS1(gpx); err1 = get_GPS1(gpx);
err2 = get_GPS2(gpx); err2 = get_GPS2(gpx);
err3 = get_GPS3(gpx); err3 = get_GPS3(gpx);
@ -1113,8 +1135,8 @@ static int print_position(gpx_t *gpx, int ec) {
fprintf(stdout, "[%5d] ", gpx->frnr); fprintf(stdout, "[%5d] ", gpx->frnr);
fprintf(stdout, "(%s) ", gpx->id); fprintf(stdout, "(%s) ", gpx->id);
} }
if (encrypted) { if (encrypted) { // e.g. 0x80A7-pck
fprintf(stdout, " Encrypted payload (RS41-SGM) "); fprintf(stdout, " (RS41-SGM: %02X%02X) ", gpx->frame[pos_PTU], gpx->frame[pos_PTU+1]);
} }
if (!err1) { if (!err1) {
Gps2Date(gpx); Gps2Date(gpx);
@ -1131,7 +1153,7 @@ static int print_position(gpx_t *gpx, int ec) {
//if (gpx->option.vbs) //if (gpx->option.vbs)
{ {
//fprintf(stdout, " (%.1f %.1f %.1f) ", gpx->vN, gpx->vE, gpx->vU); //fprintf(stdout, " (%.1f %.1f %.1f) ", gpx->vN, gpx->vE, gpx->vU);
fprintf(stdout," vH: %4.1f D: %5.1f vV: %3.1f ", gpx->vH, gpx->vD, gpx->vU); fprintf(stdout," vH: %4.1f D: %5.1f vV: %3.1f ", gpx->vH, gpx->vD, gpx->vV);
if (gpx->option.vbs == 3) fprintf(stdout," sats: %02d ", gpx->numSV); if (gpx->option.vbs == 3) fprintf(stdout," sats: %02d ", gpx->numSV);
} }
} }
@ -1149,9 +1171,9 @@ static int print_position(gpx_t *gpx, int ec) {
int flen = NDATA_LEN; int flen = NDATA_LEN;
if (frametype(gpx) < 0) flen += XDATA_LEN; if (frametype(gpx) < 0) flen += XDATA_LEN;
pos = pos_FRAME; pos = pos_FRAME;
while (pos < flen-1) { while (pos < flen-1) { // e.g.
blk = gpx->frame[pos]; // 0x80XX: encrypted block blk = gpx->frame[pos]; // 0x80xx: encrypted block
len = gpx->frame[pos+1]; // 0x76XX: 00-padding block len = gpx->frame[pos+1]; // 0x76xx: 00-padding block
crc = check_CRC(gpx, pos, blk<<8); crc = check_CRC(gpx, pos, blk<<8);
fprintf(stdout, " %02X%02X", gpx->frame[pos], gpx->frame[pos+1]); fprintf(stdout, " %02X%02X", gpx->frame[pos], gpx->frame[pos+1]);
fprintf(stdout, "[%d]", crc&1); fprintf(stdout, "[%d]", crc&1);
@ -1188,7 +1210,7 @@ static int print_position(gpx_t *gpx, int ec) {
if ((!err && !err1 && !err3) || (!err && encrypted)) { // frame-nb/id && gps-time && gps-position (crc-)ok; 3 CRCs, RS not needed if ((!err && !err1 && !err3) || (!err && encrypted)) { // frame-nb/id && gps-time && gps-position (crc-)ok; 3 CRCs, RS not needed
// eigentlich GPS, d.h. UTC = GPS - 18sec (ab 1.1.2017) // eigentlich GPS, d.h. UTC = GPS - 18sec (ab 1.1.2017)
fprintf(stdout, "{ \"frame\": %d, \"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f, \"sats\": %d", fprintf(stdout, "{ \"frame\": %d, \"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f, \"sats\": %d",
gpx->frnr, gpx->id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vU, gpx->numSV); gpx->frnr, gpx->id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV, gpx->numSV );
if (gpx->option.ptu && !err0 && gpx->T > -273.0) { if (gpx->option.ptu && !err0 && gpx->T > -273.0) {
fprintf(stdout, ", \"temp\": %.1f", gpx->T ); fprintf(stdout, ", \"temp\": %.1f", gpx->T );
} }
@ -1199,7 +1221,7 @@ static int print_position(gpx_t *gpx, int ec) {
fprintf(stdout, ", \"aux\": \"%s\"", gpx->xdata ); fprintf(stdout, ", \"aux\": \"%s\"", gpx->xdata );
} }
if (encrypted){ if (encrypted){
printf(",\"encrypted\": true"); printf(", \"encrypted\": true");
} }
fprintf(stdout, " }\n"); fprintf(stdout, " }\n");
fprintf(stdout, "\n"); fprintf(stdout, "\n");