diff --git a/PyATEMMax/ATEMCommandHandlers.py b/PyATEMMax/ATEMCommandHandlers.py index 58bf8b3..13d05f6 100644 --- a/PyATEMMax/ATEMCommandHandlers.py +++ b/PyATEMMax/ATEMCommandHandlers.py @@ -902,5 +902,87 @@ def _handleTime(self) -> None: self._d.lastStateChange.timeCode.frame = self._inBuf.getU8(3) + def _handleLKST(self) -> None: + storeId = self._inBuf.getU8(1) + state = self._inBuf.getU8Flag(2,0) + self._sw.log.debug(f"[DBG] _handleLKST storeId {storeId} state {state}") + + + def _handleLKOB(self) -> None: + storeId = self._inBuf.getU8(1) + self._sw.log.debug(f"[DBG] _handleLKOB Lock obtained for storeId {storeId}") + + + def _handleFTDE(self) -> None: + error_msg = self._inBuf.getString(0, len(self._inBuf)) + self._sw.log.debug(f"[DBG] _handleFTDE error_msg: [{error_msg}]") + + + def _handleFTUA(self) -> None: + transferId = self._inBuf.getU16(0) + transferIndex = self._inBuf.getU8(3) + self._sw.log.debug(f"[DBG] _handleFTUA transferId: {transferId} transferIndex: {transferIndex}") + + + def _handleRXMS(self) -> None: + hyperDeckId = self._inBuf.getU16(0) # Values from 0 to 4 + + ipAddress = self._inBuf.getU32(4) + + inputId = self._inBuf.getU16(8) + autoRoll = self._inBuf.getU8Flag(10, 0) + autoRollFrameDelay = self._inBuf.getU16(12) # Values from 0 to 60 + + connStatus = self._inBuf.getU8(14) + + storageMediaCount = self._inBuf.getU16(16) + isRemoteEnabled = self._inBuf.getU8Flag(18, 0) + + + # self._sw.log.debug(f"""[DBG] _handleRXMS + # - hyperDeckId: [{hyperDeckId}] + # - ipAddress: [{ipAddress}] + # - inputId: [{inputId}] + # - autoRoll: [{autoRoll}] + # - autoRollFrameDelay: [{autoRollFrameDelay}] + # - connStatus: [{connStatus}] + # - storageMediaCount: [{storageMediaCount}] + # - isRemoteEnabled: [{isRemoteEnabled}] + # """) + # print(f"[DBG] {'-'*80}") + + def _handleNOTIMPLEMENTED(self) -> None: pass + +''' +namespace LibAtem.Commands.Settings.HyperDeck +{ + + [CommandName("RXMS", CommandDirection.ToClient, 20)] + public class HyperDeckSettingsGetCommand : SerializableCommandBase + { + [CommandId] + [Serialize(0), UInt16Range(0, 4)] + public uint Id { get; set; } + + [Serialize(4), IpAddress] + public string NetworkAddress { get; set; } + + [Serialize(8), Enum16] + public VideoSource Input { get; set; } + [Serialize(10), Bool] + public bool AutoRoll { get; set; } + [Serialize(12), UInt16Range(0, 60)] + public uint AutoRollFrameDelay { get; set; } + + [Serialize(14), Enum8] + public HyperDeckConnectionStatus Status { get; set; } + + [Serialize(16), UInt16] + public uint StorageMediaCount { get; set; } + [Serialize(18), Bool] + public bool IsRemoteEnabled { get; set; } + } +} +''' diff --git a/PyATEMMax/ATEMProtocol.py b/PyATEMMax/ATEMProtocol.py index 72882aa..d824763 100644 --- a/PyATEMMax/ATEMProtocol.py +++ b/PyATEMMax/ATEMProtocol.py @@ -162,6 +162,13 @@ class ATEMProtocol: "TlIn": 'Tally By Index', "TlSr": 'Tally By Source', "Time": 'Last State Change Time Code', + 'LKST': 'Lock State', + 'PLCK': 'Acquire Media Lock', + 'LKOB': 'Lock Obtained', + 'LOCK': 'Set Lock State', + 'FTDE': 'Data Transfer Error', + 'FTUA': 'Data Transfer Ack', + 'RXMS': 'HyperDeck Settings Get', # These commands are not really unknown, # but they are not implemented @@ -226,15 +233,10 @@ class ATEMProtocol: 'FTCD': 'Not implemented: Data Transfer Upload Continue', 'FTDa': 'Not implemented: Data Transfer Data', 'FTDC': 'Not implemented: Data Transfer Completed', - 'FTDE': 'Not implemented: Data Transfer Error', 'FTFD': 'Not implemented: Data File Description', 'FTSD': 'Not implemented: Data Transfer to Switcher', 'FTSU': 'Not implemented: Data Transfer Request', - 'FTUA': 'Not implemented: Data Transfer Ack', 'InCm': 'Not implemented: Initialization Completed', - 'LKOB': 'Not implemented: Lock Obtained', - 'LKST': 'Not implemented: Lock State', - 'LOCK': 'Not implemented: Set Lock State', 'MAct': 'Not implemented: Macro Action', 'MMOP': 'Not implemented: MMOP', 'MPSS': 'Not implemented: Media Player Source', @@ -242,13 +244,11 @@ class ATEMProtocol: 'MSlp': 'Not implemented: Macro Add Pause', 'MSRc': 'Not implemented: Macro Start Recording', 'MvVM': 'Not implemented: MvVM', - 'PLCK': 'Not implemented: Acquire Media Lock', 'PZCS': 'Not implemented: PZCS', 'RAMP': 'Not implemented: Reset Audio Mixer Peaks', 'RFlK': 'Not implemented: Run Flying Key', 'RXCC': 'Not implemented: RXCC', 'RXCP': 'Not implemented: RXCP', - 'RXMS': 'Not implemented: RXMS', 'RXSS': 'Not implemented: RXSS', 'SALN': 'Not implemented: Audio Levels', 'SCPS': 'Not implemented: Clip Player', diff --git a/PyATEMMax/ATEMSetterMethods.py b/PyATEMMax/ATEMSetterMethods.py index bfff47c..8f133e6 100644 --- a/PyATEMMax/ATEMSetterMethods.py +++ b/PyATEMMax/ATEMSetterMethods.py @@ -4089,3 +4089,76 @@ def setResetAudioMixerPeaksMaster(self, master: bool) -> None: self.switcher._outBuf.setU8Flag(0, 2) self.switcher._outBuf.setU8(4, master) self.switcher._finishCommandPacket() + + + # ------------------------------------------------------------------------ + + + def sendSetLockState(self, storeId: int, state: bool) -> None: + """Send Set Lock State + + Args: + storeId: 0:Still / 1:Clip1 / 2:Clip2 / 3:MV_labels / 255:Macro + state: + """ + + print(f"[DBG] Sending Set Lock State !!!") + self.switcher._prepareCommandPacket("LOCK", 4) + self.switcher._outBuf.setU8(1, storeId) + self.switcher._outBuf.setU8(2, state) + self.switcher._finishCommandPacket() + + + def sendAcquireMediaLock(self, storeId: int, index: int) -> None: + """Acquire Media Lock + + Args: + storeId: 0:Still / 1:Clip1 / 2:Clip2 / 3:MV_labels / 255:Macro + index: + """ + + print(f"[DBG] Acquiring Media Lock !!!") + self.switcher._prepareCommandPacket("PLCK", 8) + self.switcher._outBuf.setU8(1, storeId) + self.switcher._outBuf.setU8(3, index) + self.switcher._outBuf.setU8(4, 0xFD) # command ? + self.switcher._outBuf.setU8(5, 0x01) # command ? + self.switcher._finishCommandPacket() + + + def sendDataTransferRequest(self, transferId: int, storeId: int, index: int) -> None: + """Send Data Transfer Request + + Args: + transferId: + storeId: 0:Still / 1:Clip1 / 2:Clip2 / 3:MV_labels / 255:Macro + index: + """ + + print(f"[DBG] Sending data transfer request !!!") + self.switcher._prepareCommandPacket("FTSU", 12) + self.switcher._outBuf.setU16(0, transferId) + self.switcher._outBuf.setU8(2, storeId) + self.switcher._outBuf.setU8(7, index) + self.switcher._outBuf.setU8(8, 0x03 if storeId == 0xff else 0) + self.switcher._finishCommandPacket() + + + def sendInitDownloadToSwitcherRequest(self, transferId: int, storeId: int, index: int, data_size: int) -> None: + """Init Download to switcher Request + + Args: + transferId: + storeId: 0:Still / 1:Clip1 / 2:Clip2 / 3:MV_labels / 255:Macro + index: + data_size: size of data to be sent + """ + + print(f"[DBG] Sending init download request !!!") + self.switcher._prepareCommandPacket("FTSD", 16) + self.switcher._outBuf.setU16(0, transferId) + self.switcher._outBuf.setU8(2, storeId) + self.switcher._outBuf.setU8(7, index) + self.switcher._outBuf.setU32(8, data_size) + self.switcher._outBuf.setU8(13, 0x01) # 0x01 == write, 0x02 == Clear + self.switcher._finishCommandPacket()