358 lines
11 KiB
C
358 lines
11 KiB
C
#include "ps2000_internal.h"
|
|
#include <string.h>
|
|
|
|
/* ========================================================================== */
|
|
/* 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 (ctx->info.eeprom_valid == 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;
|
|
} |