Files
ps2000-my/src/ps2000_ops.c
T

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;
}