Sends a "standard CMD write" packet :param cmd: 2 byte CMD code :param cmd_param: 4 byte parameter that gets sent together with CMD (for spi_* commands, the address needs to be passed in as big-endian) :param data: payload :param dataLen: payload length
(self, cmd: int, cmd_param: int = 0, data: bytes = b'\x00', dataLen: int = -1)
| 138 | return bytes(res) |
| 139 | |
| 140 | def _standard_cmd_write(self, cmd: int, cmd_param: int = 0, data: bytes = b'\x00', dataLen: int = -1): |
| 141 | """ |
| 142 | Sends a "standard CMD write" packet |
| 143 | |
| 144 | :param cmd: 2 byte CMD code |
| 145 | :param cmd_param: 4 byte parameter that gets sent together with CMD (for spi_* commands, the address needs to be passed in as big-endian) |
| 146 | :param data: payload |
| 147 | :param dataLen: payload length |
| 148 | """ |
| 149 | if dataLen == -1: |
| 150 | dataLen = len(data) |
| 151 | |
| 152 | cmd_param = struct.unpack('<I', struct.pack('>I', cmd_param))[0] # switch endinanness |
| 153 | |
| 154 | # If there is no payload, send the 8 byte command immediately |
| 155 | if (dataLen == 0 or data == b'\x00'): |
| 156 | # send 1d00 with cmd |
| 157 | d = struct.pack("<H", cmd) |
| 158 | d += struct.pack(">I2x", cmd_param) |
| 159 | log.debug(f's_cmd_w {0x1d00:#x} ({len(d):2}) {d.hex()}') |
| 160 | self._dev.ctrl_transfer(0x41, 0x45, 0x78, 0x1d00, d) |
| 161 | self._block_until_camera_ready() |
| 162 | return |
| 163 | |
| 164 | outer_chunk_size = 0x100 |
| 165 | inner_chunk_size = 0x40 |
| 166 | |
| 167 | # A "camera command" can be 256 bytes long max, but we can split the data and |
| 168 | # send more with an incremented address parameter (only spi_read/write actually uses that afaik) |
| 169 | # (adress parameter is big endian, but others are either little endian or only one byte in initial_data[2]) |
| 170 | for i in range(0, dataLen, outer_chunk_size): |
| 171 | outer_chunk = data[i:i+outer_chunk_size] |
| 172 | |
| 173 | # Send initial "camera command" |
| 174 | initial_data = struct.pack("<H", cmd) |
| 175 | initial_data += struct.pack(">IH", cmd_param + i, len(outer_chunk)) |
| 176 | log.debug(f's_cmd_w {0x9d00:#x} ({len(initial_data):2}) {initial_data.hex()}') |
| 177 | self._dev.ctrl_transfer(0x41, 0x45, 0x78, 0x9d00, initial_data) |
| 178 | self._block_until_camera_ready() |
| 179 | |
| 180 | # Each vendor control transfer can be 64 bytes max. Split up and send with incrementing wIndex value |
| 181 | for j in range(0, len(outer_chunk), inner_chunk_size): |
| 182 | inner_chunk = outer_chunk[j:j+inner_chunk_size] |
| 183 | to_send = len(outer_chunk) - j |
| 184 | |
| 185 | # The logic for splitting up long vendor requests is a bit weird |
| 186 | # I just reimplemented it like Infiray did according to the USB trace. Don't want to cause unnecessary problems |
| 187 | if (to_send <= 8): |
| 188 | log.debug(f's_cmd_w {(0x1d08 + j):#x} ({len(inner_chunk):2}) {inner_chunk.hex()}') |
| 189 | self._dev.ctrl_transfer(0x41, 0x45, 0x78, 0x1d08 + j, inner_chunk) |
| 190 | self._block_until_camera_ready() |
| 191 | elif (to_send <= 64): |
| 192 | log.debug(f's_cmd_w {(0x9d08 + j):#x} ({len(inner_chunk[:-8]):2}) {inner_chunk[:-8].hex()}') |
| 193 | log.debug( |
| 194 | f's_cmd_w {(0x1d08 + j + to_send - 8):#x} ({len(inner_chunk[-8:]):2}) {inner_chunk[-8:].hex()}') |
| 195 | self._dev.ctrl_transfer(0x41, 0x45, 0x78, 0x9d08 + j, inner_chunk[:-8]) |
| 196 | self._dev.ctrl_transfer(0x41, 0x45, 0x78, 0x1d08 + j + to_send - 8, inner_chunk[-8:]) |
| 197 | self._block_until_camera_ready() |
no test coverage detected