pecanpico9/decoder/image.py

132 wiersze
3.5 KiB
Python

import binascii
import urllib.request
import urllib.error
from datetime import datetime
from subprocess import *
import time
import threading
from shutil import copyfile
import base91
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
imageProcessor = None
imageData = {}
lock = threading.RLock()
def imgproc():
global imageData
while True:
with lock:
for _id in imageData:
(call, data) = imageData[_id]
filename = 'html/images/%s-%d.jpg' % (call.replace('-',''), _id)
f = open(filename, 'wb')
process = Popen(['./ssdv', '-d'], stdin=PIPE, stdout=f, stderr=PIPE)
process.stdin.write(data)
dummy,err = process.communicate()
f.close()
filename2 = 'html/images/%s.jpg' % (call.replace('-',''))
copyfile(filename, filename2)
imageData = {} # Clear data
time.sleep(1)
w = time.time()
def insert_image(sqlite, receiver, call, data_b91):
global imageProcessor,imageData,w
data = base91.decode(data_b91)
if len(data) != 174:
return # APRS message has invalid type or length (or both)
cur = sqlite.cursor()
# Decode various meta data
imageID = data[0]
packetID = (data[1] << 8) | data[2]
data = binascii.hexlify(data[3:]).decode("ascii")
# 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 = ('68%08x%02x%04x' % (encode_callsign(bcall), imageID, packetID)) + data
data += "%08x" % (binascii.crc32(binascii.unhexlify(data)) & 0xffffffff)
timd = int(datetime.now().timestamp())
# Find image ID (or generate new one)
_id = None
cur.execute("SELECT id,packetID FROM image WHERE call = ? AND imageID = ? AND rxtime+15*60 >= ? ORDER BY rxtime DESC LIMIT 1", (call, imageID, timd))
fetch = cur.fetchall()
if len(fetch):
_id = fetch[0][0]
lastPacketId = fetch[0][1]
if _id is None or lastPacketId > packetID:
# Generate ID
cur.execute("SELECT id+1 FROM image ORDER BY id DESC LIMIT 1")
fetch = cur.fetchall()
if len(fetch):
_id = fetch[0][0]
else: # No entries in the database
_id = 0
# Debug
print('Received image packet Call=%s ImageID=%d PacketID=%d ServerID=%d' % (call, imageID, packetID, _id))
# Insert into database
cur.execute("""
INSERT OR IGNORE INTO image (call,rxtime,imageID,packetID,data,id)
VALUES (?,?,?,?,?,?)""",
(call, timd, imageID, packetID, data, _id)
)
if w+0.5 < time.time():
sqlite.commit()
w = time.time()
with lock:
cur.execute("SELECT GROUP_CONCAT('55' || data || '"+(144*'0')+"', '') FROM image WHERE id = ? GROUP BY id ORDER BY packetID", (_id,))
data = cur.fetchall()[0][0]
imageData[_id] = (call, binascii.unhexlify(data))
if imageProcessor is None:
imageProcessor = threading.Thread(target=imgproc)
imageProcessor.start()