diff --git a/proxyclient/experiments/aop.py b/proxyclient/experiments/aop.py deleted file mode 100755 index 0dba36fb..00000000 --- a/proxyclient/experiments/aop.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: MIT -import sys, pathlib -sys.path.append(str(pathlib.Path(__file__).resolve().parents[1])) - -import struct -import traceback -from construct import * - -from m1n1.setup import * -from m1n1.shell import run_shell -from m1n1.hw.dart import DART, DARTRegs -from m1n1.fw.asc import StandardASC, ASCDummyEndpoint -from m1n1.fw.asc.base import * -from m1n1.fw.aop import * -from m1n1.fw.aop.ipc import * -from m1n1.fw.afk.rbep import * -from m1n1.fw.afk.epic import * - -# Set up a secondary proxy channel so that we can stream -# the microphone samples -p.usb_iodev_vuart_setup(p.iodev_whoami()) -p.iodev_set_usage(IODEV.USB_VUART, USAGE.UARTPROXY) - -p.pmgr_adt_clocks_enable("/arm-io/dart-aop") - -adt_dc = u.adt["/arm-io/aop/iop-aop-nub/aop-audio/dc-2400000"] - -pdm_config = Container( - unk1=2, - clockSource=u'pll ', - pdmFrequency=2400000, - unk3_clk=24000000, - unk4_clk=24000000, - unk5_clk=24000000, - channelPolaritySelect=256, - unk7=99, - unk8=1013248, - unk9=0, - ratios=Container( - r1=15, - r2=5, - r3=2, - ), - filterLengths=0x542c47, - coeff_bulk=120, - coefficients=GreedyRange(Int32sl).parse(adt_dc.coefficients), - unk10=1, - micTurnOnTimeMs=20, - unk11=1, - micSettleTimeMs=50, -) - -decimator_config = Container( - latency=15, - ratios=Container( - r1=15, - r2=5, - r3=2, - ), - filterLengths=0x542c47, - coeff_bulk=120, - coefficients=GreedyRange(Int32sl).parse(adt_dc.coefficients), -) - -class AFKEP_Hello(AFKEPMessage): - TYPE = 63, 48, Constant(0x80) - UNK = 7, 0 - -class AFKEP_Hello_Ack(AFKEPMessage): - TYPE = 63, 48, Constant(0xa0) - -class EPICEndpoint(AFKRingBufEndpoint): - BUFSIZE = 0x1000 - - def __init__(self, *args, **kwargs): - self.seq = 0x0 - self.wait_reply = False - self.ready = False - super().__init__(*args, **kwargs) - - @msg_handler(0x80, AFKEP_Hello) - def Hello(self, msg): - self.rxbuf, self.rxbuf_dva = self.asc.ioalloc(self.BUFSIZE) - self.txbuf, self.txbuf_dva = self.asc.ioalloc(self.BUFSIZE) - - self.send(AFKEP_Hello_Ack()) - - def handle_hello(self, hdr, sub, fd): - if sub.type != 0xc0: - return False - - payload = fd.read() - name = payload.split(b"\0")[0].decode("ascii") - self.log(f"Hello! (endpoint {name})") - self.ready = True - return True - - def handle_reply(self, hdr, sub, fd): - if self.wait_reply: - self.pending_call.read_resp(fd) - self.wait_reply = False - return True - return False - - def handle_ipc(self, data): - fd = BytesIO(data) - hdr = EPICHeader.parse_stream(fd) - sub = EPICSubHeaderVer2.parse_stream(fd) - - handled = False - - if sub.category == EPICCategory.REPORT: - handled = self.handle_hello(hdr, sub, fd) - if sub.category == EPICCategory.REPLY: - handled = self.handle_reply(hdr, sub, fd) - - if not handled and getattr(self, 'VERBOSE', False): - self.log(f"< 0x{hdr.channel:x} Type {hdr.type} Ver {hdr.version} Tag {hdr.seq}") - self.log(f" Len {sub.length} Ver {sub.version} Cat {sub.category} Type {sub.type:#x} Ts {sub.timestamp:#x}") - self.log(f" Unk1 {sub.unk1:#x} Unk2 {sub.unk2:#x}") - chexdump(fd.read()) - - def indirect(self, call, chan=0x1000000d, timeout=0.1): - tx = call.ARGS.build(call.args) - self.asc.iface.writemem(self.txbuf, tx[4:]) - - cmd = self.roundtrip(IndirectCall( - txbuf=self.txbuf_dva, txlen=len(tx) - 4, - rxbuf=self.rxbuf_dva, rxlen=self.BUFSIZE, - retcode=0, - ), category=EPICCategory.COMMAND, typ=call.TYPE) - fd = BytesIO() - fd.write(struct.pack(" pw1 -> pwrd state. it starts capturing at pwrd +# shutdown sequence must also be pwrd -> pw1 -> idle + +def aop_start(): + aop.audio.send_notify(SetDeviceProp( + devid=u'hpai', + modifier=202, + data=Container( + devid=u'hpai', + cookie=2, + target_pstate=u'pwrd', + unk2=1, + ) + )) + +def aop_stop(): + aop.audio.send_notify(SetDeviceProp( + devid='hpai', + modifier=202, + data=Container( + devid='hpai', + cookie=3, + target_pstate='pw1 ', + unk2=1, + ) + )) + + aop.audio.send_notify(SetDeviceProp( + devid='hpai', + modifier=202, + data=Container( + devid='hpai', + cookie=4, + target_pstate='idle', + unk2=0, + ) + )) + +def main(): + aop.start() + for epno in [0x20, 0x21, 0x22, 0x24, 0x25, 0x26, 0x27, 0x28]: + aop.start_ep(epno) + aop.work_for(0.3) + audep = aop.audio + + audep.send_notify(AttachDevice(devid='hpai')) # high power audio input; actual mic + audep.send_notify(AttachDevice(devid='lpai')) # low power audio input; voice trigger mic + audep.send_notify(AttachDevice(devid='pdm0')) # leap: low-energy audio processor I think + # [syslog] * [udioPDMNodeBase.cpp:554]PDMDev off ->xi0 , 0->2400000 AP state 1 + + # initChannelControl (<7, 7, 1, 7>) + audep.send_notify(SetDeviceProp(devid='lpai', modifier=301, data=Container(unk1=7, unk2=7, unk3=1, unk4=7))) + audep.send_notify(SetDeviceProp(devid='pdm0', modifier=200, data=pdm_config)) + audep.send_notify(SetDeviceProp(devid='pdm0', modifier=210, data=decimator_config)) + ret = audep.send_roundtrip(AudioPropertyState(devid="hpai")) + print("hpai state: %s" % (ret.state)) # idle + + audep.send_notify(SetDeviceProp( + devid='hpai', + modifier=202, + data=Container( + devid='hpai', + cookie=1, + target_pstate='pw1 ', + unk2=0, + ) + )) + + ret = audep.send_roundtrip(AudioPropertyState(devid="hpai")) + print("hpai state: %s" % (ret.state)) + assert(ret.state == "pw1 ") + +try: + main() + pass +except KeyboardInterrupt: + pass + +run_shell(locals(), poll_func=aop.work) diff --git a/proxyclient/m1n1/fw/aop/ipc.py b/proxyclient/m1n1/fw/aop/ipc.py index e7ac9c1d..54dbdc48 100644 --- a/proxyclient/m1n1/fw/aop/ipc.py +++ b/proxyclient/m1n1/fw/aop/ipc.py @@ -118,6 +118,30 @@ class WrappedCall(EPICCall): self.dump() raise ValueError(f"retcode {self.rets.retcode} in {str(type(self))} (call dumped, see above)") +@reg_calltype +class AudioProbeDevice(EPICCall): + TYPE = 0x20 + SUBTYPE = 0xc3_00_00_01 + ARGS = Struct( + "pad" / Const(0x0, Int32ul), + "unk1" / Hex(Const(0xffffffff, Int32ul)), + "subtype" / Hex(Const(0xc3000001, Int32ul)), + "pad2" / ZPadding(16), + "cookie" / Default(Hex(Int32ul), 0), + "len" / Hex(Const(0x28, Int64ul)), + "devno" / Int32ul, + ) + RETS = Struct( + "retcode" / Const(0x0, Int32ul), + "devid" / FourCC, + "format" / FourCC, + "sample_rate" / Int32ul, + "channels" / Int32ul, + "bytes_per_sample" / Int32ul, + "unk_1f" / Default(Hex(Int32ul), 0), + "unk" / Array(51, Default(Hex(Int32ul), 0)), + ) + @WrappedCall.reg_subclass class AttachDevice(WrappedCall): CALLTYPE = 0xc3_00_00_02 @@ -246,6 +270,96 @@ DEVPROPS = { ), } +class AudioPropertyKey(IntEnum): + STATE = 200 # 0xc8 + POWER = 202 # 0xca + MAIN = 203 # 0xcb + FORMAT = 302 # 0x12e + +@reg_calltype +class AudioProperty(EPICCall): + TYPE = 0x20 + SUBTYPE = 0xc3000004 + SUBCLASSES = {} + + @classmethod + def subclass(cls, cls2): + cls.SUBCLASSES[int(cls2.SUBTYPE)] = cls2 + return cls2 + +@AudioProperty.subclass +class AudioPropertyState(AudioProperty): + SUBSUBTYPE = AudioPropertyKey.STATE + ARGS = Struct( + "pad" / Const(0x0, Int32ul), + "unk1" / Hex(Const(0xffffffff, Int32ul)), + "calltype" / Hex(Const(0xc3000004, Int32ul)), + "blank2" / ZPadding(16), + "cookie" / Default(Hex(Int32ul), 0), + "len" / Hex(Const(0x30, Int64ul)), + "devid" / FourCC, + "modifier" / Const(AudioPropertyKey.STATE, Int32ul), + "data" / Const(0x1, Int32ul), + ) + RETS = Struct( + "retcode" / Const(0x0, Int32ul), + "size" / Const(4, Int32ul), + "state" / FourCC, + ) + +@AudioProperty.subclass +class AudioPropertyFormat(AudioProperty): + SUBSUBTYPE = AudioPropertyKey.FORMAT + ARGS = Struct( + "pad" / Const(0x0, Int32ul), + "unk1" / Hex(Const(0xffffffff, Int32ul)), + "calltype" / Hex(Const(0xc3000004, Int32ul)), + "blank2" / ZPadding(16), + "cookie" / Default(Hex(Int32ul), 0), + "len" / Hex(Const(0x30, Int64ul)), + "devid" / FourCC, + "modifier" / Const(AudioPropertyKey.FORMAT, Int32ul), + "data" / Const(0x1, Int32ul), + ) + RETS = Struct( + "retcode" / Const(0x0, Int32ul), + "format" / Int32ul, # 16 == float32? + "fourcc" / FourCC, # PCML + "sample_rate" / Int32ul, # 16000 + "channels" / Int32ul, # 3 + "bytes_per_sample" / Int32ul, # 2 + ) + +AudioPowerSetting = Struct( + "devid" / FourCC, + "unk1" / Int32ul, + "cookie" / Default(Hex(Int32ul), 0), + "blank" / ZPadding(8), + "target_pstate" / FourCC, + "unk2" / Int32ul, + "blank2" / ZPadding(20), +) + +@AudioProperty.subclass +class AudioPropertyPower(AudioProperty): + SUBSUBTYPE = AudioPropertyKey.POWER + ARGS = Struct( + "pad" / Const(0x0, Int32ul), + "unk1" / Hex(Const(0xffffffff, Int32ul)), + "calltype" / Hex(Const(0xc3000005, Int32ul)), + "blank2" / ZPadding(16), + "cookie" / Default(Hex(Int32ul), 0), + "len" / Hex(Const(0x30 + 0x30, Int64ul)), # len(this.data) + 0x30 + "devid" / FourCC, + "modifier" / Const(AudioPropertyKey.POWER, Int32ul), + "len2" / Hex(Const(0x30, Int32ul)), # len(this.data) + "data" / AudioPowerSetting, + ) + RETS = Struct( + "retcode" / Const(0x0, Int32ul), + "value" / HexDump(GreedyBytes), + ) + @WrappedCall.reg_subclass class GetDeviceProp(WrappedCall): CALLTYPE = 0xc3_00_00_04