diff --git a/README.md b/README.md index 1081fa51..cf2f5bea 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,18 @@ Auto-RX's [Web Interface](https://github.com/projecthorus/radiosonde_auto_rx/wik ### Radiosonde Support Matrix -Manufacturer | Model | Position | Temperature | Humidity | Pressure --------------|-------|----------|-------------|----------|---------- -Vaisala | RS92-SGP/NGP | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: -Vaisala | RS41-SG/SGP/SGM | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (for -SGP) -Graw | DFM06/09/17 | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: -Meteomodem | M10 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent -Meteomodem | M20 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (For some models) -Intermet Systems | iMet-4 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent -Intermet Systems | iMet-54 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent -Lockheed Martin | LMS6-400/1680 | :heavy_check_mark: | :x: | :x: | :x: -Meisei | iMS-100 | :heavy_check_mark: | :x: | :x: | :x: -Meteo-Radiy | MRZ-H1 (400 MHz) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: +Manufacturer | Model | Position | Temperature | Humidity | Pressure | XDATA +-------------|-------|----------|-------------|----------|----------|------ +Vaisala | RS92-SGP/NGP | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: +Vaisala | RS41-SG/SGP/SGM | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (for -SGP) | :heavy_check_mark: +Graw | DFM06/09/17 | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | :x: +Meteomodem | M10 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent | :x: +Meteomodem | M20 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: (For some models) | :x: +Intermet Systems | iMet-4 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent | :x: +Intermet Systems | iMet-54 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | Not Sent | :x: +Lockheed Martin | LMS6-400/1680 | :heavy_check_mark: | :x: | :x: | :x: | Not Sent +Meisei | iMS-100 | :heavy_check_mark: | :x: | :x: | :x: | Not Sent +Meteo-Radiy | MRZ-H1 (400 MHz) | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | Not Sent Support for other radiosondes may be added as required - please send us sondes to test with! If you have any information about telemetry formats, we'd love to hear from you (see our contact details below). @@ -53,4 +53,4 @@ All software within this repository is licensed under the GNU General Public Lic Radiosonde telemetry data captured via this software and uploaded into the [Sondehub](https://sondehub.org/) Database system is licensed under [Creative Commons BY-SA v2.0](https://creativecommons.org/licenses/by-sa/2.0/). Telemetry data uploaded into the APRS-IS network is generally considered to be released into the public domain. -By uploading data into these systems (by enabling the relevant uploaders within the `station.cfg` file) you as the user agree for your data to be made available under these licenses. Note that uploading to Sondehub is enabled by default. \ No newline at end of file +By uploading data into these systems (by enabling the relevant uploaders within the `station.cfg` file) you as the user agree for your data to be made available under these licenses. Note that uploading to Sondehub is enabled by default. diff --git a/auto_rx/auto_rx.py b/auto_rx/auto_rx.py index a77061d7..f7c20013 100644 --- a/auto_rx/auto_rx.py +++ b/auto_rx/auto_rx.py @@ -497,7 +497,7 @@ def telemetry_filter(telemetry): if "sats" in telemetry: if telemetry["sats"] < 4: logging.warning( - "Sonde %s can only see %d SVs - discarding position as bad." + "Sonde %s can only see %d GNSS sats - discarding position as bad." % (telemetry["id"], telemetry["sats"]) ) return False diff --git a/auto_rx/autorx/__init__.py b/auto_rx/autorx/__init__.py index 5426d0eb..2c00724e 100644 --- a/auto_rx/autorx/__init__.py +++ b/auto_rx/autorx/__init__.py @@ -17,7 +17,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.5.8" +__version__ = "1.5.9" # Global Variables diff --git a/auto_rx/autorx/decode.py b/auto_rx/autorx/decode.py index b1ab83b0..84db559f 100644 --- a/auto_rx/autorx/decode.py +++ b/auto_rx/autorx/decode.py @@ -209,6 +209,12 @@ def __init__( # This should hopefully handle a few iMets on the same frequency in a graceful manner. self.imet_max_ids = 4 self.imet_id = [] + # iMet-1 and iMet-4 sondes behave differently. + # iMet-1 sondes increment the frame counter *twice* each second, imet-4 only once per second. + # We need to detect this to be able to calculate a start time, and hence generate a serial number. + self.imet_type = None + self.imet_prev_time = None + self.imet_prev_frame = None # This will become our decoder thread. self.decoder = None @@ -1307,7 +1313,7 @@ def handle_decoder_line(self, data): # We append -Ozone to the sonde type field to indicate this. # TODO: Decode device ID from aux field to indicate what the aux payload actually is? if "aux" in _telemetry: - _telemetry["type"] += "-Ozone" + _telemetry["type"] += "-Ozone" # iMet Specific actions if self.sonde_type == "IMET": @@ -1321,9 +1327,44 @@ def handle_decoder_line(self, data): # Fix up the time. _telemetry["datetime_dt"] = fix_datetime(_telemetry["datetime"]) + + # An attempt at detecting iMet-1 vs iMet-4 sondes based on how the frame count increments + # compared to the time. + # Note that this is going to break horribly if an iMet-1 and an iMet-4 are on the same frequency, + # or if there are multiple iMet-4's in the air when this is performed. I don't have a nice + # solution to that second problem. + # This may also break when running in UDP mode for long periods. + if self.imet_type is None: + if self.imet_prev_frame is None: + self.imet_prev_frame = _telemetry['frame'] + self.imet_prev_time = _telemetry["datetime_dt"] + self.log_info("Waiting for additional frames to determine iMet type (1 or 4)") + return False + else: + # Calculate and compare frame vs time deltas. + _time_delta = (_telemetry["datetime_dt"] - self.imet_prev_time).total_seconds() + _frame_delta = _telemetry['frame'] - self.imet_prev_frame + + if _time_delta == _frame_delta//2: + # Frame counter increments at twice the rate of the time counter = iMet-1 + self.log_info("iMet sonde is most likely an iMet-1") + self.imet_type = "iMet-1" + elif _time_delta == _frame_delta: + # Frame counter increments at the same rate as the time counter = iMet-4 + self.log_info("iMet sonde is most likely an iMet-4") + self.imet_type = "iMet-4" + else: + # Some other case (possibly 2 sondes on the same frequency?) + # Assume iMet-4... + self.log_info("iMet sonde is most likely an iMet-4 (less confidence)") + self.imet_type = "iMet-4" + else: + _telemetry['subtype'] = self.imet_type + + # Generate a unique ID based on the power-on time and frequency, as iMet sonde telemetry is painful # and doesn't send any ID. - _new_imet_id = imet_unique_id(_telemetry) + _new_imet_id = imet_unique_id(_telemetry, imet1=(self.imet_type=="iMet-1")) # If we have seen this ID before, keep using it. if _new_imet_id in self.imet_id: diff --git a/auto_rx/autorx/sonde_specific.py b/auto_rx/autorx/sonde_specific.py index 914a9457..9ef531b8 100644 --- a/auto_rx/autorx/sonde_specific.py +++ b/auto_rx/autorx/sonde_specific.py @@ -51,7 +51,7 @@ def fix_datetime(datetime_str, local_dt_str=None): # -def imet_unique_id(telemetry, custom="SONDE"): +def imet_unique_id(telemetry, custom="SONDE", imet1=False): """ Generate a 'unique' imet radiosonde ID based on the power-on time, frequency, and an optional location code. This requires the following fields be present in the telemetry dict: @@ -62,8 +62,16 @@ def imet_unique_id(telemetry, custom="SONDE"): _imet_dt = telemetry["datetime_dt"] + if imet1: + # iMet-1 sondes increment their frame counter TWICE every second, so we need to + # compensate for this to be able to determine a power-on time. + _frame = telemetry["frame"]//2 + else: + # iMet-4 sondes increment the frame counter once per second. + _frame = telemetry["frame"] + # Determine power on time: Current time - number of frames (one frame per second) - _power_on_time = _imet_dt - datetime.timedelta(seconds=telemetry["frame"]) + _power_on_time = _imet_dt - datetime.timedelta(seconds=_frame) # Round frequency to the nearest 100 kHz (iMet sondes only have 100 kHz frequency steps) _freq = round(telemetry["freq_float"] * 10.0) / 10.0 diff --git a/auto_rx/autorx/sondehub.py b/auto_rx/autorx/sondehub.py index 29711e0a..35b18652 100644 --- a/auto_rx/autorx/sondehub.py +++ b/auto_rx/autorx/sondehub.py @@ -192,7 +192,10 @@ def reformat_data(self, telemetry): elif telemetry["type"] == "IMET": _output["manufacturer"] = "Intermet Systems" - _output["type"] = "iMet-4" + if "subtype" in telemetry: + _output["type"] = telemetry['subtype'] + else: + _output["type"] = "iMet-4" _output["serial"] = telemetry["id"].split("-")[1] elif telemetry["type"] == "IMET5": diff --git a/imet/imet1rs_dft.c b/imet/imet1rs_dft.c index b93003aa..cdcf8d41 100644 --- a/imet/imet1rs_dft.c +++ b/imet/imet1rs_dft.c @@ -30,34 +30,6 @@ int option_verbose = 0, // ausfuehrliche Anzeige option_json = 0, wavloaded = 0; -// Bell202, 1200 baud (1200Hz/2200Hz), 8N1 -#define BAUD_RATE 1200 - - -typedef struct { - // GPS - int hour; - int min; - int sec; - float lat; - float lon; - int alt; - int sats; - // PTU - int frame; - float temp; - float pressure; - float humidity; - float batt; - // - int gps_valid; - int ptu_valid; - // - int jsn_freq; // freq/kHz (SDR) -} gpx_t; - -gpx_t gpx; - /* ------------------------------------------------------------------------------------ */ int sample_rate = 0, bits_sample = 0, channels = 0; @@ -158,11 +130,43 @@ int f32read_sample(FILE *fp, float *s) { /* ------------------------------------------------------------------------------------ */ +// Bell202, 1200 baud (1200Hz/2200Hz), 8N1 +#define BAUD_RATE 1200 + #define BITS (10) #define LEN_BITFRAME BAUD_RATE #define LEN_BYTEFRAME (LEN_BITFRAME/BITS) #define HEADLEN 30 +typedef struct { + // GPS + int hour; + int min; + int sec; + float lat; + float lon; + int alt; + int sats; + float vH; float vD; float vV; // eGPS + // PTU + int frame; + float temp; + float pressure; + float humidity; + float batt; + // XDATA + char xdata[2*LEN_BYTEFRAME+1]; // xdata hex string: aux_str1#aux_str2... + char *paux; + // + int gps_valid; + int ptu_valid; + // + int jsn_freq; // freq/kHz (SDR) +} gpx_t; + +gpx_t gpx; + + char header[] = "1111111111111111111""10""10000000""1"; char buf[HEADLEN+1] = "x"; int bufpos = -1; @@ -254,20 +258,108 @@ int crc16(ui8_t bytes[], int len) { /* -------------------------------------------------------------------------- */ #define LEN_GPSePTU (18+20) +/* + standard frame: + 01 02 (GPS) .. .. 01 04 (ePTU) .. .. +*/ +#define SOH_01 0x01 + +#define PKT_PTU 0x01 +#define PKT_GPS 0x02 +#define PKT_XDATA 0x03 +#define PKT_ePTU 0x04 +#define PKT_eGPS 0x05 /* -GPS Data Packet +PTU (enhanced) Data Packet (LSB) offset bytes description 0 1 SOH = 0x01 - 1 1 PKT_ID = 0x02 + 1 1 PKT_ID = 0x01/0x04 + 2 2 PKT = packet number + 4 3 P, mbs (P = n/100) + 7 2 T, °C (T = n/100) + 9 2 U, % (U = n/100) +11 1 Vbat, V (V = n/10) + 12 2 Tint, °C (Tint = n/100) + 14 2 Tpr, °C (Tpr = n/100) + 16 2 Tu, °C (Tu = n/100) +12/18 2 CRC (16-bit) +packet size = 14/20 bytes +*/ +#define pos_PCKnum 0x02 // 2 byte +#define pos_PTUprs 0x04 // 3 byte +#define pos_PTUtem 0x07 // 2 byte int +#define pos_PTUhum 0x09 // 2 byte +#define pos_PTUbat 0x0B // 1 byte +#define pos_PTUcrc 0x0C // 2 byte +#define pos_ePTUtint 0x0C // 2 byte +#define pos_ePTUtpr 0x0E // 2 byte +#define pos_ePTUtu 0x10 // 2 byte +#define pos_ePTUcrc 0x12 // 2 byte + +int print_ePTU(int pos, ui8_t PKT_ID) { + int P, U; + short T; + int bat, pcknum; + int crc_val, crc; // 0x04: ePTU 0x01: PTU + int posPTUCRC = (PKT_ID == PKT_ePTU) ? pos_ePTUcrc : pos_PTUcrc; + + if (PKT_ID != PKT_ePTU && PKT_ID != PKT_PTU) return -1; + + crc_val = ((byteframe+pos)[posPTUCRC] << 8) | (byteframe+pos)[posPTUCRC+1]; + crc = crc16(byteframe+pos, posPTUCRC); // len=pos + + P = (byteframe+pos)[pos_PTUprs] | ((byteframe+pos)[pos_PTUprs+1]<<8) | ((byteframe+pos)[pos_PTUprs+2]<<16); + T = (byteframe+pos)[pos_PTUtem] | ((byteframe+pos)[pos_PTUtem+1]<<8); + U = (byteframe+pos)[pos_PTUhum] | ((byteframe+pos)[pos_PTUhum+1]<<8); + bat = (byteframe+pos)[pos_PTUbat]; + + pcknum = (byteframe+pos)[pos_PCKnum] | ((byteframe+pos)[pos_PCKnum+1]<<8); + fprintf(stdout, "[%d] ", pcknum); + + fprintf(stdout, " P:%.2fmb ", P/100.0); + fprintf(stdout, " T:%.2f°C ", T/100.0); + fprintf(stdout, " U:%.2f%% ", U/100.0); + fprintf(stdout, " bat:%.1fV ", bat/10.0); + + fprintf(stdout, " # "); + fprintf(stdout, " CRC: %04X ", crc_val); + fprintf(stdout, "- %04X ", crc); + if (crc_val == crc) { + fprintf(stdout, "[OK]"); + gpx.ptu_valid = PKT_ID; + gpx.frame = pcknum; + gpx.pressure = P/100.0; + gpx.temp = T/100.0; + gpx.humidity = U/100.0; + gpx.batt = bat/10.0; + } + else { + fprintf(stdout, "[NO]"); + gpx.ptu_valid = 0; + } + fprintf(stdout, "\n"); + + return (crc_val != crc); +} + + +/* +GPS (enhanced) Data Packet (LSB) +offset bytes description + 0 1 SOH = 0x01 + 1 1 PKT_ID = 0x02/0x05 2 4 Latitude, +/- deg (float) 6 4 Longitude, +/- deg (float) 10 2 Altitude, meters (Alt = n-5000) 12 1 nSat (0 - 12) -13 3 Time (hr,min,sec) -16 2 CRC (16-bit) -packet size = 18 bytes + 13 4 velE m/s (float) + 17 4 velN m/s (float) + 21 4 velU m/s (float) +13/25 3 Time (hr,min,sec) +16/28 2 CRC (16-bit) +packet size = 18/30 bytes */ #define pos_GPSlat 0x02 // 4 byte float #define pos_GPSlon 0x06 // 4 byte float @@ -275,12 +367,22 @@ packet size = 18 bytes #define pos_GPSsats 0x0C // 1 byte #define pos_GPStim 0x0D // 3 byte #define pos_GPScrc 0x10 // 2 byte +#define pos_eGPSvE 0x0D // 4 byte float +#define pos_eGPSvN 0x11 // 4 byte float +#define pos_eGPSvU 0x15 // 4 byte float +#define pos_eGPStim 0x19 // 3 byte +#define pos_eGPScrc 0x1C // 2 byte -int print_GPS(int pos) { +int print_eGPS(int pos, ui8_t PKT_ID) { float lat, lon; + float vE, vN, vU, vH, vD; // E,N,U, speed, dir/heading int alt, sats; int std, min, sek; - int crc_val, crc; + int crc_val, crc; // 0x02: GPS 0x05: eGPS + int posGPStim = (PKT_ID == PKT_GPS) ? pos_GPStim : pos_eGPStim; + int posGPSCRC = (PKT_ID == PKT_GPS) ? pos_GPScrc : pos_eGPScrc; + + if (PKT_ID != PKT_GPS && PKT_ID != PKT_eGPS) return -1; crc_val = ((byteframe+pos)[pos_GPScrc] << 8) | (byteframe+pos)[pos_GPScrc+1]; crc = crc16(byteframe+pos, pos_GPScrc); // len=pos @@ -293,9 +395,9 @@ int print_GPS(int pos) { alt = ((byteframe+pos)[pos_GPSalt+1]<<8)+(byteframe+pos)[pos_GPSalt] - 5000; sats = (byteframe+pos)[pos_GPSsats]; - std = (byteframe+pos)[pos_GPStim+0]; - min = (byteframe+pos)[pos_GPStim+1]; - sek = (byteframe+pos)[pos_GPStim+2]; + std = (byteframe+pos)[posGPStim+0]; + min = (byteframe+pos)[posGPStim+1]; + sek = (byteframe+pos)[posGPStim+2]; fprintf(stdout, "(%02d:%02d:%02d) ", std, min, sek); fprintf(stdout, " lat: %.6f° ", lat); @@ -303,12 +405,24 @@ int print_GPS(int pos) { fprintf(stdout, " alt: %dm ", alt); fprintf(stdout, " sats: %d ", sats); + gpx.vH = gpx.vD = gpx.vV = 0; + if (PKT_ID == PKT_eGPS) { + memcpy(&vE, byteframe+pos+pos_eGPSvE, 4); + memcpy(&vN, byteframe+pos+pos_eGPSvN, 4); + memcpy(&vU, byteframe+pos+pos_eGPSvU, 4); + vH = sqrt(vE*vE+vN*vN); + vD = atan2(vE, vN) * 180.0 / M_PI; + if (vD < 0) vD += 360.0; + // TODO: TEST eGPS/vel + fprintf(stdout, " vH: %.1fm/s D: %.1f° vV: %.1fm/s ", vH, vD, vU); + } + fprintf(stdout, " # "); fprintf(stdout, " CRC: %04X ", crc_val); fprintf(stdout, "- %04X ", crc); if (crc_val == crc) { fprintf(stdout, "[OK]"); - gpx.gps_valid = 1; + gpx.gps_valid = PKT_ID; gpx.lat = lat; gpx.lon = lon; gpx.alt = alt; @@ -316,88 +430,115 @@ int print_GPS(int pos) { gpx.hour = std; gpx.min = min; gpx.sec = sek; + if (PKT_ID == PKT_eGPS) { + gpx.vH = vH; + gpx.vD = vD; + gpx.vV = vU; + } } else { fprintf(stdout, "[NO]"); gpx.gps_valid = 0; } + fprintf(stdout, "\n"); return (crc_val != crc); } /* -PTU (enhanced) Data Packet +Extra Data Packet - XDATA offset bytes description 0 1 SOH = 0x01 - 1 1 PKT_ID = 0x04 - 2 2 PKT = packet number - 4 3 P, mbs (P = n/100) - 7 2 T, °C (T = n/100) - 9 2 U, % (U = n/100) -11 1 Vbat, V (V = n/10) -12 2 Tint, °C (Tint = n/100) -14 2 Tpr, °C (Tpr = n/100) -16 2 Tu, °C (Tu = n/100) -18 2 CRC (16-bit) -packet size = 20 bytes + 1 1 PKT_ID = 0x03 + 2 2 N = number of data bytes to follow + 3+N 2 CRC (16-bit) +N=8, ID=0x01: Ozonesonde (MSB) + 3 1 Instrument_type = 0x01 (ID) + 4 1 Instrument_number + 5 2 Icell, uA (I = n/1000) + 7 2 Tpump, °C (T = n/100) + 9 1 Ipump, mA +10 1 Vbat, (V = n/10) +11 2 CRC (16-bit) +packet size = 12 bytes +// +ID=0x05: OIF411 +ID=0x08: CFH (Cryogenic Frost-Point Hygrometer) +ID=0x19: COBALD (Compact Optical Backscatter Aerosol Detector) */ -#define pos_PCKnum 0x02 // 2 byte -#define pos_PTUprs 0x04 // 3 byte -#define pos_PTUtem 0x07 // 2 byte int -#define pos_PTUhum 0x09 // 2 byte -#define pos_PTUbat 0x0B // 1 byte -#define pos_PTUcrc 0x12 // 2 byte -int print_ePTU(int pos) { +int print_xdata(int pos, ui8_t N) { int P, U; - short T; - int bat, pcknum; + ui8_t InstrumentNum; + short Tpump; + unsigned short Icell, Ipump, Vbat; int crc_val, crc; + int crc_len = 3+N; + + crc_val = ((byteframe+pos)[crc_len] << 8) | (byteframe+pos)[crc_len+1]; + crc = crc16(byteframe+pos, crc_len); // len=pos + + fprintf(stdout, " XDATA "); + // (byteframe+pos)[2] = N + if (N == 8 && (byteframe+pos)[3] == 0x01) + { // Ozonesonde 01 03 08 01 .. .. (MSB) + InstrumentNum = (byteframe+pos)[4]; + Icell = (byteframe+pos)[5+1] | ((byteframe+pos)[5]<<8); // MSB + Tpump = (byteframe+pos)[7+1] | ((byteframe+pos)[7]<<8); // MSB + Ipump = (byteframe+pos)[9]; + Vbat = (byteframe+pos)[10]; + fprintf(stdout, " Icell:%.3fuA ", Icell/1000.0); + fprintf(stdout, " Tpump:%.2f°C ", Tpump/100.0); + fprintf(stdout, " Ipump:%dmA ", Ipump); + fprintf(stdout, " Vbat:%.1fV ", Vbat/10.0); + } + else { + int j; + fprintf(stdout, " (N=0x%02X)", N); + for (j = 0; j < N; j++) fprintf(stdout, " %02X", (byteframe+pos)[3+j]); + } - crc_val = ((byteframe+pos)[pos_PTUcrc] << 8) | (byteframe+pos)[pos_PTUcrc+1]; - crc = crc16(byteframe+pos, pos_PTUcrc); // len=pos - - P = (byteframe+pos)[pos_PTUprs] | ((byteframe+pos)[pos_PTUprs+1]<<8) | ((byteframe+pos)[pos_PTUprs+2]<<16); - T = (byteframe+pos)[pos_PTUtem] | ((byteframe+pos)[pos_PTUtem+1]<<8); - U = (byteframe+pos)[pos_PTUhum] | ((byteframe+pos)[pos_PTUhum+1]<<8); - bat = (byteframe+pos)[pos_PTUbat]; - - pcknum = (byteframe+pos)[pos_PCKnum] | ((byteframe+pos)[pos_PCKnum+1]<<8); - fprintf(stdout, "[%d] ", pcknum); - - fprintf(stdout, " P:%.2fmb ", P/100.0); - fprintf(stdout, " T:%.2f°C ", T/100.0); - fprintf(stdout, " U:%.2f%% ", U/100.0); - fprintf(stdout, " bat:%.1fV ", bat/10.0); + if (crc_val == crc && (gpx.paux-gpx.xdata)+2*(N+1) < 2*LEN_BYTEFRAME) { + // hex(xdata[2:3+N]) , strip [0103NN]..[CRC16] , '#'-separated + int j; + if (gpx.paux > gpx.xdata) { + *(gpx.paux) = '#'; + gpx.paux += 1; + } + //exclude length (byteframe+pos)[2]=N (sprintf(gpx.paux, "%02X", (byteframe+pos)[2]); gpx.paux += 2;) + for (j = 0; j < N; j++) { + sprintf(gpx.paux, "%02X", (byteframe+pos)[3+j]); + gpx.paux += 2; + } + *(gpx.paux) = '\0'; + } fprintf(stdout, " # "); fprintf(stdout, " CRC: %04X ", crc_val); fprintf(stdout, "- %04X ", crc); if (crc_val == crc) { fprintf(stdout, "[OK]"); - gpx.ptu_valid = 1; - gpx.frame = pcknum; - gpx.pressure = P/100.0; - gpx.temp = T/100.0; - gpx.humidity = U/100.0; - gpx.batt = bat/10.0; } else { fprintf(stdout, "[NO]"); - gpx.ptu_valid = 0; } + fprintf(stdout, "\n"); return (crc_val != crc); } + /* -------------------------------------------------------------------------- */ + int print_frame(int len) { int i; int framelen; int crc_err1 = 0, - crc_err2 = 0; + crc_err2 = 0, + crc_err3 = 0; + int ofs = 0; int out = 0; if ( len < 2 || len > LEN_BYTEFRAME) return -1; @@ -406,40 +547,63 @@ int print_frame(int len) { gpx.gps_valid = 0; gpx.ptu_valid = 0; + framelen = bits2bytes(bitframe, byteframe, len); + if (option_rawbits) { - print_rawbits((LEN_GPSePTU+2)*BITS); + print_rawbits(framelen*BITS); } else { - framelen = bits2bytes(bitframe, byteframe, len); - if (option_raw) { for (i = 0; i < framelen; i++) { // LEN_GPSePTU fprintf(stdout, "%02X ", byteframe[i]); } fprintf(stdout, "\n"); - out |= 4; + out |= 8; } //else { - if ((byteframe[0] == 0x01) && (byteframe[1] == 0x02)) { // GPS Data Packet - crc_err1 = print_GPS(0x00); // packet offset in byteframe - fprintf(stdout, "\n"); - out |= 1; - } - if ((byteframe[pos_GPScrc+2+0] == 0x01) && (byteframe[pos_GPScrc+2+1] == 0x04)) { // PTU Data Packet - crc_err2 = print_ePTU(pos_GPScrc+2); // packet offset in byteframe - fprintf(stdout, "\n"); - out |= 2; - } -/* - if ((byteframe[0] == 0x01) && (byteframe[1] == 0x04)) { // PTU Data Packet - print_ePTU(0x00); // packet offset in byteframe - fprintf(stdout, "\n"); + ofs = 0; + gpx.xdata[0] = '\0'; + gpx.paux = gpx.xdata; + while (ofs < framelen && byteframe[ofs] == SOH_01) // SOH = 0x01 + { + ui8_t PKT_ID = byteframe[ofs+1]; + if (PKT_ID == PKT_GPS || PKT_ID == PKT_eGPS) // GPS/eGPS Data Packet + { + int posGPSCRC = (PKT_ID == PKT_GPS) ? pos_GPScrc : pos_eGPScrc; + crc_err1 = print_eGPS(ofs, PKT_ID); // packet offset in byteframe + ofs += posGPSCRC+2; + out |= 1; + } + else if (PKT_ID == PKT_ePTU || PKT_ID == PKT_PTU) // ePTU/PTU Data Packet + { + int posPTUCRC = (PKT_ID == PKT_ePTU) ? pos_ePTUcrc : pos_PTUcrc; + crc_err2 = print_ePTU(ofs, PKT_ID); // packet offset in byteframe + ofs += posPTUCRC+2; + out |= 2; + } + else if (PKT_ID == PKT_XDATA) // Extra Data Packet + { + ui8_t N = byteframe[ofs+2]; + if (N > 0 && ofs+2+N+2 < framelen) + { + crc_err3 = print_xdata(ofs, N); // packet offset in byteframe + ofs += N+3+2; + out |= 4; + } + else { + break; + } + } + else { + break; + } } -*/ -// // if (crc_err1==0 && crc_err2==0) { } + + // if (crc_err1==0 && crc_err2==0) { } + if (option_json) { if (gpx.gps_valid && gpx.ptu_valid) // frameNb part of PTU-pck @@ -448,6 +612,13 @@ int print_frame(int len) { fprintf(stdout, "{ \"type\": \"%s\"", "IMET"); fprintf(stdout, ", \"frame\": %d, \"id\": \"iMet\", \"datetime\": \"%02d:%02d:%02dZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %d, \"sats\": %d, \"temp\": %.2f, \"humidity\": %.2f, \"pressure\": %.2f, \"batt\": %.1f", gpx.frame, gpx.hour, gpx.min, gpx.sec, gpx.lat, gpx.lon, gpx.alt, gpx.sats, gpx.temp, gpx.humidity, gpx.pressure, gpx.batt); + // TODO: TEST eGPS/vel + if (0 && gpx.gps_valid == PKT_eGPS) { + fprintf(stdout, ", \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f", gpx.vH, gpx.vD, gpx.vV ); + } + if (gpx.xdata[0]) { + fprintf(stdout, ", \"aux\": \"%s\"", gpx.xdata ); + } if (gpx.jsn_freq > 0) { fprintf(stdout, ", \"freq\": %d", gpx.jsn_freq); }