Files
ps2000-my/src/ps2000_fw.c
T

100 lines
3.3 KiB
C

#include "ps2000_internal.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/* ========================================================================== */
/* FIRMWARE LOADER (Anchor Protocol) */
/* ========================================================================== */
#define ANCHOR_CMD_RAM_WRITE 0xA0U
#define ANCHOR_CPUCS_REG 0xE600U
#define ANCHOR_CPUCS_HALT 0x01U
#define ANCHOR_CPUCS_RUN 0x00U
#define PS2000_FW_ANCHOR_CHUNK 4096U
/**
* @brief Write data to Anchor chip RAM via USB Control Transfer.
*
* Reconstructs "AnchorWrite download %llx returned err" (0x4E68F).
*/
static ps2000_status_t _ps2000_fw_anchor_write_chunk(ps2000_context_t *ctx,
uint16_t addr,
const uint8_t *data,
uint16_t len) {
if (!ctx || !ctx->usb_host.handle || !data) return PS2000_ERR_INVALID_PARAM;
int transferred = libusb_control_transfer(
ctx->usb_host.handle,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
ANCHOR_CMD_RAM_WRITE,
addr, 0,
(uint8_t*)data, len,
PS2000_USB_TIMEOUT_MS
);
if (transferred < 0) {
PS2000_LOG_ERR("AnchorWrite download %04X returned err %d", addr, transferred);
return PS2000_ERR_USB;
}
return PS2000_OK;
}
static ps2000_status_t _ps2000_fw_anchor_set_cpu(ps2000_context_t *ctx, bool halt) {
uint8_t cpucs_val = halt ? ANCHOR_CPUCS_HALT : ANCHOR_CPUCS_RUN;
return _ps2000_fw_anchor_write_chunk(ctx, ANCHOR_CPUCS_REG, &cpucs_val, 1);
}
ps2000_status_t _ps2000_fw_load(ps2000_context_t *ctx,
const uint8_t *fw_data, uint32_t fw_len) {
if (!ctx || !fw_data || fw_len == 0) return PS2000_ERR_INVALID_PARAM;
PS2000_LOG_INF("Loading firmware via Anchor protocol (%u bytes)...", fw_len);
ps2000_status_t status = _ps2000_fw_anchor_set_cpu(ctx, true);
if (status != PS2000_OK) return status;
uint32_t offset = 0;
while (offset < fw_len) {
uint32_t chunk_len = fw_len - offset;
if (chunk_len > PS2000_FW_ANCHOR_CHUNK) chunk_len = PS2000_FW_ANCHOR_CHUNK;
status = _ps2000_fw_anchor_write_chunk(ctx, (uint16_t)offset,
&fw_data[offset], (uint16_t)chunk_len);
if (status != PS2000_OK) {
_ps2000_fw_anchor_set_cpu(ctx, false);
return status;
}
offset += chunk_len;
}
status = _ps2000_fw_anchor_set_cpu(ctx, false);
if (status == PS2000_OK) {
usleep(100000); /* Wait for re-enumeration */
PS2000_LOG_INF("Firmware loaded and CPU started");
}
return status;
}
ps2000_status_t _ps2000_fw_init(ps2000_context_t *ctx) {
(void)ctx;
return PS2000_OK;
}
void _ps2000_fw_cleanup(ps2000_context_t *ctx) {
(void)ctx;
}
ps2000_status_t _ps2000_fw_reset_device(ps2000_context_t *ctx) {
if (!ctx || !ctx->usb_host.handle) return PS2000_ERR_NOT_OPENED;
uint8_t cmd = 0x01;
return _ps2000_usb_control_transfer(ctx,
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
0xA8, 0, 0, &cmd, 1);
}
ps2000_status_t _ps2000_fw_verify(ps2000_context_t *ctx) {
(void)ctx;
return PS2000_OK;
}