Läuft die Voice Acoustic VA-Remotecontrol (AllDSP AllControl) nativ unter Linux auf echtem wxGTK 3.0 — ohne Wine und ohne dekompilierten App-Code. Ausgeführt wird das unveränderte Python-2.7-Bytecode aus dem macOS-.app; C-Extensions (wxGTK/numpy/ scipy/PortAudio) kommen nativ aus Debian stretch. Enthält: va/ (Original-.pyc + pure-Python-Libs + Assets + launch.py mit den drei Linux-Fixes), Dockerfile/run.sh/entrypoint.sh, reference/ (dekompilierter Quellcode zum Debuggen) und README/STATUS. img.cache (378 MB, regenerierbar) ist per .gitignore ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
275 lines
12 KiB
Python
275 lines
12 KiB
Python
# uncompyle6 version 3.9.3
|
|
# Python bytecode version base 2.6 (62161)
|
|
# Decompiled from: Python 3.9.25 (main, Oct 31 2025, 23:16:49)
|
|
# [GCC 14.2.0]
|
|
# Embedded file name: d_bootloader.pyc
|
|
# Compiled at: 2023-05-16 13:01:50
|
|
import socket, collections, mytime, threading, sys, copy, struct, types, d_protocol, os.path, traceback, main, one_unit, wx
|
|
from definitions import *
|
|
|
|
def getString(str):
|
|
return one_unit.getString(str)
|
|
|
|
|
|
mac_names = 'posix'
|
|
|
|
def check_interfaces():
|
|
if os.name in mac_names:
|
|
return
|
|
import subprocess
|
|
startupinfo = subprocess.STARTUPINFO()
|
|
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
|
|
args = [
|
|
'ipconfig']
|
|
run = subprocess.Popen(args, stdout=subprocess.PIPE, startupinfo=startupinfo)
|
|
pfile = run.stdout
|
|
res = pfile.read()
|
|
pfile.close()
|
|
if res.count('IP Address') > 1:
|
|
wx.MessageBox('Warning: You have multiple network interfaces connected. This may lead to problems during upload. It is strongly recommended to disconnect all but one interface.')
|
|
return
|
|
|
|
|
|
class Bootloader:
|
|
|
|
def __init__(self, parent):
|
|
self.thread = threading.Thread(name='AllDSP Server Bootloader Detection', target=self.process)
|
|
self.thread.daemon = True
|
|
self.parent = parent
|
|
self.channel = None
|
|
self.erasecounter = 0
|
|
self.MAC = 'Bootloader'
|
|
self.lastPrintTime = 0
|
|
return
|
|
|
|
def process(self):
|
|
one_unit.lowPriority()
|
|
PORT = 30684
|
|
reported_error = False
|
|
while one_unit.app.application_stopping == False:
|
|
try:
|
|
s.close()
|
|
del s
|
|
mytime.sleep(1)
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
s.bind(('', PORT))
|
|
s.settimeout(0.01)
|
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
|
one_unit.app.bootloader_ok = True
|
|
except:
|
|
if reported_error == False:
|
|
print mytime.displayTime() + ' Bootloader Server Failed'
|
|
traceback.print_exc(file=sys.stdout)
|
|
reported_error = True
|
|
mytime.sleep(1)
|
|
continue
|
|
|
|
self.clients = {}
|
|
self.erasecounter = 0
|
|
while one_unit.app.application_stopping == False:
|
|
mytime.sleep(0.01)
|
|
try:
|
|
(new_pkt, addr) = s.recvfrom(4096)
|
|
one_unit.app.bootloader_last_rx = mytime.clock()
|
|
self.addr = addr
|
|
self.stopping = False
|
|
self.action = 'start_main_update'
|
|
self.completion = 'erasing'
|
|
if ord(new_pkt[0]) == 0 and ord(new_pkt[1]) == 1 and ord(new_pkt[2]) == 66 and ord(new_pkt[3]) == 76:
|
|
skin_high = unicode(ord(new_pkt[4]))
|
|
skin_mid = unicode(ord(new_pkt[5]))
|
|
skin_low = unicode(ord(new_pkt[6]))
|
|
self.broadcasted_skin = skin_high + '_' + skin_mid + '_' + skin_low
|
|
else:
|
|
break
|
|
skinBeforeReplacement = ':' + skin_high + '.' + skin_mid + '.' + skin_low
|
|
try:
|
|
self.broadcasted_skin = one_unit.app.type_replacements[self.broadcasted_skin]
|
|
except:
|
|
pass
|
|
|
|
unit = d_protocol.RemoteUnit()
|
|
unit.MAC = 'Startup...'
|
|
unit.IP = 'Startup...'
|
|
unit.type = self.broadcasted_skin
|
|
unit.name = 'Startup...'
|
|
unit.pkt = None
|
|
unit.link_type = 'Ethernet'
|
|
unit.link_status = 'Bootloader'
|
|
unit.HWVersion = 'Unknown'
|
|
unit.PICVersion = 'Unknown'
|
|
unit.Serial = 'Unknown'
|
|
unit.DSPState = 0
|
|
unit.ProductionDate = 'Unknown'
|
|
unit.originalSwID = skin_high + '.' + skin_mid + '.' + skin_low + skinBeforeReplacement
|
|
self.parent.peers.add(unit)
|
|
if one_unit.app.enable_bootloader == False:
|
|
continue
|
|
print mytime.displayTime() + ' d_b.Entering bootloader'
|
|
check_interfaces()
|
|
one_unit.updateBootloaderDial('Bootloader', getString('eif'), statusInfo=infoStatusInterfaceUpdate | infoStatusResetOK | infoStatusRunning)
|
|
(ip, port) = addr
|
|
self.ip = ip
|
|
ip = '<broadcast>'
|
|
addr = (ip, port)
|
|
while one_unit.app.application_stopping == False:
|
|
if self.action != None:
|
|
self.upload_ethernet_firmware(s, addr)
|
|
mytime.sleep(0.01)
|
|
continue
|
|
else:
|
|
break
|
|
|
|
break
|
|
except:
|
|
pass
|
|
|
|
try:
|
|
s.close()
|
|
except:
|
|
pass
|
|
|
|
if one_unit.app.application_stopping == False:
|
|
mytime.sleep(5)
|
|
|
|
return
|
|
|
|
def start(self):
|
|
"""Start the updating thread"""
|
|
self.stopping = False
|
|
self.thread.start()
|
|
return
|
|
|
|
def upload_ethernet_firmware(self, s, addr):
|
|
if self.action == 'start_main_update':
|
|
if self.completion == 'erasing':
|
|
counter = 1000
|
|
while counter > 0:
|
|
counter -= 1
|
|
try:
|
|
new_pkt = s.recv(4096)
|
|
except:
|
|
break
|
|
|
|
cmd = chr(0) + chr(2) + 'dddd.dfi' + chr(0) + 'netascii' + chr(0)
|
|
try:
|
|
s.sendto(cmd, addr)
|
|
except:
|
|
print mytime.displayTime() + ' Bootloader Send Failed:', addr
|
|
return
|
|
else:
|
|
self.update_start_time = mytime.clock()
|
|
if mytime.clock() - self.lastPrintTime > 1:
|
|
self.lastPrintTime = mytime.clock()
|
|
print mytime.displayTime() + ' Erasing Interface....'
|
|
start_time = mytime.clock()
|
|
while True:
|
|
try:
|
|
new_pkt = s.recv(4096)
|
|
except:
|
|
mytime.sleep(0.1)
|
|
print mytime.displayTime() + ' No packet received'
|
|
new_pkt = None
|
|
|
|
if new_pkt != None:
|
|
break
|
|
if mytime.clock() - start_time > 10:
|
|
print mytime.clock(), start_time
|
|
break
|
|
|
|
if new_pkt != None and ord(new_pkt[0]) == 0 and ord(new_pkt[1]) == 4:
|
|
print mytime.displayTime() + ' Erase OK,Starting Upload'
|
|
self.completion = 1
|
|
try:
|
|
datafile = open(os.path.normpath(one_unit.app.cwd + '/dfi/' + self.broadcasted_skin + '.dfe'), 'rb')
|
|
self.data = datafile.read()
|
|
datafile.close()
|
|
print mytime.displayTime() + ' Uploading custom interface firmware:', self.broadcasted_skin + '.dfe'
|
|
except:
|
|
try:
|
|
datafile = open(os.path.normpath(one_unit.app.cwd + '/dfi/0_0_0.dfe'), 'rb')
|
|
self.data = datafile.read()
|
|
datafile.close()
|
|
except:
|
|
self.data = ''
|
|
print mytime.displayTime() + ' Unsupported interface type:', self.broadcasted_skin
|
|
self.action = None
|
|
one_unit.updateBootloaderDial('Bootloader', getString('uif'), statusInfo=infoStatusInterfaceUpdate | infoStatusUnsupported | infoStatusFinished | enableClose)
|
|
return
|
|
|
|
else:
|
|
self.length = int(len(self.data) / 512)
|
|
elif new_pkt.find('Access violation') < 0:
|
|
print mytime.displayTime() + ' d_b.Invalid Packet!', new_pkt
|
|
self.erasecounter -= 0.9
|
|
if self.erasecounter > 100:
|
|
self.action = None
|
|
one_unit.updateBootloaderDial('Bootloader', getString('efi'), statusInfo=infoStatusInterfaceUpdate | infoStatusEraseFailed | infoStatusFinished | enableClose)
|
|
print mytime.displayTime() + ' Bootloader Erase Failed'
|
|
self.erasecounter += 1
|
|
return
|
|
self.erasecounter = 0
|
|
one_unit.updateBootloaderDial('Bootloader', getString('ifu') + ' (' + str(self.completion * 100 / self.length) + '%)', alwaysUpdate=False)
|
|
if mytime.clock() - self.lastPrintTime > 1:
|
|
self.lastPrintTime = mytime.clock()
|
|
print mytime.displayTime() + ' (1) Uploading (' + str(self.completion * 100 / self.length) + '%)', 'Bootloader'
|
|
block_high = int(self.completion / 256)
|
|
block_low = self.completion - block_high * 256
|
|
start = (self.completion - 1) * 512
|
|
end = start + 512
|
|
if end >= len(self.data) - 1:
|
|
last = True
|
|
cmd = chr(0) + chr(3) + chr(block_high) + chr(block_low) + self.data[start:]
|
|
else:
|
|
last = False
|
|
cmd = chr(0) + chr(3) + chr(block_high) + chr(block_low) + self.data[start:end]
|
|
string = ''
|
|
for i in cmd:
|
|
string += hex(ord(i)) + ':'
|
|
|
|
s.sendto(cmd, addr)
|
|
start_time = mytime.clock()
|
|
send_time = mytime.clock()
|
|
while True:
|
|
mytime.sleep(0.01)
|
|
try:
|
|
new_pkt = s.recv(64)
|
|
except:
|
|
new_pkt = None
|
|
|
|
if new_pkt != None and ord(new_pkt[0]) == 0 and ord(new_pkt[1]) == 4 and ord(new_pkt[2]) == block_high and ord(new_pkt[3]) == block_low:
|
|
break
|
|
if mytime.clock() - send_time > 0.5:
|
|
send_time = mytime.clock()
|
|
try:
|
|
s.sendto(cmd, addr)
|
|
except:
|
|
pass
|
|
|
|
if mytime.clock() - start_time > 5:
|
|
print mytime.displayTime() + ' Timeout!'
|
|
one_unit.updateBootloaderDial('Bootloader', getString('itwf'), statusInfo=infoStatusInterfaceUpdate | infoStatusWriteFailed | infoStatusFinished | enableClose)
|
|
break
|
|
|
|
if new_pkt != None and ord(new_pkt[0]) == 0 and ord(new_pkt[1]) == 4 and ord(new_pkt[2]) == block_high and ord(new_pkt[3]) == block_low:
|
|
self.completion += 1
|
|
if last == True:
|
|
one_unit.updateBootloaderDial('Bootloader', 'Finished')
|
|
print mytime.displayTime() + ' Finished in', round(mytime.clock() - self.update_start_time, 1), 'seconds'
|
|
mytime.sleep(1)
|
|
self.action = None
|
|
if one_unit.app.bootloader_mode == False:
|
|
one_unit.app.enable_bootloader = False
|
|
return
|
|
else:
|
|
return
|
|
|
|
|
|
|
|
# okay decompiling pycode/d_bootloader.pyc
|