Debugging
This commit is contained in:
parent
f14256d60d
commit
88bbff42f1
|
|
@ -118,7 +118,6 @@ class SstvDemodulator(ServiceDemodulator):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sampleRate = 48000
|
self.sampleRate = 48000
|
||||||
workers = [
|
workers = [
|
||||||
Shift(1500.0 / self.sampleRate),
|
|
||||||
Agc(Format.COMPLEX_FLOAT),
|
Agc(Format.COMPLEX_FLOAT),
|
||||||
SstvDecoder(self.sampleRate),
|
SstvDecoder(self.sampleRate),
|
||||||
SstvParser()
|
SstvParser()
|
||||||
|
|
|
||||||
|
|
@ -1205,7 +1205,11 @@ img.openwebrx-mirror-img
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aprs-symbol {
|
#openwebrx-panel-sstv-message .frame {
|
||||||
|
border: 2px dotted white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aprs-symbol {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
height: 15px;
|
height: 15px;
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ SstvMessagePanel.prototype.render = function() {
|
||||||
$(this.el).append($(
|
$(this.el).append($(
|
||||||
'<table>' +
|
'<table>' +
|
||||||
'<thead><tr>' +
|
'<thead><tr>' +
|
||||||
'<th class="message">Message</th>' +
|
'<th class="message">TV</th>' +
|
||||||
'</tr></thead>' +
|
'</tr></thead>' +
|
||||||
'<tbody></tbody>' +
|
'<tbody></tbody>' +
|
||||||
'</table>'
|
'</table>'
|
||||||
|
|
@ -290,15 +290,30 @@ SstvMessagePanel.prototype.render = function() {
|
||||||
|
|
||||||
SstvMessagePanel.prototype.pushMessage = function(msg) {
|
SstvMessagePanel.prototype.pushMessage = function(msg) {
|
||||||
var $b = $(this.el).find('tbody');
|
var $b = $(this.el).find('tbody');
|
||||||
if(msg.hasOwnProperty('message'))
|
if(msg.hasOwnProperty('message')) {
|
||||||
$b.append($('<tr><td class="message">' + msg.message + '</td></tr>'));
|
$b.append($('<tr><td class="message">' + msg.message + '</td></tr>'));
|
||||||
if(msg.width>0 && msg.height>0 && !msg.hasOwnProperty('line')) {
|
$b.scrollTop($b[0].scrollHeight);
|
||||||
var $h = 'SCREEN ' + msg.width + "x" + msg.height + '<br>';
|
}
|
||||||
var $c = '<canvas width="' + msg.width + '" height="' + msg.height +
|
else if(msg.width>0 && msg.height>0 && !msg.hasOwnProperty('line')) {
|
||||||
'" style="border: 1px solid black;"></canvas>';
|
var h = 'SCREEN ' + msg.width + "x" + msg.height + '<br>';
|
||||||
$b.append($('<tr><td class="message">' + $h + $c + '</td></tr>'));
|
var c = '<canvas width="' + msg.width + '" height="' + msg.height +
|
||||||
|
'" class="frame"></canvas>';
|
||||||
|
$b.append($('<tr><td class="message">' + h + c + '</td></tr>'));
|
||||||
|
$b.scrollTop($b[0].scrollHeight);
|
||||||
|
}
|
||||||
|
else if(msg.width>0 && msg.height>0 && msg.line>=0 && msg.hasOwnProperty('pixels')) {
|
||||||
|
var pixels = atob(msg.pixels);
|
||||||
|
var canvas = $(this.el).find('canvas');
|
||||||
|
var ctx = canvas.getContext("2d");
|
||||||
|
var img = $ctx.createImageData(msg.width, 1);
|
||||||
|
for (var x = 0; x < msg.width; x++) {
|
||||||
|
img.data[x*4 + 0] = pixels.charCodeAt(x*3 + 2);
|
||||||
|
img.data[x*4 + 1] = pixels.charCodeAt(x*3 + 1);
|
||||||
|
img.data[x*4 + 2] = pixels.charCodeAt(x*3 + 0);
|
||||||
|
img.data[x*4 + 3] = 0xFF;
|
||||||
|
}
|
||||||
|
ctx.putImageData(img, 0, msg.line);
|
||||||
}
|
}
|
||||||
$b.scrollTop($b[0].scrollHeight);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$.fn.sstvMessagePanel = function() {
|
$.fn.sstvMessagePanel = function() {
|
||||||
|
|
|
||||||
95
owrx/sstv.py
95
owrx/sstv.py
|
|
@ -1,6 +1,5 @@
|
||||||
from csdr.module import ThreadModule
|
from csdr.module import ThreadModule
|
||||||
from pycsdr.types import Format
|
from pycsdr.types import Format
|
||||||
from io import BytesIO
|
|
||||||
import base64
|
import base64
|
||||||
import pickle
|
import pickle
|
||||||
|
|
||||||
|
|
@ -10,9 +9,10 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
class SstvParser(ThreadModule):
|
class SstvParser(ThreadModule):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.width = 0
|
self.data = bytearray(b'')
|
||||||
|
self.width = 0
|
||||||
self.height = 0
|
self.height = 0
|
||||||
self.line = 0
|
self.line = 0
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def getInputFormat(self) -> Format:
|
def getInputFormat(self) -> Format:
|
||||||
|
|
@ -22,32 +22,83 @@ class SstvParser(ThreadModule):
|
||||||
return Format.CHAR
|
return Format.CHAR
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
# Run while there is input data
|
||||||
while self.doRun:
|
while self.doRun:
|
||||||
data = self.reader.read()
|
# Read input data
|
||||||
if data is None:
|
inp = self.reader.read()
|
||||||
|
# Terminate if no input data
|
||||||
|
if inp is None:
|
||||||
self.doRun = False
|
self.doRun = False
|
||||||
break
|
break
|
||||||
out = self.process(data.tobytes())
|
# Add read data to the buffer
|
||||||
self.writer.write(pickle.dumps(out))
|
self.data = self.data + inp.tobytes()
|
||||||
|
# Process buffer contents
|
||||||
|
out = self.process()
|
||||||
|
# Keep processing while there is input to parse
|
||||||
|
while out is not None:
|
||||||
|
self.writer.write(pickle.dumps(out))
|
||||||
|
out = self.process()
|
||||||
|
|
||||||
def process(self, data):
|
def process(self):
|
||||||
try:
|
try:
|
||||||
out = { "mode": "SSTV" }
|
# Parse bitmap (BMP) file header starting with 'BM'
|
||||||
|
if len(self.data)>=54 and self.data[0]==ord(b'B') and self.data[1]==ord(b'M'):
|
||||||
if len(data)==54 and data[0]==ord(b'B') and data[1]==ord(b'M'):
|
# BMP height value is negative
|
||||||
self.width = data[18] + (data[19]<<8) + (data[20]<<16) + (data[21]<<24)
|
self.width = self.data[18] + (self.data[19]<<8) + (self.data[20]<<16) + (self.data[21]<<24)
|
||||||
self.height = data[22] + (data[23]<<8) + (data[24]<<16) + (data[25]<<24)
|
self.height = -self.data[22] - (self.data[23]<<8) - (self.data[24]<<16) - (self.data[25]<<24)
|
||||||
self.line = 0
|
self.line = 0
|
||||||
elif self.width>0 and len(data)==self.width*3:
|
logger.warning("@@@ IMAGE %d x %d" % (self.width, self.height))
|
||||||
out["pixels"] = base64.b64encode(data).decode('utf-8')
|
# Remove parsed data
|
||||||
out["line"] = self.line
|
del self.data[0:54]
|
||||||
self.line = self.line + 1
|
# Return parsed values
|
||||||
elif data[0]==ord(b' ') and data[1]==ord(b'['):
|
return {
|
||||||
out["message"] = data.decode()
|
"mode": "SSTV",
|
||||||
|
"width": self.width,
|
||||||
|
"height": self.height
|
||||||
|
}
|
||||||
|
|
||||||
out["width"] = self.width
|
# Parse debug messages enclosed in ' [...]'
|
||||||
out["height"] = self.height
|
elif len(self.data)>=2 and self.data[0]==ord(b' ') and self.data[1]==ord(b'['):
|
||||||
return out
|
# Wait until we find the closing bracket
|
||||||
|
w = self.data.find(b']')
|
||||||
|
if w>=0:
|
||||||
|
logger.warning("@@@ MESSAGE = '%s'" % str(self.data[0:w+1]))
|
||||||
|
# Compose result
|
||||||
|
return {
|
||||||
|
"mode": "SSTV",
|
||||||
|
"message": self.data[0:w+1].decode()
|
||||||
|
}
|
||||||
|
# Remove parsed data
|
||||||
|
del self.data[0:w+1]
|
||||||
|
# Return parsed values
|
||||||
|
return out
|
||||||
|
|
||||||
|
# Parse bitmap file data (scanlines)
|
||||||
|
elif self.width>0 and len(self.data)>=self.width*3:
|
||||||
|
logger.warning("@@@ LINE %d/%d..." % (self.line, self.height))
|
||||||
|
w = self.width * 3
|
||||||
|
# Compose result
|
||||||
|
out = {
|
||||||
|
"mode": "SSTV",
|
||||||
|
"pixels": base64.b64encode(self.data[0:w]).decode()
|
||||||
|
"line": self.line
|
||||||
|
"width": self.width
|
||||||
|
"height": self.height
|
||||||
|
}
|
||||||
|
# Advance scanline
|
||||||
|
self.line = self.line + 1
|
||||||
|
# If we reached the end of frame, finish scan
|
||||||
|
if self.line>=self.height:
|
||||||
|
self.width = 0
|
||||||
|
self.height = 0
|
||||||
|
self.line = 0
|
||||||
|
# Remove parsed data
|
||||||
|
del self.data[0:w]
|
||||||
|
# Return parsed values
|
||||||
|
return out
|
||||||
|
|
||||||
|
# Could not parse input data (yet)
|
||||||
|
return None
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("Exception while parsing SSTV data")
|
logger.exception("Exception while parsing SSTV data")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue