let's try to implement jt65 and jt9 as well
This commit is contained in:
		
							
								
								
									
										8
									
								
								csdr.py
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								csdr.py
									
									
									
									
									
								
							| @@ -25,7 +25,7 @@ import os | ||||
| import signal | ||||
| import threading | ||||
| from functools import partial | ||||
| from owrx.wsjt import Ft8Chopper, WsprChopper | ||||
| from owrx.wsjt import Ft8Chopper, WsprChopper, Jt9Chopper, Jt65Chopper | ||||
|  | ||||
| import logging | ||||
| logger = logging.getLogger(__name__) | ||||
| @@ -277,6 +277,10 @@ class dsp(object): | ||||
|                 chopper = Ft8Chopper(self.secondary_process_demod.stdout) | ||||
|             elif smd == "wspr": | ||||
|                 chopper = WsprChopper(self.secondary_process_demod.stdout) | ||||
|             elif smd == "jt65": | ||||
|                 chopper = Jt65Chopper(self.secondary_process_demod.stdout) | ||||
|             elif smd == "jt9": | ||||
|                 chopper = Jt9Chopper(self.secondary_process_demod.stdout) | ||||
|             chopper.start() | ||||
|             self.output.add_output("wsjt_demod", chopper.read) | ||||
|         else: | ||||
| @@ -371,7 +375,7 @@ class dsp(object): | ||||
|     def isWsjtMode(self, demodulator = None): | ||||
|         if demodulator is None: | ||||
|             demodulator = self.get_secondary_demodulator() | ||||
|         return demodulator in ["ft8", "wspr"] | ||||
|         return demodulator in ["ft8", "wspr", "jt65", "jt9"] | ||||
|  | ||||
|     def set_output_rate(self,output_rate): | ||||
|         self.output_rate=output_rate | ||||
|   | ||||
| @@ -840,20 +840,22 @@ img.openwebrx-mirror-img | ||||
| } | ||||
|  | ||||
| #openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-content-container, | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-content-container | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-content-container, | ||||
| #openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-content-container, | ||||
| #openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-content-container, | ||||
| #openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel, | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel, | ||||
| #openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-select-channel, | ||||
| #openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-select-channel | ||||
| { | ||||
|     display: none; | ||||
| } | ||||
|  | ||||
| #openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-canvas-container, | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-canvas-container | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-canvas-container, | ||||
| #openwebrx-panel-digimodes[data-mode="jt65"] #openwebrx-digimode-canvas-container, | ||||
| #openwebrx-panel-digimodes[data-mode="jt9"] #openwebrx-digimode-canvas-container | ||||
| { | ||||
|     height: 200px; | ||||
|     margin: -10px; | ||||
| } | ||||
|  | ||||
| #openwebrx-panel-digimodes[data-mode="ft8"] #openwebrx-digimode-select-channel, | ||||
| #openwebrx-panel-digimodes[data-mode="wspr"] #openwebrx-digimode-select-channel | ||||
| { | ||||
|     display: none; | ||||
| } | ||||
| @@ -82,6 +82,8 @@ | ||||
|                             <option value="bpsk31">BPSK31</option> | ||||
|                             <option value="ft8">FT8</option> | ||||
|                             <option value="wspr">WSPR</option> | ||||
|                             <option value="jt65">JT65</option> | ||||
|                             <option value="jt9">JT9</option> | ||||
|                         </select> | ||||
|                     </div> | ||||
|                     <div class="openwebrx-panel-line"> | ||||
|   | ||||
| @@ -1385,7 +1385,7 @@ function update_wsjt_panel(msg) { | ||||
|     var t = new Date(msg['timestamp']); | ||||
|     var pad = function(i) { return ('' + i).padStart(2, "0"); } | ||||
|     var linkedmsg = msg['msg']; | ||||
|     if (msg['mode'] == 'FT8') { | ||||
|     if (['FT8', 'JT65', 'JT9'].indexOf(msg['mode']) >= 0) { | ||||
|         var matches = linkedmsg.match(/(.*\s[A-Z0-9]+\s)([A-R]{2}[0-9]{2})$/); | ||||
|         if (matches && matches[2] != 'RR73') { | ||||
|             linkedmsg = html_escape(matches[1]) + '<a href="/map?locator=' + matches[2] + '" target="_blank">' + matches[2] + '</a>'; | ||||
| @@ -2709,6 +2709,8 @@ function demodulator_digital_replace(subtype) | ||||
|     case "rtty": | ||||
|     case "ft8": | ||||
|     case "wspr": | ||||
|     case "jt65": | ||||
|     case "jt9": | ||||
|         secondary_demod_start(subtype); | ||||
|         demodulator_analog_replace('usb', true); | ||||
|         demodulator_buttons_update(); | ||||
| @@ -2716,7 +2718,7 @@ function demodulator_digital_replace(subtype) | ||||
|     } | ||||
|     $('#openwebrx-panel-digimodes').attr('data-mode', subtype); | ||||
|     toggle_panel("openwebrx-panel-digimodes", true); | ||||
|     toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr'].indexOf(subtype) >= 0); | ||||
|     toggle_panel("openwebrx-panel-wsjt-message", ['ft8', 'wspr', 'jt65', 'jt9'].indexOf(subtype) >= 0); | ||||
| } | ||||
|  | ||||
| function secondary_demod_create_canvas() | ||||
| @@ -2888,6 +2890,8 @@ function secondary_demod_listbox_changed() | ||||
|         case "rtty": | ||||
|         case "ft8": | ||||
|         case "wspr": | ||||
|         case "jt65": | ||||
|         case "jt9": | ||||
|             demodulator_digital_replace(sdm); | ||||
|             break; | ||||
|     } | ||||
|   | ||||
							
								
								
									
										47
									
								
								owrx/wsjt.py
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								owrx/wsjt.py
									
									
									
									
									
								
							| @@ -144,9 +144,29 @@ class WsprChopper(WsjtChopper): | ||||
|         return ["wsprd", "-d", file] | ||||
|  | ||||
|  | ||||
| class Jt65Chopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 60 | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
|         #TODO expose decoding quality parameters through config | ||||
|         return ["jt9", "--jt65", "-d", "3", file] | ||||
|  | ||||
|  | ||||
| class Jt9Chopper(WsjtChopper): | ||||
|     def __init__(self, source): | ||||
|         self.interval = 60 | ||||
|         super().__init__(source) | ||||
|  | ||||
|     def decoder_commandline(self, file): | ||||
|         #TODO expose decoding quality parameters through config | ||||
|         return ["jt9", "--jt9", "-d", "3", file] | ||||
|  | ||||
|  | ||||
| class WsjtParser(object): | ||||
|     locator_pattern = re.compile(".*\\s([A-Z0-9]+)\\s([A-R]{2}[0-9]{2})$") | ||||
|     jt9_pattern = re.compile("^[0-9]{6} .*") | ||||
|     jt9_pattern = re.compile("^([0-9]{6}|\\*{4}) .*") | ||||
|     wspr_pattern = re.compile("^[0-9]{4} .*") | ||||
|     wspr_splitter_pattern = re.compile("([A-Z0-9]*)\\s([A-R]{2}[0-9]{2})\\s([0-9]+)") | ||||
|  | ||||
| @@ -154,7 +174,9 @@ class WsjtParser(object): | ||||
|         self.handler = handler | ||||
|  | ||||
|     modes = { | ||||
|         "~": "FT8" | ||||
|         "~": "FT8", | ||||
|         "#": "JT65", | ||||
|         "@": "JT9" | ||||
|     } | ||||
|  | ||||
|     def parse(self, data): | ||||
| @@ -179,15 +201,22 @@ class WsjtParser(object): | ||||
|     def parse_from_jt9(self, msg): | ||||
|         # ft8 sample | ||||
|         # '222100 -15 -0.0  508 ~  CQ EA7MJ IM66' | ||||
|         # jt65 sample | ||||
|         # '**** -10  0.4 1556 #  CQ RN6AM KN95' | ||||
|         out = {} | ||||
|         ts = datetime.strptime(msg[0:6], "%H%M%S") | ||||
|         out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000) | ||||
|         out["db"] = float(msg[7:10]) | ||||
|         out["dt"] = float(msg[11:15]) | ||||
|         out["freq"] = int(msg[16:20]) | ||||
|         modeChar = msg[21:22] | ||||
|         if msg.startswith("****"): | ||||
|             out["timestamp"] = int(datetime.now().timestamp() * 1000) | ||||
|             msg = msg[5:] | ||||
|         else: | ||||
|             ts = datetime.strptime(msg[0:6], "%H%M%S") | ||||
|             out["timestamp"] = int(datetime.combine(date.today(), ts.time(), datetime.now().tzinfo).timestamp() * 1000) | ||||
|             msg = msg[7:] | ||||
|         out["db"] = float(msg[0:3]) | ||||
|         out["dt"] = float(msg[4:8]) | ||||
|         out["freq"] = int(msg[9:13]) | ||||
|         modeChar = msg[14:15] | ||||
|         out["mode"] = mode = WsjtParser.modes[modeChar] if modeChar in WsjtParser.modes else "unknown" | ||||
|         wsjt_msg = msg[24:60].strip() | ||||
|         wsjt_msg = msg[17:53].strip() | ||||
|         self.parseLocator(wsjt_msg, mode) | ||||
|         out["msg"] = wsjt_msg | ||||
|         return out | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Jakob Ketterl
					Jakob Ketterl