#include "ps2000_internal.h" #include /* ========================================================================== */ /* STUB IMPLEMENTATIONS */ /* ========================================================================== */ /** * @brief Universal stub returning 0. * * Reconstructs the pattern `xor eax, eax; retn` found in approximately * 27 methods of the operations table (sub_2ADA0, sub_2CC10, nullsub_5, * sub_2D900, sub_2D8F0, sub_2D910, sub_2CC30, sub_2CCF0, sub_2CEE0, * sub_2CED0, sub_12B00, sub_136C0, sub_136B0, sub_136D0, sub_13D90, * sub_13DA0, sub_15A00, sub_171C0, sub_171E0, sub_171F0, sub_171D0, * sub_17390, sub_173A0, sub_173B0, sub_173C0, nullsub_1, nullsub_2). */ int _ps2000_ops_stub_zero(void) { return 0; } /* ========================================================================== */ /* IDENTITY AND BASIC INFO */ /* ========================================================================== */ /** * @brief Returns the argument unchanged. * * Reconstructs sub_26F00: * mov eax, edi * retn * * Used as identity function for device identification. */ int _ps2000_ops_get_identity(ps2000_context_t *ctx) { if (!ctx) return 0; return (int)(intptr_t)ctx; } /** * @brief Returns maximum buffer size constant 0xA00 (2560). * * Reconstructs sub_22A00: * mov eax, 0A00h * retn */ int _ps2000_ops_get_max_buffer_size(ps2000_context_t *ctx) { (void)ctx; return (int)PS2000_MAX_BUFFER_SIZE; } /** * @brief Returns mode count constant 7. * * Reconstructs sub_220A0: * mov eax, 7 * retn */ int _ps2000_ops_get_mode_count(ps2000_context_t *ctx) { (void)ctx; return (int)PS2000_MODE_COUNT; } /* ========================================================================== */ /* CAPABILITIES AND VALIDATION */ /* ========================================================================== */ /** * @brief Check device capability by bit index. * * Reconstructs sub_133D0 / sub_13220 / sub_12B30: * movzx ecx, byte ptr [rdi+235h] ; load capabilities bitmap * cmp ecx, 3Ah ; check bit index limit (58) * ja loc_exit ; exit if bit > 57 * mov rax, 40100000D040000h ; capabilities mask * shr rax, cl ; shift to target bit * not rax ; invert (specific logic) * and eax, 1 ; extract bit */ bool _ps2000_ops_check_capability(ps2000_context_t *ctx, uint8_t bit) { if (!ctx) return false; if (bit > 58) return false; /* Extract bit from capabilities mask */ uint64_t mask = PS2000_CAPABILITIES_MASK; mask >>= bit; mask = ~mask; return (mask & 1ULL) != 0; } /** * @brief Validate channel pair (both must be <= 4). * * Reconstructs sub_2D2C0: * cmp esi, 4 * setbe al * cmp edx, 4 * setbe dl * and al, dl */ int _ps2000_ops_validate_channels(ps2000_context_t *ctx, uint32_t ch_a, uint32_t ch_b) { if (!ctx) return 0; bool valid_a = (ch_a <= PS2000_MAX_CHANNELS); bool valid_b = (ch_b <= PS2000_MAX_CHANNELS); return (valid_a && valid_b) ? 1 : 0; } /** * @brief Check AWG presence. * * Reconstructs sub_2A830: * cmp word ptr [rdi+39Eh], 0 ; awg_config_flag * jz loc_not_configured * cmp word ptr [rdi+392h], 0 ; awg_ext_param * jz loc_not_configured * mov eax, 1 * retn */ int _ps2000_ops_check_awg(ps2000_context_t *ctx) { if (!ctx) return 0; if (ctx->siggen.awg_config_flag == 0) return 0; if (ctx->siggen.ext_param == 0) return 0; return 1; } /** * @brief Validate signal generator configuration. * * Reconstructs sub_2D3A0: * movss xmm1, cs:dword_A4C84 ; min frequency limit * comiss xmm1, xmm0 ; compare with input * ja loc_invalid ; if input < min, invalid * movss xmm1, cs:dword_A4C88 ; max frequency limit * comiss xmm0, xmm1 ; compare with input * ja loc_invalid ; if input > max, invalid * cmp esi, 3FFFFFh ; check AWG sample count * ja loc_invalid */ int _ps2000_ops_validate_siggen(ps2000_context_t *ctx, uint32_t awg_samples) { if (!ctx) return 0; /* Check AWG sample count limit */ if (awg_samples > PS2000_AWG_MAX_SAMPLES) return 0; return 1; } /** * @brief Reset signal generator to default state. * * Reconstructs sub_2CEF0: * cmp word ptr [rdi+392h], 0 * mov dword ptr [rdi+104h], 0 * mov [rdi+392h], ax */ int _ps2000_ops_siggen_reset(ps2000_context_t *ctx) { if (!ctx) return 0; ctx->siggen.ext_param = 0; ctx->capture.buffer_size = 0; return 1; } /** * @brief Initialize signal generator with default values. * * Reconstructs sub_2A850: * mov dword ptr [rdi+32Eh], 80000h * cmp byte ptr [rdi+235h], 10h */ int _ps2000_ops_siggen_default_init(ps2000_context_t *ctx) { if (!ctx) return 0; ctx->siggen.config = PS2000_SIGGEN_DEFAULT; /* Check capabilities bitmap for specific feature */ if (_ps2000_ops_check_capability(ctx, 4)) { /* bit 4 = 0x10 */ /* Extended initialization for capable devices */ ctx->siggen.awg_config_flag = 1; } return 1; } /* ========================================================================== */ /* STATE AND MODE */ /* ========================================================================== */ /** * @brief Check timebase mode. * * Reconstructs sub_173F0: * cmp dword ptr [rdi+0F8h], 5 ; device_mode * setnz al * movzx eax, al */ int _ps2000_ops_check_timebase_mode(ps2000_context_t *ctx) { if (!ctx) return 0; return (ctx->device_mode != PS2000_DEVICE_MODE_SPECIAL) ? 1 : 0; } /** * @brief Get device state. * * Reconstructs sub_17200: * movzx eax, word ptr [rdi+112h] ; active_channel * mov esi, [rdi+104h] ; channel_param */ int _ps2000_ops_get_state(ps2000_context_t *ctx) { if (!ctx) return 0; /* Return combined state from channel configuration */ return (int)ctx->capture.buffer_size; } /** * @brief Check device state against special value 5. * * Reconstructs sub_14610: * mov dword ptr [rdi+226h], 0 * call sub_13CF0 * cmp dword ptr [rbx+226h], 5 */ int _ps2000_ops_check_device_state(ps2000_context_t *ctx) { if (!ctx) return 0; /* Reset state field */ ctx->capture.capture_state = 0; /* Perform state check (simplified from sub_13CF0) */ /* In original, this calls a sub-function that updates state */ /* For reconstruction, we check the current capture state */ if (ctx->capture.capture_state == PS2000_DEVICE_STATE_SPECIAL) { return 1; } return 0; } /** * @brief Check channel configuration. * * Reconstructs sub_14670: * cmp word ptr [rdi+112h], 0 ; active_channel */ int _ps2000_ops_check_channel(ps2000_context_t *ctx) { if (!ctx) return 0; return (ctx->capture.channel_mask != 0) ? 1 : 0; } /* ========================================================================== */ /* OPERATIONS TABLE INITIALIZATION */ /* ========================================================================== */ /** * @brief Initialize operations table based on device variant. * * Reconstructs sub_237C0: * mov eax, [rdi+0AAh] ; load device variant * cmp eax, 4 * jz loc_23DC8 ; variant 4 -> special handler * ja loc_23AC0 ; variant > 4 -> alternative branch * sub eax, 2 * cmp eax, 1 * ja locret_23DB8 ; variants 0, 1 -> exit * * The function populates the operations table with function pointers * appropriate for the detected device variant. */ ps2000_status_t _ps2000_ops_init_table(ps2000_context_t *ctx) { if (!ctx) return PS2000_ERR_INVALID_PARAM; int32_t variant = ctx->device_variant; /* Validate device variant (from sub_237C0 prologue) */ if (variant < PS2000_DEVICE_VARIANT_2) { PS2000_LOG_WRN("Unsupported device variant: %d", variant); return PS2000_ERR_NOT_IMPLEMENTED; } /* Initialize all stubs first */ ctx->ops.stub_01 = _ps2000_ops_stub_zero; ctx->ops.stub_02 = _ps2000_ops_stub_zero; ctx->ops.stub_03 = _ps2000_ops_stub_zero; ctx->ops.stub_04 = _ps2000_ops_stub_zero; ctx->ops.stub_05 = _ps2000_ops_stub_zero; ctx->ops.stub_06 = _ps2000_ops_stub_zero; ctx->ops.stub_07 = _ps2000_ops_stub_zero; ctx->ops.stub_08 = _ps2000_ops_stub_zero; ctx->ops.stub_09 = _ps2000_ops_stub_zero; ctx->ops.stub_10 = _ps2000_ops_stub_zero; ctx->ops.stub_11 = _ps2000_ops_stub_zero; ctx->ops.stub_12 = _ps2000_ops_stub_zero; ctx->ops.stub_13 = _ps2000_ops_stub_zero; ctx->ops.stub_14 = _ps2000_ops_stub_zero; ctx->ops.stub_15 = _ps2000_ops_stub_zero; ctx->ops.stub_16 = _ps2000_ops_stub_zero; ctx->ops.stub_17 = _ps2000_ops_stub_zero; ctx->ops.stub_18 = _ps2000_ops_stub_zero; ctx->ops.stub_19 = _ps2000_ops_stub_zero; ctx->ops.stub_20 = _ps2000_ops_stub_zero; ctx->ops.stub_21 = _ps2000_ops_stub_zero; ctx->ops.stub_22 = _ps2000_ops_stub_zero; ctx->ops.stub_23 = _ps2000_ops_stub_zero; ctx->ops.stub_24 = _ps2000_ops_stub_zero; ctx->ops.stub_25 = _ps2000_ops_stub_zero; ctx->ops.stub_26 = _ps2000_ops_stub_zero; ctx->ops.stub_27 = _ps2000_ops_stub_zero; /* Populate implemented methods */ ctx->ops.get_identity = _ps2000_ops_get_identity; ctx->ops.get_max_buffer_size = _ps2000_ops_get_max_buffer_size; ctx->ops.get_mode_count = _ps2000_ops_get_mode_count; ctx->ops.check_capability_a = _ps2000_ops_check_capability; ctx->ops.check_capability_b = _ps2000_ops_check_capability; ctx->ops.check_capability_c = _ps2000_ops_check_capability; ctx->ops.validate_channels = _ps2000_ops_validate_channels; ctx->ops.check_awg = _ps2000_ops_check_awg; ctx->ops.siggen_reset = _ps2000_ops_siggen_reset; ctx->ops.siggen_default_init = _ps2000_ops_siggen_default_init; ctx->ops.check_timebase_mode = _ps2000_ops_check_timebase_mode; ctx->ops.get_state = _ps2000_ops_get_state; ctx->ops.check_device_state = _ps2000_ops_check_device_state; ctx->ops.check_channel = _ps2000_ops_check_channel; /* Variant-specific initialization */ switch (variant) { case PS2000_DEVICE_VARIANT_2: case PS2000_DEVICE_VARIANT_3: /* Standard initialization for variants 2 and 3 */ PS2000_LOG_INF("Operations table initialized for variant %d", variant); break; case PS2000_DEVICE_VARIANT_4: /* Special handler for variant 4 (from loc_23DC8 -> sub_15590) */ /* Variant 4 has extended capabilities */ PS2000_LOG_INF("Operations table initialized for extended variant 4"); break; default: /* Variants > 4 go to alternative branch (loc_23AC0) */ PS2000_LOG_WRN("Unknown device variant: %d, using defaults", variant); break; } return PS2000_OK; }