<commit_before>/*
 * STM32 firmware update protocol implementation
 * LGPL v2.1
 * Copyright Arduino S.r.l.
 * Author <NAME> 2016
 */

#include "dfu.h"
#include "dfu-internal.h"
#include "dfu-cmd.h"

#define ACK 0x79

struct stm32_usart_data {
#define STM32_EXTENDED_MEMORY_ERASE	(1 << 0)
#define STM32_DOUBLE_NAK		(1 << 1)
	int target_flags;
	phys_addr_t curr_chunk_addr;
	struct dfu_cmdstate cmd_state;
	struct dfu_timeout cmd_timeout;
	const struct dfu_cmddescr *curr_descr;
};

struct stm32_get_cmd_reply {
	uint8_t len;
	uint8_t bootloader_version;
	uint8_t supported_commands[11];
	uint8_t ack;
} __attribute__((packed));

struct stm32_gid_cmd_reply {
	uint8_t len;
	uint8_t pid[2];
	uint8_t ack;
};


static void checksum_update(const struct dfu_cmddescr *descr, const void *_buf,
			    unsigned int l)
{
	uint8_t *cptr = descr->checksum_ptr;
	const uint8_t *buf = _buf;
	unsigned int i;

	if (!cptr) {
		dfu_dbg("%s invoked with NULL checksum ptr\n", __func__);
		return;
	}
	for (i = 0; i < l; i++)
		*cptr ^= buf[i];
}

static int _check_ack(const struct dfu_cmddescr *descr,
		      const struct dfu_cmdbuf *buf)
{
	char *ptr = buf->buf.in;

	dfu_dbg("%s: ptr[0] = 0x%02x (expected 0x%02x)\n", __func__, ptr[0],
		ACK);
	return ptr[0] == ACK ? 0 : -1;
}

static int get_cmd(struct dfu_target *target, struct stm32_get_cmd_reply *r)
{
	struct stm32_usart_data *priv = target->priv;
	static const uint8_t cmdb[] = { 0, 0xff, };
	static uint8_t ack;
	static struct dfu_cmdbuf cmds[] = {
		{
			.dir = OUT,
			.buf = {
				.out = cmdb,
			},
			.len = sizeof(cmdb),
		},
		{
			.dir = IN,
			.buf = {
				.in = &ack,
			},
			.len = sizeof(ack),
			.timeout = 200,
			.completed = _check_ack,
		},
		{
			.dir = IN,
			.len = sizeof(*r),
			.timeout = 300,
		},
	};
	static struct dfu_cmddescr descr0 = {
		.cmdbufs = cmds,
		.ncmdbufs = ARRAY_SIZE(cmds),
	};

	descr0.state = &priv->cmd_state;
	descr0.timeout = &priv->cmd_timeout;
	cmds[2].buf.in = r;
	priv->curr_descr = &descr0;
	return dfu_cmd_do_sync(target, &descr0);
}

static int gid_cmd(struct dfu_target *target, struct stm32_gid_cmd_reply *r)
{
	struct stm32_usart_data *priv = target->priv;
	static const uint8_t cmdb[] = { 0x02, 0xfd, };
	static uint8_t ack;
	static struct dfu_cmdbuf cmds[] = {
		{
			.dir = OUT,
			.buf = {
				.out = cmdb,
			},
			.len = sizeof(cmdb),
		},
		{
			.dir = IN,
			.buf = {
				.in = &ack,
			},
			.len = sizeof(ack),
			.timeout = 200,
			.completed = _check_ack,
		},
		{
			.dir = IN,
			.len = sizeof(*r),
			.timeout = 300,
		},
	};
	static struct dfu_cmddescr descr0 = {
		.cmdbufs = cmds,
		.ncmdbufs = ARRAY_SIZE(cmds),
	};

	cmds[2].buf.in = r;
	descr0.state = &priv->cmd_state;
	descr0.timeout = &priv->cmd_timeout;
	priv->curr_descr = &descr0;
	return dfu_cmd_do_sync(target, &descr0);
}

int stm32_usart_init(struct dfu_target *target,
		     struct dfu_interface *interface)
{
	static struct stm32_usart_data priv;
	target->interface = interface;
	memset(&priv, 0, sizeof(priv));
	target->priv = &priv;
	dfu_log("STM32-USART target initialized\n");
	return 0;
}

/* Remove this ? */
int stm32_usart_probe(struct dfu_target *target)
{
	int stat, i;
	struct stm32_get_cmd_reply r1;
	struct stm32_gid_cmd_reply r2;
	struct stm32_usart_data *priv = target->priv;

	dfu_log("Probing stm32 target\n");
	stat = get_cmd(target, &r1);
	if (stat < 0)
		return -1;
	dfu_log("Bootloader version = 0x%02x\n", r1.bootloader_version);
	dfu_log("Supported commands:\n");
	for (i = 0; i < sizeof(r1.supported_commands); i++)
		dfu_log("\t0x%02x\n", r1.supported_commands[i]);
	if (r1.supported_commands[6] == 0x44) {
		dfu_log("Extended memory erase cmd supported\n");
		priv->target_flags |= STM32_EXTENDED_MEMORY_ERASE;
	}
	if (r1.bootloader_version == 0x31) {
		dfu_log("Double NAK quirk enabled\n");
		priv->target_flags |= STM32_DOUBLE_NAK;
	}
	stat = gid_cmd(target, &r2);
	if (stat < 0)
		return -1;
	dfu_log("Product id = 0x%02x 0x%02x\n", r2.pid[0], r2.pid[1]);
	dfu_log("stm32 target probed\n");
	return 0;
}

static void _chunk_done(struct dfu_target *target,
			const struct dfu_cmddescr *descr)
{
	struct stm32_usart_data *priv = target->priv;

	if (descr->state->status == DFU_CMD_STATUS_OK)
		dfu_dbg("chunk 0x%08x programmed OK\n",
			(unsigned int)priv->curr_chunk_addr);
	dfu_binary_file_chunk_done(target->dfu->bf, priv->curr_chunk_addr,
				   descr->state->status == DFU_CMD_STATUS_OK ?
				   0 : -1);
}

/* Chunk of binary data is available for writing */
int stm32_usart_chunk_available(struct dfu_target *target,
				phys_addr_t address,
				const void *buf, unsigned long sz)
{
	static const uint8_t cmdb[] = { 0x31, 0xce, };
	static uint32_t addr;<commit_msg>target, stm32-usart: check part id on probe<commit_after>/*
 * STM32 firmware update protocol implementation
 * LGPL v2.1
 * Copyright Arduino S.r.l.
 * Author <NAME> 2016
 */

#include "dfu.h"
#include "dfu-internal.h"
#include "dfu-cmd.h"
#include "stm32-device.h"

#define ACK 0x79

struct stm32_usart_data {
#define STM32_EXTENDED_MEMORY_ERASE	(1 << 0)
#define STM32_DOUBLE_NAK		(1 << 1)
	int target_flags;
	phys_addr_t curr_chunk_addr;
	struct dfu_cmdstate cmd_state;
	struct dfu_timeout cmd_timeout;
	const struct dfu_cmddescr *curr_descr;
};

struct stm32_get_cmd_reply {
	uint8_t len;
	uint8_t bootloader_version;
	uint8_t supported_commands[11];
	uint8_t ack;
} __attribute__((packed));

struct stm32_gid_cmd_reply {
	uint8_t len;
	uint8_t pid[2];
	uint8_t ack;
};


static void checksum_update(const struct dfu_cmddescr *descr, const void *_buf,
			    unsigned int l)
{
	uint8_t *cptr = descr->checksum_ptr;
	const uint8_t *buf = _buf;
	unsigned int i;

	if (!cptr) {
		dfu_dbg("%s invoked with NULL checksum ptr\n", __func__);
		return;
	}
	for (i = 0; i < l; i++)
		*cptr ^= buf[i];
}

static int _check_ack(const struct dfu_cmddescr *descr,
		      const struct dfu_cmdbuf *buf)
{
	char *ptr = buf->buf.in;

	dfu_dbg("%s: ptr[0] = 0x%02x (expected 0x%02x)\n", __func__, ptr[0],
		ACK);
	return ptr[0] == ACK ? 0 : -1;
}

static int get_cmd(struct dfu_target *target, struct stm32_get_cmd_reply *r)
{
	struct stm32_usart_data *priv = target->priv;
	static const uint8_t cmdb[] = { 0, 0xff, };
	static uint8_t ack;
	static struct dfu_cmdbuf cmds[] = {
		{
			.dir = OUT,
			.buf = {
				.out = cmdb,
			},
			.len = sizeof(cmdb),
		},
		{
			.dir = IN,
			.buf = {
				.in = &ack,
			},
			.len = sizeof(ack),
			.timeout = 200,
			.completed = _check_ack,
		},
		{
			.dir = IN,
			.len = sizeof(*r),
			.timeout = 300,
		},
	};
	static struct dfu_cmddescr descr0 = {
		.cmdbufs = cmds,
		.ncmdbufs = ARRAY_SIZE(cmds),
	};

	descr0.state = &priv->cmd_state;
	descr0.timeout = &priv->cmd_timeout;
	cmds[2].buf.in = r;
	priv->curr_descr = &descr0;
	return dfu_cmd_do_sync(target, &descr0);
}

static int gid_cmd(struct dfu_target *target, struct stm32_gid_cmd_reply *r)
{
	struct stm32_usart_data *priv = target->priv;
	static const uint8_t cmdb[] = { 0x02, 0xfd, };
	static uint8_t ack;
	static struct dfu_cmdbuf cmds[] = {
		{
			.dir = OUT,
			.buf = {
				.out = cmdb,
			},
			.len = sizeof(cmdb),
		},
		{
			.dir = IN,
			.buf = {
				.in = &ack,
			},
			.len = sizeof(ack),
			.timeout = 200,
			.completed = _check_ack,
		},
		{
			.dir = IN,
			.len = sizeof(*r),
			.timeout = 300,
		},
	};
	static struct dfu_cmddescr descr0 = {
		.cmdbufs = cmds,
		.ncmdbufs = ARRAY_SIZE(cmds),
	};

	cmds[2].buf.in = r;
	descr0.state = &priv->cmd_state;
	descr0.timeout = &priv->cmd_timeout;
	priv->curr_descr = &descr0;
	return dfu_cmd_do_sync(target, &descr0);
}

int stm32_usart_init(struct dfu_target *target,
		     struct dfu_interface *interface)
{
	static struct stm32_usart_data priv;
	target->interface = interface;
	memset(&priv, 0, sizeof(priv));
	target->priv = &priv;
	if (!target->pars) {
		dfu_err("%s: no parameters received\n", __func__);
		return -1;
	}
	dfu_log("STM32-USART target initialized\n");
	return 0;
}

/* Remove this ? */
int stm32_usart_probe(struct dfu_target *target)
{
	int stat, i;
	struct stm32_get_cmd_reply r1;
	struct stm32_gid_cmd_reply r2;
	struct stm32_usart_data *priv = target->priv;
	const struct stm32_device_data *pars = target->pars;

	dfu_log("Probing stm32 target\n");
	stat = get_cmd(target, &r1);
	if (stat < 0)
		return -1;
	dfu_log("Bootloader version = 0x%02x\n", r1.bootloader_version);
	dfu_log("Supported commands:\n");
	for (i = 0; i < sizeof(r1.supported_commands); i++)
		dfu_log("\t0x%02x\n", r1.supported_commands[i]);
	if (r1.supported_commands[6] == 0x44) {
		dfu_log("Extended memory erase cmd supported\n");
		priv->target_flags |= STM32_EXTENDED_MEMORY_ERASE;
	}
	if (r1.bootloader_version == 0x31) {
		dfu_log("Double NAK quirk enabled\n");
		priv->target_flags |= STM32_DOUBLE_NAK;
	}
	stat = gid_cmd(target, &r2);
	if (stat < 0)
		return -1;
	dfu_log("Product id = 0x%02x 0x%02x\n", r2.pid[0], r2.pid[1]);
	if (r2.pid[0] != pars->part_id[0] ||
	    r2.pid[1] != pars->part_id[1]) {
		dfu_err("Unexpected part id\n");
		return -1;
	}
	dfu_log("stm32 target probed\n");
	return 0;
}

static void _chunk_done(struct dfu_target *target,
			const struct dfu_cmddescr *descr)
{
	struct stm32_usart_data *priv = target->priv;

	if (descr->state->status == DFU_CMD_STATUS_OK)
		dfu_dbg("chunk 0x%08x programmed OK\n",
			(unsigned int)priv->curr_chunk_addr);
	dfu_binary_file_chunk_done(target->dfu->bf, priv->curr_chunk_addr,
				   descr->state->status == DFU_CMD_STATUS_OK ?
				   0 : -1);
}

/* Chunk of binary data is available for writing */
int stm32_usart_chunk_available(struct dfu_target *target,
				phys_addr_t address,
				const void *buf, unsigned long sz)
{
	static const uint8_t cmdb[] = { 0x31, 0xce, };
	static uint32_t addr;
{'fraction_non_alphanumeric': 0.1439019365471776, 'fraction_numerical': 0.036258755665430575, 'mean_word_length': 3.763984298331698, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5491416', 'n_tokens_mistral': 4566, 'n_tokens_neox': 4137, 'n_words': 891}