pecanpico9/decoder/image.py

126 wiersze
3.9 KiB
Python

import binascii
import urllib.request
import urllib.error
import datetime
from position import decode_position
from subprocess import *
jsons = []
def decode_callsign(code):
callsign = ''
while code > 0:
s = code % 40
if s == 0: callsign += '-'
elif s < 11: callsign += chr(47 + s)
elif s < 14: callsign += '-'
else: callsign += chr(51 + s)
code /= 40
return callsign
def encode_callsign(callsign):
x = 0
for i in range(len(callsign)-1,-1,-1):
x *= 40
c = ord(callsign[i])
if c >= 65 and c <= 90: x += c - 51
elif c >= 97 and c <= 122: x += c - 83
elif c >= 48 and c <= 57: x += c - 47
return x
"""
Decodes an APRS/SSDV image packet (APRS header must be removed already)
sqlite - Database handle
reciever - The call of the receiving station
call - The call of the transmitter
data - Binary data
"""
def insert_image(sqlite, receiver, call, tim, posi, data, server, grouping):
global jsons
if len(data) != 214:
return # APRS message sampled too short
# Encode callsign (ensure callsign has no more than 6 chars)
bcall = call.split('-') # Split callsign and SSID
if len(bcall) == 1: # No SSID available, so take the callsign
bcall = bcall[0][0:6]
elif(len(bcall[0]) < 5): # Callsign has 4 chars, so take it with the SSID
bcall = bcall[0] + bcall[1][0:2]
elif(len(bcall[0]) < 6): # Callsign has 5 chars, so take it with the last digit of the SSID
bcall = bcall[0] + bcall[1][-1]
else:
bcall = bcall[0][0:6] # Callsign has 6 chars, so take the call without SSID
data = binascii.unhexlify('66%08x' % encode_callsign(bcall)) + data
# Calculate CRC for SSDV server
crc = binascii.crc32(data) & 0xffffffff
# Create message for SSDV server (and save to array)
ssdv = '55' + binascii.hexlify(data).decode("ascii") + ('%08x' % crc) + (64*'0')
jsons.append("""{
\"type\": \"packet\",
\"packet\": \"""" + ssdv + """\",
\"encoding\": \"hex\",
\"received\": \"""" + datetime.datetime.now().isoformat('T')[:19] + """Z\",
\"receiver\": \"""" + receiver + """\"
}""")
# Decode various meta data
timd,x,y,z,dummy = decode_position(tim, posi, None)
imageID = data[5]
packetID = (data[6] << 8) | data[7]
# Debug
print('Received packet from %s image %d packet %d' % (call, imageID, packetID))
# Insert
sqlite.cursor().execute("""
INSERT OR REPLACE INTO image (call,time,imageID,packetID,lat,lon,alt,data)
VALUES (?,?,?,?,?,?,?,?)""",
(call, int(timd.timestamp()), imageID, packetID, y, x, int(z), ssdv)
)
sqlite.commit()
# SSDV decode
cur = sqlite.cursor()
cur.execute("SELECT GROUP_CONCAT(data,'') FROM image WHERE call = ? AND imageID = ? AND time = ? GROUP BY imageID ORDER BY packetID", (call, imageID, int(timd.timestamp())))
name = 'html/images/%s-%d-%d.jpg' % (call.replace('-',''), int(timd.timestamp()), imageID)
f = open(name, 'wb')
process = Popen(['./ssdv', '-d'], stdin=PIPE, stdout=f, stderr=PIPE)
process.stdin.write(binascii.unhexlify(cur.fetchall()[0][0]))
dummy,err = process.communicate()
f.close()
if len(jsons) >= grouping: # Enough packets collected, send them all to the server
req = urllib.request.Request(server)
req.add_header('Content-Type', 'application/json')
json = "{\"type\":\"packets\",\"packets\":[" + ",".join(jsons) + "]}" # Group all SSDV packets into a big JSON
jsons = []
try:
error = True
while error:
print('Send to SSDV data server')
try:
result = urllib.request.urlopen(req, "".join(json.split(' ')).encode("ascii")) # Send packets to server
print('Response from Server: OK')
error = False
except urllib.error.URLError as error:
if error.code == 400:
print('Response from Server: %s', error.read())
error = False
else:
print('SSDV-Server connection error... try again')
except urllib.error.HTTPError as error: # The server did not like our packets :(
print('Send to SSDV data server: failed (the server did not like our packets :( )')
print(error.read())