diff --git a/auto_rx/auto_rx.py b/auto_rx/auto_rx.py index 463f315..1b44659 100644 --- a/auto_rx/auto_rx.py +++ b/auto_rx/auto_rx.py @@ -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. +# Temporary frequency block list +# This contains frequncies that should be blocked for a short amount of time. +temporary_block_list = {} + # Scan Result Queue # 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(): """ 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: # Already a scanner running! Return. @@ -136,7 +140,9 @@ def start_scanner(): gain = autorx.sdr_list[_device_idx]['gain'], ppm = autorx.sdr_list[_device_idx]['ppm'], 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 @@ -174,7 +180,19 @@ def start_decoder(freq, sonde_type): 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. _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. if (_check_type not in VALID_SONDE_TYPES): logging.error("Unsupported sonde type: %s" % _check_type) + # TODO - Potentially add the frequency of the unsupported sonde to the temporary block list? continue if allocate_sdr(check_only=True) is not None : @@ -277,19 +296,40 @@ def clean_task_list(): try: _running = autorx.task_list[_key]['task'].running() _task_sdr = autorx.task_list[_key]['device_idx'] + _exit_state = autorx.task_list[_key]['task'].exit_state except Exception as e: logging.error("Task Manager - Error getting task %s state - %s" % (str(_key),str(e))) continue 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]['task'] = None + # Pop the task from the task list. autorx.task_list.pop(_key) # Indicate to the web client that the task list has been updated. 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. 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. diff --git a/auto_rx/autorx/__init__.py b/auto_rx/autorx/__init__.py index 39c877d..9d20649 100644 --- a/auto_rx/autorx/__init__.py +++ b/auto_rx/autorx/__init__.py @@ -11,7 +11,7 @@ # 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. -__version__ = "1.1.1-experimental" +__version__ = "1.1.2-experimental" # Global Variables diff --git a/auto_rx/autorx/config.py b/auto_rx/autorx/config.py index e8ace63..8e20c4c 100644 --- a/auto_rx/autorx/config.py +++ b/auto_rx/autorx/config.py @@ -100,7 +100,8 @@ def read_auto_rx_config(filename): 'scan_dwell_time' : 20, 'detect_dwell_time' : 5, 'scan_delay' : 10, - 'payload_id_valid' : 5, + 'payload_id_valid' : 5, + 'temporary_block_time' : 60, # Rotator Settings 'enable_rotator': False, 'rotator_update_rate': 30, @@ -245,6 +246,12 @@ def read_auto_rx_config(filename): except: 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. auto_rx_config['sdr_settings'] = {} diff --git a/auto_rx/autorx/decode.py b/auto_rx/autorx/decode.py index e0bccfc..99e5989 100644 --- a/auto_rx/autorx/decode.py +++ b/auto_rx/autorx/decode.py @@ -142,6 +142,8 @@ class SondeDecoder(object): # This will become our decoder thread. self.decoder = None + self.exit_state = "OK" + # Detect if we have an 'inverted' sonde. if self.sonde_type.startswith('-'): self.inverted = True @@ -407,6 +409,7 @@ class SondeDecoder(object): if time.time() > (_last_packet + self.timeout): # If we have not seen data for a while, break. self.log_error("RX Timed out.") + self.exit_state = "Timeout" break else: # Otherwise, sleep for a short time. @@ -486,9 +489,12 @@ class SondeDecoder(object): if _field not in _telemetry: _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.) if 'encrypted' in _telemetry: 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 return False diff --git a/auto_rx/autorx/scan.py b/auto_rx/autorx/scan.py index d945531..7ad5f0e 100644 --- a/auto_rx/autorx/scan.py +++ b/auto_rx/autorx/scan.py @@ -13,7 +13,7 @@ import platform import subprocess import time import traceback -from threading import Thread +from threading import Thread, Lock from types import FunctionType, MethodType from .utils import detect_peaks, rtlsdr_test, reset_rtlsdr_by_serial, reset_all_rtlsdrs, peak_decimation try: @@ -358,7 +358,9 @@ class SondeScanner(object): gain = -1, ppm = 0, bias = False, - save_detection_audio = False): + save_detection_audio = False, + temporary_block_list = {}, + temporary_block_time = 60): """ Initialise a Sonde Scanner Object. 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. bias (bool): If True, enable the bias tee on the SDR. save_detection_audio (bool): Save the audio used in each detecton to detect_.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. @@ -420,6 +424,14 @@ class SondeScanner(object): self.callback = callback 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. self.error_retries = 0 @@ -439,8 +451,11 @@ class SondeScanner(object): if not _rtlsdr_ok: self.log_error("RTLSDR #%s non-functional - exiting." % device_idx) self.sonde_scanner_running = False + self.exit_state = "Failed SDR" return + self.exit_state = "OK" + if auto_start: self.start() @@ -611,6 +626,7 @@ class SondeScanner(object): _, peak_idx = np.unique(peak_frequencies, return_index=True) peak_frequencies = peak_frequencies[np.sort(peak_idx)] + # Remove any frequencies in the blacklist. for _frequency in np.array(self.blacklist)*1e6: _index = np.argwhere(peak_frequencies==_frequency) @@ -623,6 +639,25 @@ class SondeScanner(object): # Append on any frequencies in the supplied greylist 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. # This is actually a bit of a pain to do... _peak_freq = [] @@ -734,6 +769,20 @@ class SondeScanner(object): 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): """ Helper function to log a debug message with a descriptive heading. Args: diff --git a/auto_rx/station.cfg.example b/auto_rx/station.cfg.example index 4f4eaf6..42f2b5e 100644 --- a/auto_rx/station.cfg.example +++ b/auto_rx/station.cfg.example @@ -335,6 +335,8 @@ detect_dwell_time = 5 scan_delay = 10 # Quantize search results to x Hz steps. Useful as most sondes are on 10 kHz frequency steps. 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. # 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. diff --git a/demod/mod/rs41mod.c b/demod/mod/rs41mod.c index e206a4c..a480a04 100644 --- a/demod/mod/rs41mod.c +++ b/demod/mod/rs41mod.c @@ -82,8 +82,7 @@ typedef struct { int wday; int std; int min; float sek; double lat; double lon; double alt; - double vN; double vE; double vU; - double vH; double vD; double vD2; + double vH; double vD; double vV; float T; float RH; ui32_t crc; ui8_t frame[FRAME_LEN]; @@ -96,12 +95,12 @@ typedef struct { float ptu_co2[3]; // { -243.911 , 0.187654 , 8.2e-06 } float ptu_calT2[3]; // calibration T2-Hum float ptu_calH[2]; // calibration Hum + ui32_t freq; // freq/kHz 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_bt; // burst timer (sec) 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 int aux; 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) { ui32_t crclen = 0, crcdat = 0; + // check only pck_type (variable len pcks 0x76, 0x7E) if (((pck>>8) & 0xFF) != gpx->frame[pos]) return -1; crclen = gpx->frame[pos+1]; if (pos + crclen + 4 > FRAME_LEN) return -1; @@ -273,62 +273,62 @@ GPS chip: ublox UBX-G6010-ST 0x12B: 7Exx AUX-xdata */ -#define crc_FRAME (1<<0) -#define xor_FRAME 0x1713 // ^0x6E3B=0x7928 -#define pck_FRAME 0x7928 -#define pos_FRAME 0x039 -#define pos_FrameNb 0x03B // 2 byte -#define pos_SondeID 0x03D // 8 byte -#define pos_CalData 0x052 // 1 byte, counter 0x00..0x32 -#define pos_Calfreq 0x055 // 2 byte, calfr 0x00 -#define pos_Calburst 0x05E // 1 byte, calfr 0x02 +#define crc_FRAME (1<<0) +#define xor_FRAME 0x1713 // ^0x6E3B=0x7928 +#define pck_FRAME 0x7928 +#define pos_FRAME 0x039 +#define pos_FrameNb 0x03B // 2 byte +#define pos_SondeID 0x03D // 8 byte +#define pos_CalData 0x052 // 1 byte, counter 0x00..0x32 +#define pos_Calfreq 0x055 // 2 byte, calfr 0x00 +#define pos_Calburst 0x05E // 1 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 -#define crc_PTU (1<<1) -#define xor_PTU 0xE388 // ^0x99A2=0x0x7A2A -#define pck_PTU 0x7A2A // PTU -#define pos_PTU 0x065 +#define crc_PTU (1<<1) +#define xor_PTU 0xE388 // ^0x99A2=0x0x7A2A +#define pck_PTU 0x7A2A // PTU +#define pos_PTU 0x065 -#define crc_GPS1 (1<<2) -#define xor_GPS1 0x9667 // ^0xEA79=0x7C1E -#define pck_GPS1 0x7C1E // RXM-RAW (0x02 0x10) -#define pos_GPS1 0x093 -#define pos_GPSweek 0x095 // 2 byte -#define pos_GPSiTOW 0x097 // 4 byte -#define pos_satsN 0x09B // 12x2 byte (1: SV, 1: quality,strength) +#define crc_GPS1 (1<<2) +#define xor_GPS1 0x9667 // ^0xEA79=0x7C1E +#define pck_GPS1 0x7C1E // RXM-RAW (0x02 0x10) +#define pos_GPS1 0x093 +#define pos_GPSweek 0x095 // 2 byte +#define pos_GPSiTOW 0x097 // 4 byte +#define pos_satsN 0x09B // 12x2 byte (1: SV, 1: quality,strength) -#define crc_GPS2 (1<<3) -#define xor_GPS2 0xD7AD // ^0xAAF4=0x7D59 -#define pck_GPS2 0x7D59 // RXM-RAW (0x02 0x10) -#define pos_GPS2 0x0B5 -#define pos_minPR 0x0B7 // 4 byte -#define pos_FF 0x0BB // 1 byte -#define pos_dataSats 0x0BC // 12x(4+3) byte (4: pseudorange, 3: doppler) +#define crc_GPS2 (1<<3) +#define xor_GPS2 0xD7AD // ^0xAAF4=0x7D59 +#define pck_GPS2 0x7D59 // RXM-RAW (0x02 0x10) +#define pos_GPS2 0x0B5 +#define pos_minPR 0x0B7 // 4 byte +#define pos_FF 0x0BB // 1 byte +#define pos_dataSats 0x0BC // 12x(4+3) byte (4: pseudorange, 3: doppler) -#define crc_GPS3 (1<<4) -#define xor_GPS3 0xB9FF // ^0xC2EA=0x7B15 -#define pck_GPS3 0x7B15 // NAV-SOL (0x01 0x06) -#define pos_GPS3 0x112 -#define pos_GPSecefX 0x114 // 4 byte -#define pos_GPSecefY 0x118 // 4 byte -#define pos_GPSecefZ 0x11C // 4 byte -#define pos_GPSecefV 0x120 // 3*2 byte -#define pos_numSats 0x126 // 1 byte -#define pos_sAcc 0x127 // 1 byte -#define pos_pDOP 0x128 // 1 byte +#define crc_GPS3 (1<<4) +#define xor_GPS3 0xB9FF // ^0xC2EA=0x7B15 +#define pck_GPS3 0x7B15 // NAV-SOL (0x01 0x06) +#define pos_GPS3 0x112 +#define pos_GPSecefX 0x114 // 4 byte +#define pos_GPSecefY 0x118 // 4 byte +#define pos_GPSecefZ 0x11C // 4 byte +#define pos_GPSecefV 0x120 // 3*2 byte +#define pos_numSats 0x126 // 1 byte +#define pos_sAcc 0x127 // 1 byte +#define pos_pDOP 0x128 // 1 byte -#define crc_AUX (1<<5) -#define pck_AUX 0x7E00 // LEN variable -#define pos_AUX 0x12B +#define crc_AUX (1<<5) +#define pck_AUX 0x7E00 // LEN variable +#define pos_AUX 0x12B -#define crc_ZERO (1<<6) // LEN variable -#define pck_ZERO 0x7600 -#define pck_ZEROstd 0x7611 // NDATA std-frm, no aux -#define pos_ZEROstd 0x12B // pos_AUX(0) +#define crc_ZERO (1<<6) // LEN variable +#define pck_ZERO 0x7600 +#define pck_ZEROstd 0x7611 // NDATA std-frm, no aux +#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) @@ -344,72 +344,6 @@ static int frametype(gpx_t *gpx) { // -4..+4: 0xF0 -> -4 , 0x0F -> +4 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) { int i; unsigned byte; @@ -442,16 +376,20 @@ static int get_SondeID(gpx_t *gpx, int crc) { if ( strncmp(gpx->id, sondeid_bytes, 8) != 0 ) { //for (i = 0; i < 51; i++) gpx->calfrchk[i] = 0; memset(gpx->calfrchk, 0, 51); - memcpy(gpx->id, sondeid_bytes, 8); - gpx->id[8] = '\0'; - // conf data + // reset conf data + memset(gpx->rstyp, 0, 9); + gpx->freq = 0; gpx->conf_fw = 0; - gpx->conf_cd = -1; - gpx->conf_kt = -1; gpx->conf_bt = 0; gpx->conf_bk = 0; - gpx->freq = 0; - memset(gpx->rstyp, 0, 9); + gpx->conf_cd = -1; + 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; err = crc; - err |= get_FrameNb(gpx); err |= get_SondeID(gpx, crc); + err |= get_FrameNb(gpx); if (crc == 0) { calfr = gpx->frame[pos_CalData]; @@ -636,10 +574,10 @@ static int get_PTU(gpx_t *gpx) { printf(" Tc:%.2f ", Tc); printf(" RH:%.1f ", RH); printf(" TH:%.2f ", TH); - } + } 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("; %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; } + +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) { int i; unsigned byte; @@ -714,15 +728,16 @@ static int get_GPStime(gpx_t *gpx) { static int get_GPS1(gpx_t *gpx) { int err=0; - // ((gpx->frame[pos_GPS1]<<8) | gpx->frame[pos_GPS1+1]) != pck_GPS1 ? - if ( gpx->frame[pos_GPS1] != ((pck_GPS1>>8) & 0xFF) ) { + // gpx->frame[pos_GPS1+1] != (pck_GPS1 & 0xFF) ? + err = check_CRC(gpx, pos_GPS1, pck_GPS1); + if (err) { 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; } - err = check_CRC(gpx, pos_GPS1, pck_GPS1); - if (err) gpx->crc |= crc_GPS1; - err |= get_GPSweek(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) { int err=0; + // gpx->frame[pos_GPS2+1] != (pck_GPS2 & 0xFF) ? err = check_CRC(gpx, pos_GPS2, pck_GPS2); if (err) gpx->crc |= crc_GPS2; @@ -775,7 +791,9 @@ static int get_GPSkoord(gpx_t *gpx) { double X[3], lat, lon, alt; ui8_t gpsVel_bytes[2]; 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++) { @@ -809,12 +827,12 @@ static int get_GPSkoord(gpx_t *gpx) { // ECEF-Vel -> NorthEastUp phi = lat*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); - gpx->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); + vN = -V[0]*sin(phi)*cos(lam) - V[1]*sin(phi)*sin(lam) + V[2]*cos(phi); + vE = -V[0]*sin(lam) + V[1]*cos(lam); + vU = V[0]*cos(phi)*cos(lam) + V[1]*cos(phi)*sin(lam) + V[2]*sin(phi); // NEU -> HorDirVer - gpx->vH = sqrt(gpx->vN*gpx->vN+gpx->vE*gpx->vE); + gpx->vH = sqrt(vN*vN+vE*vE); /* double alpha; 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) gpx->vD2 = dir; */ - dir = atan2(gpx->vE, gpx->vN) * 180 / M_PI; + dir = atan2(vE, vN) * 180 / M_PI; if (dir < 0) dir += 360; gpx->vD = dir; + gpx->vV = vU; + gpx->numSV = gpx->frame[pos_numSats]; return 0; @@ -834,15 +854,17 @@ static int get_GPSkoord(gpx_t *gpx) { static int get_GPS3(gpx_t *gpx) { int err=0; - // ((gpx->frame[pos_GPS3]<<8) | gpx->frame[pos_GPS3+1]) != pck_GPS3 ? - if ( gpx->frame[pos_GPS3] != ((pck_GPS3>>8) & 0xFF) ) { + // gpx->frame[pos_GPS3+1] != (pck_GPS3 & 0xFF) ? + err = check_CRC(gpx, pos_GPS3, pck_GPS3); + if (err) { 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; } - 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) return err; @@ -891,7 +913,7 @@ static int get_Aux(gpx_t *gpx) { } 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; return count7E; @@ -1080,20 +1102,20 @@ static int print_position(gpx_t *gpx, int ec) { int i; int err, err0, err1, err2, err3; int output, out_mask; - int encrypted; + int encrypted = 0; gpx->out = 0; gpx->aux = 0; - err = get_FrameConf(gpx); - // Quick check for an encrypted packet (RS41-SGM) // These sondes have a type 0x80 packet in place of the regular PTU packet. - if (gpx->frame[pos_PTU] == pck_ENCRYPTED){ - encrypted = 1; - // Continue with the rest of the extraction (which will result in null data) + if (check_CRC(gpx, pos_PTU, pck_ENCRYPTED)==0) { // frame[pos_PTU] == pck_ENCRYPTED>>8 + encrypted = 1; // and CRC-OK + // Continue with the rest of the extraction } + err = get_FrameConf(gpx); + err1 = get_GPS1(gpx); err2 = get_GPS2(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, "(%s) ", gpx->id); } - if (encrypted) { - fprintf(stdout, " Encrypted payload (RS41-SGM) "); + if (encrypted) { // e.g. 0x80A7-pck + fprintf(stdout, " (RS41-SGM: %02X%02X) ", gpx->frame[pos_PTU], gpx->frame[pos_PTU+1]); } if (!err1) { Gps2Date(gpx); @@ -1131,7 +1153,7 @@ static int print_position(gpx_t *gpx, int ec) { //if (gpx->option.vbs) { //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); } } @@ -1149,9 +1171,9 @@ static int print_position(gpx_t *gpx, int ec) { int flen = NDATA_LEN; if (frametype(gpx) < 0) flen += XDATA_LEN; pos = pos_FRAME; - while (pos < flen-1) { - blk = gpx->frame[pos]; // 0x80XX: encrypted block - len = gpx->frame[pos+1]; // 0x76XX: 00-padding block + while (pos < flen-1) { // e.g. + blk = gpx->frame[pos]; // 0x80xx: encrypted block + len = gpx->frame[pos+1]; // 0x76xx: 00-padding block crc = check_CRC(gpx, pos, blk<<8); fprintf(stdout, " %02X%02X", gpx->frame[pos], gpx->frame[pos+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 // 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", - 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) { 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 ); } if (encrypted){ - printf(",\"encrypted\": true"); + printf(", \"encrypted\": true"); } fprintf(stdout, " }\n"); fprintf(stdout, "\n");