Exemplo n.º 1
0
int main(int argc, char* argv[]) {
	int ret = 1;
	parser_err_t perr;
	
	(void) signal(SIGINT, caught_sigint);

	printf("stm32flash - http://stm32flash.googlecode.com/\n\n");
	if (parse_options(argc, argv) != 0)
		goto close;

	if (wr) {
		/* first try hex */
		if (!force_binary) {
			parser = &PARSER_HEX;
			p_st = parser->init();
			if (!p_st) {
				fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
				goto close;
			}
		}

		if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) {
			if (force_binary || perr == PARSER_ERR_INVALID_FILE) {
				if (!force_binary) {
					parser->close(p_st);
					p_st = NULL;
				}

				/* now try binary */
				parser = &PARSER_BINARY;
				p_st = parser->init();
				if (!p_st) {
					fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
					goto close;
				}
				perr = parser->open(p_st, filename, 0);
			}

			/* if still have an error, fail */
			if (perr != PARSER_ERR_OK) {
				fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
				if (perr == PARSER_ERR_SYSTEM) perror(filename);
				goto close;
			}
		}

		fprintf(stdout, "Using Parser : %s\n", parser->name);
	} else {
		parser = &PARSER_BINARY;
		p_st = parser->init();
		if (!p_st) {
			fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
			goto close;
		}
	}

	serial = serial_open(device);
	if (!serial) {
		perror(device);
		goto close;
	}

	if (serial_setup(
		serial,
		baudRate,
		SERIAL_BITS_8,
		SERIAL_PARITY_EVEN,
		SERIAL_STOPBIT_1
	) != SERIAL_ERR_OK) {
		perror(device);
		goto close;
	}

	printf("Serial Config: %s\n", serial_get_setup_str(serial));
	if (!(stm = stm32_init(serial, init_flag))) goto close;

	printf("Version      : 0x%02x\n", stm->bl_version);
	printf("Option 1     : 0x%02x\n", stm->option1);
	printf("Option 2     : 0x%02x\n", stm->option2);
	printf("Device ID    : 0x%04x (%s)\n", stm->pid, stm->dev->name);
	printf("RAM          : %dKiB  (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
	printf("Flash        : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps);
	printf("Option RAM   : %db\n", stm->dev->opt_end - stm->dev->opt_start);
	printf("System RAM   : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024);

	uint8_t		buffer[256];
	uint32_t	addr;
	unsigned int	len;
	int		failed = 0;

	if (rd) {
		printf("\n");

		if ((perr = parser->open(p_st, filename, 1)) != PARSER_ERR_OK) {
			fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
			if (perr == PARSER_ERR_SYSTEM) perror(filename);
			goto close;
		}

		addr = stm->dev->fl_start + (spage * stm->dev->fl_ps);
		fflush(stdout);
		fprintf(stdout, "\033[?25l");
		while(addr < stm->dev->fl_end) {
			uint32_t left	= stm->dev->fl_end - addr;
			len		= sizeof(buffer) > left ? left : sizeof(buffer);
			if (!stm32_read_memory(stm, addr, buffer, len)) {
				fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr);
				goto close;
			}
			assert(parser->write(p_st, buffer, len) == PARSER_ERR_OK);
			addr += len;

			fprintf(stdout,
				"\033[1GRead address 0x%08x (%.2f%%) ",
				addr,
				(100.0f / (float)(stm->dev->fl_end - stm->dev->fl_start)) * (float)(addr - stm->dev->fl_start)
			);
			fflush(stdout);
		}
		fprintf(stdout,	"Done.\n");
		fprintf(stdout, "\033[?25h");
		ret = 0;
		goto close;

	} else if (wu) {
		fprintf(stdout, "Write-unprotecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_wunprot_memory(stm);
		fprintf(stdout,	"Done.\n");

	} else if (wr) {
		printf("\n");

		off_t 	offset = 0;
		ssize_t r;
		unsigned int size = parser->size(p_st);

		if (size > stm->dev->fl_end - stm->dev->fl_start) {
			fprintf(stderr, "File provided larger then available flash space.\n");
			goto close;
		}

		if (!stm32_erase_memory(stm, spage, npages)) {
			fprintf(stderr, "Failed to erase memory\n");
			goto close;
		}

		addr = stm->dev->fl_start + (spage * stm->dev->fl_ps);
		fflush(stdout);
                fprintf(stdout, "\033[?25l");
		while(addr < stm->dev->fl_end && offset < size) {
			uint32_t left	= stm->dev->fl_end - addr;
			len		= sizeof(buffer) > left ? left : sizeof(buffer);
			len		= len > size - offset ? size - offset : len;

			if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK)
				goto close;
	
			again:
			if (!stm32_write_memory(stm, addr, buffer, len)) {
				fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr);
				goto close;
			}

			if (verify) {
				uint8_t compare[len];
				if (!stm32_read_memory(stm, addr, compare, len)) {
					fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr);
					goto close;
				}

				for(r = 0; r < len; ++r)
					if (buffer[r] != compare[r]) {
						if (failed == retry) {
							fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n",
								(uint32_t)(addr + r),
								buffer [r],
								compare[r]
							);
							goto close;
						}
						++failed;
						goto again;
					}

				failed = 0;
			}

			addr	+= len;
			offset	+= len;

			fprintf(stdout,
				"\033[1GWrote %saddress 0x%08x (%.2f%%) ",
				verify ? "and verified " : "\n",
				addr,
				(100.0f / size) * offset
			);
			fflush(stdout);

		}

		fprintf(stdout,	"Done.\n");
                fprintf(stdout, "\033[?25h");
		ret = 0;
		goto close;
	} else
		ret = 0;

close:
	if (stm && exec_flag && ret == 0) {
		if (execute == 0)
			execute = stm->dev->fl_start;

		fprintf(stdout, "\nStarting execution at address 0x%08x... ", execute);
		fflush(stdout);
		if (stm32_go(stm, execute)) {
			reset_flag = 0;
			fprintf(stdout, "done.\n");
		} else
			fprintf(stdout, "failed.\n");
	}

	if (stm && reset_flag) {
		fprintf(stdout, "\nResetting device... ");
		fflush(stdout);
		if (stm32_reset_device(stm))
			fprintf(stdout, "done.\n");
		else	fprintf(stdout, "failed.\n");
	}


	cleanup();
	printf("\n");
	return ret;
}
Exemplo n.º 2
0
int main(int argc, char* argv[])
{
	struct port_interface *port = NULL;
	int ret = 1;
	stm32_err_t s_err;
	parser_err_t perr;
	FILE *diag = stdout;

	fprintf(diag, "stm32flash " VERSION "\n\n");
	fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n");
	if (parse_options(argc, argv) != 0)
		goto close;

	if (rd && filename[0] == '-') {
		diag = stderr;
	}

	if (wr) {
		/* first try hex */
		if (!force_binary) {
			parser = &PARSER_HEX;
			p_st = parser->init();
			if (!p_st) {
				fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
				goto close;
			}
		}

		if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) {
			if (force_binary || perr == PARSER_ERR_INVALID_FILE) {
				if (!force_binary) {
					parser->close(p_st);
					p_st = NULL;
				}

				/* now try binary */
				parser = &PARSER_BINARY;
				p_st = parser->init();
				if (!p_st) {
					fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
					goto close;
				}
				perr = parser->open(p_st, filename, 0);
			}

			/* if still have an error, fail */
			if (perr != PARSER_ERR_OK) {
				fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
				if (perr == PARSER_ERR_SYSTEM) perror(filename);
				goto close;
			}
		}

		fprintf(diag, "Using Parser : %s\n", parser->name);
	} else {
		parser = &PARSER_BINARY;
		p_st = parser->init();
		if (!p_st) {
			fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
			goto close;
		}
	}

	if (port_open(&port_opts, &port) != PORT_ERR_OK) {
		fprintf(stderr, "Failed to open port: %s\n", port_opts.device);
		goto close;
	}

	fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port));
	if (init_flag && init_bl_entry(port, gpio_seq) == 0)
		goto close;
	stm = stm32_init(port, init_flag);
	if (!stm)
		goto close;

	fprintf(diag, "Version      : 0x%02x\n", stm->bl_version);
	if (port->flags & PORT_GVR_ETX) {
		fprintf(diag, "Option 1     : 0x%02x\n", stm->option1);
		fprintf(diag, "Option 2     : 0x%02x\n", stm->option2);
	}
	fprintf(diag, "Device ID    : 0x%04x (%s)\n", stm->pid, stm->dev->name);
	fprintf(diag, "- RAM        : %dKiB  (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
	fprintf(diag, "- Flash      : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps);
	fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1);
	fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024);

	uint8_t		buffer[256];
	uint32_t	addr, start, end;
	unsigned int	len;
	int		failed = 0;
	int		first_page, num_pages;

	/*
	 * Cleanup addresses:
	 *
	 * Starting from options
	 *	start_addr, readwrite_len, spage, npages
	 * and using device memory size, compute
	 *	start, end, first_page, num_pages
	 */
	if (start_addr || readwrite_len) {
		start = start_addr;

		if (is_addr_in_flash(start))
			end = stm->dev->fl_end;
		else {
			no_erase = 1;
			if (is_addr_in_ram(start))
				end = stm->dev->ram_end;
			else
				end = start + sizeof(uint32_t);
		}

		if (readwrite_len && (end > start + readwrite_len))
			end = start + readwrite_len;

		first_page = flash_addr_to_page_floor(start);
		if (!first_page && end == stm->dev->fl_end)
			num_pages = 0xff; /* mass erase */
		else
			num_pages = flash_addr_to_page_ceil(end) - first_page;
	} else if (!spage && !npages) {
		start = stm->dev->fl_start;
		end = stm->dev->fl_end;
		first_page = 0;
		num_pages = 0xff; /* mass erase */
	} else {
		first_page = spage;
		start = flash_page_to_addr(first_page);
		if (start > stm->dev->fl_end) {
			fprintf(stderr, "Address range exceeds flash size.\n");
			goto close;
		}

		if (npages) {
			num_pages = npages;
			end = flash_page_to_addr(first_page + num_pages);
			if (end > stm->dev->fl_end)
				end = stm->dev->fl_end;
		} else {
			end = stm->dev->fl_end;
			num_pages = flash_addr_to_page_ceil(end) - first_page;
		}

		if (!first_page && end == stm->dev->fl_end)
			num_pages = 0xff; /* mass erase */
	}

	if (rd) {
		unsigned int max_len = port_opts.rx_frame_max;

		fprintf(diag, "Memory read\n");

		perr = parser->open(p_st, filename, 1);
		if (perr != PARSER_ERR_OK) {
			fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
			if (perr == PARSER_ERR_SYSTEM)
				perror(filename);
			goto close;
		}

		fflush(diag);
		addr = start;
		while (addr < end) {
			uint32_t left	= end - addr;
			len		= max_len > left ? left : max_len;
			s_err = stm32_read_memory(stm, addr, buffer, len);
			if (s_err != STM32_ERR_OK) {
				fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr);
				goto close;
			}
			if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) {
				fprintf(stderr, "Failed to write data to file\n");
				goto close;
			}
			addr += len;

			fprintf(diag,
			        "\rRead address 0x%08x (%.2f%%) ",
			        addr,
			        (100.0f / (float)(end - start)) * (float)(addr - start)
			       );
			fflush(diag);
		}
		fprintf(diag,	"Done.\n");
		ret = 0;
		goto close;
	} else if (rp) {
		fprintf(stdout, "Read-Protecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_readprot_memory(stm);
		fprintf(stdout,	"Done.\n");
	} else if (ur) {
		fprintf(stdout, "Read-UnProtecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_runprot_memory(stm);
		fprintf(stdout,	"Done.\n");
	} else if (eraseOnly) {
		ret = 0;
		fprintf(stdout, "Erasing flash\n");

		if (num_pages != 0xff &&
		    (start != flash_page_to_addr(first_page)
		     || end != flash_page_to_addr(first_page + num_pages))) {
			fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n");
			ret = 1;
			goto close;
		}

		s_err = stm32_erase_memory(stm, first_page, num_pages);
		if (s_err != STM32_ERR_OK) {
			fprintf(stderr, "Failed to erase memory\n");
			ret = 1;
			goto close;
		}
	} else if (wu) {
		fprintf(diag, "Write-unprotecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_wunprot_memory(stm);
		fprintf(diag,	"Done.\n");

	} else if (wr) {
		fprintf(diag, "Write to memory\n");

		off_t 	offset = 0;
		ssize_t r;
		unsigned int size;
		unsigned int max_wlen, max_rlen;

		max_wlen = port_opts.tx_frame_max - 2;	/* skip len and crc */
		max_wlen &= ~3;	/* 32 bit aligned */

		max_rlen = port_opts.rx_frame_max;
		max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen;

		/* Assume data from stdin is whole device */
		if (filename[0] == '-' && filename[1] == '\0')
			size = end - start;
		else
			size = parser->size(p_st);

		// TODO: It is possible to write to non-page boundaries, by reading out flash
		//       from partial pages and combining with the input data
		// if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) {
		//	fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n");
		//	goto close;
		// }

		// TODO: If writes are not page aligned, we should probably read out existing flash
		//       contents first, so it can be preserved and combined with new data
		if (!no_erase && num_pages) {
			fprintf(diag, "Erasing memory\n");
			s_err = stm32_erase_memory(stm, first_page, num_pages);
			if (s_err != STM32_ERR_OK) {
				fprintf(stderr, "Failed to erase memory\n");
				goto close;
			}
		}

		fflush(diag);
		addr = start;
		while (addr < end && offset < size) {
			uint32_t left	= end - addr;
			len		= max_wlen > left ? left : max_wlen;
			len		= len > size - offset ? size - offset : len;

			if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK)
				goto close;

			if (len == 0) {
				if (filename[0] == '-') {
					break;
				} else {
					fprintf(stderr, "Failed to read input file\n");
					goto close;
				}
			}

again:
			s_err = stm32_write_memory(stm, addr, buffer, len);
			if (s_err != STM32_ERR_OK) {
				fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr);
				goto close;
			}

			if (verify) {
				uint8_t compare[len];
				unsigned int offset, rlen;

				offset = 0;
				while (offset < len) {
					rlen = len - offset;
					rlen = rlen < max_rlen ? rlen : max_rlen;
					s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen);
					if (s_err != STM32_ERR_OK) {
						fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset);
						goto close;
					}
					offset += rlen;
				}

				for (r = 0; r < len; ++r)
					if (buffer[r] != compare[r]) {
						if (failed == retry) {
							fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n",
							        (uint32_t)(addr + r),
							        buffer [r],
							        compare[r]
							       );
							goto close;
						}
						++failed;
						goto again;
					}

				failed = 0;
			}

			addr	+= len;
			offset	+= len;

			fprintf(diag,
			        "\rWrote %saddress 0x%08x (%.2f%%) ",
			        verify ? "and verified " : "",
			        addr,
			        (100.0f / size) * offset
			       );
			fflush(diag);

		}

		fprintf(diag,	"Done.\n");
		ret = 0;
		goto close;
	} else if (crc) {
		uint32_t crc_val = 0;

		fprintf(diag, "CRC computation\n");

		s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val);
		if (s_err != STM32_ERR_OK) {
			fprintf(stderr, "Failed to read CRC\n");
			goto close;
		}
		fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end,
		        crc_val);
		ret = 0;
		goto close;
	} else
		ret = 0;

close:
	if (stm && exec_flag && ret == 0) {
		if (execute == 0)
			execute = stm->dev->fl_start;

		fprintf(diag, "\nStarting execution at address 0x%08x... ", execute);
		fflush(diag);
		if (stm32_go(stm, execute) == STM32_ERR_OK) {
			reset_flag = 0;
			fprintf(diag, "done.\n");
		} else
			fprintf(diag, "failed.\n");
	}

	if (stm && reset_flag) {
		fprintf(diag, "\nResetting device... ");
		fflush(diag);
		if (init_bl_exit(stm, port, gpio_seq))
			fprintf(diag, "done.\n");
		else	fprintf(diag, "failed.\n");
	}

	if (p_st  ) parser->close(p_st);
	if (stm   ) stm32_close  (stm);
	if (port)
		port->close(port);

	fprintf(diag, "\n");
	return ret;
}
Exemplo n.º 3
0
int main(int argc, char* argv[]) {
	int ret = 1;
	parser_err_t perr;
	FILE *diag = stdout;

	fprintf(diag, "stm32flash " VERSION "\n\n");
	fprintf(diag, "http://stm32flash.googlecode.com/\n\n");
	if (parse_options(argc, argv) != 0)
		goto close;

	if (rd && filename[0] == '-') {
		diag = stderr;
	}

	if (wr) {
		/* first try hex */
		if (!force_binary) {
			parser = &PARSER_HEX;
			p_st = parser->init();
			if (!p_st) {
				fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
				goto close;
			}
		}

		if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) {
			if (force_binary || perr == PARSER_ERR_INVALID_FILE) {
				if (!force_binary) {
					parser->close(p_st);
					p_st = NULL;
				}

				/* now try binary */
				parser = &PARSER_BINARY;
				p_st = parser->init();
				if (!p_st) {
					fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
					goto close;
				}
				perr = parser->open(p_st, filename, 0);
			}

			/* if still have an error, fail */
			if (perr != PARSER_ERR_OK) {
				fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
				if (perr == PARSER_ERR_SYSTEM) perror(filename);
				goto close;
			}
		}

		fprintf(diag, "Using Parser : %s\n", parser->name);
	} else {
		parser = &PARSER_BINARY;
		p_st = parser->init();
		if (!p_st) {
			fprintf(stderr, "%s Parser failed to initialize\n", parser->name);
			goto close;
		}
	}

	serial = serial_open(device);
	if (!serial) {
		fprintf(stderr, "Failed to open serial port: ");
		perror(device);
		goto close;
	}

	if (serial_setup(
		serial,
		baudRate,
		serial_get_bits(serial_mode),
		serial_get_parity(serial_mode),
		serial_get_stopbit(serial_mode)
	) != SERIAL_ERR_OK) {
		perror(device);
		goto close;
	}

	fprintf(diag, "Serial Config: %s\n", serial_get_setup_str(serial));
	if (init_flag && init_bl_entry(serial, gpio_seq) == 0) goto close;
	if (!(stm = stm32_init(serial, init_flag))) goto close;

	fprintf(diag, "Version      : 0x%02x\n", stm->bl_version);
	fprintf(diag, "Option 1     : 0x%02x\n", stm->option1);
	fprintf(diag, "Option 2     : 0x%02x\n", stm->option2);
	fprintf(diag, "Device ID    : 0x%04x (%s)\n", stm->pid, stm->dev->name);
	fprintf(diag, "- RAM        : %dKiB  (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
	fprintf(diag, "- Flash      : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps);
	fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1);
	fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024);

	uint8_t		buffer[256];
	uint32_t	addr, start, end;
	unsigned int	len;
	int		failed = 0;

	if (rd) {
		fprintf(diag, "\n");

		if ((perr = parser->open(p_st, filename, 1)) != PARSER_ERR_OK) {
			fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr));
			if (perr == PARSER_ERR_SYSTEM) perror(filename);
			goto close;
		}

		if (start_addr || readwrite_len) {
			start = start_addr;
			if (readwrite_len)
				end = start_addr + readwrite_len;
			else
				end = stm->dev->fl_end;
		} else {
			start = stm->dev->fl_start + (spage * stm->dev->fl_ps);
			end = stm->dev->fl_end;
		}
		addr = start;

		if (start < stm->dev->fl_start || end > stm->dev->fl_end) {
			fprintf(stderr, "Specified start & length are invalid\n");
			goto close;
		}

		fflush(diag);
		while(addr < end) {
			uint32_t left	= end - addr;
			len		= sizeof(buffer) > left ? left : sizeof(buffer);
			if (!stm32_read_memory(stm, addr, buffer, len)) {
				fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr);
				goto close;
			}
			if (parser->write(p_st, buffer, len) != PARSER_ERR_OK)
			{
				fprintf(stderr, "Failed to write data to file\n");
				goto close;
			}
			addr += len;

			fprintf(diag,
				"\rRead address 0x%08x (%.2f%%) ",
				addr,
				(100.0f / (float)(end - start)) * (float)(addr - start)
			);
			fflush(diag);
		}
		fprintf(diag,	"Done.\n");
		ret = 0;
		goto close;
	} else if (rp) {
		fprintf(stdout, "Read-Protecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_readprot_memory(stm);
		fprintf(stdout,	"Done.\n");
	} else if (ur) {
		fprintf(stdout, "Read-UnProtecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_runprot_memory(stm);
		fprintf(stdout,	"Done.\n");
	} else if (eraseOnly) {
		ret = 0;
		fprintf(stdout, "Erasing flash\n");
		if (start_addr || readwrite_len) {
			if ((start_addr % stm->dev->fl_ps) != 0
			    || (readwrite_len % stm->dev->fl_ps) != 0) {
				fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n");
				ret = 1;
				goto close;
			}
			spage = (start_addr - stm->dev->fl_start) / stm->dev->fl_ps;
			if (readwrite_len)
				npages = readwrite_len / stm->dev->fl_ps;
			else
				npages = (stm->dev->fl_end - stm->dev->fl_start) / stm->dev->fl_ps;
		}

		if (!spage && !npages)
			npages = 0xff; /* mass erase */

		if (!stm32_erase_memory(stm, spage, npages)) {
			fprintf(stderr, "Failed to erase memory\n");
			ret = 1;
			goto close;
		}
		
	} else if (wu) {
		fprintf(diag, "Write-unprotecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
		reset_flag = 0;
		stm32_wunprot_memory(stm);
		fprintf(diag,	"Done.\n");

	} else if (wr) {
		fprintf(diag, "\n");

		off_t 	offset = 0;
		ssize_t r;
		unsigned int size;

		/* Assume data from stdin is whole device */
		if (filename[0] == '-')
			size = stm->dev->fl_end - stm->dev->fl_start;
		else
			size = parser->size(p_st);

		if (start_addr || readwrite_len) {
			start = start_addr;
			spage = (start_addr - stm->dev->fl_start) / stm->dev->fl_ps;
			if (readwrite_len) {
				end = start_addr + readwrite_len;
				npages = (end - stm->dev->fl_start + stm->dev->fl_ps - 1) / stm->dev->fl_ps - spage;
			} else {
				end = stm->dev->fl_end;
				if (spage)
					npages = (end - stm->dev->fl_start) / stm->dev->fl_ps - spage;
				else
					npages = 0xff; /* mass erase */
			}
		} else if (!spage && !npages) {
			start = stm->dev->fl_start;
			end = stm->dev->fl_end;
			npages = 0xff; /* mass erase */
		} else {
			start = stm->dev->fl_start + (spage * stm->dev->fl_ps);
			if (npages)
				end = start + npages * stm->dev->fl_ps;
			else
				end = stm->dev->fl_end;
		}
		addr = start;

		if (start < stm->dev->fl_start || end > stm->dev->fl_end) {
			fprintf(stderr, "Specified start & length are invalid\n");
			goto close;
		}

		// TODO: It is possible to write to non-page boundaries, by reading out flash
		//       from partial pages and combining with the input data
		// if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) {
		//	fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n");
		//	goto close;
		// } 

		// TODO: If writes are not page aligned, we should probably read out existing flash
		//       contents first, so it can be preserved and combined with new data
		if (!stm32_erase_memory(stm, spage, npages)) {
			fprintf(stderr, "Failed to erase memory\n");
			goto close;
		}

		fflush(diag);
		while(addr < end && offset < size) {
			uint32_t left	= end - addr;
			len		= sizeof(buffer) > left ? left : sizeof(buffer);
			len		= len > size - offset ? size - offset : len;

			if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK)
				goto close;

			if (len == 0) {
				if (filename[0] == '-') {
					break;
				} else {
					fprintf(stderr, "Failed to read input file\n");
					goto close;
				}
			}
	
			again:
			if (!stm32_write_memory(stm, addr, buffer, len)) {
				fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr);
				goto close;
			}

			if (verify) {
				uint8_t compare[len];
				if (!stm32_read_memory(stm, addr, compare, len)) {
					fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr);
					goto close;
				}

				for(r = 0; r < len; ++r)
					if (buffer[r] != compare[r]) {
						if (failed == retry) {
							fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n",
								(uint32_t)(addr + r),
								buffer [r],
								compare[r]
							);
							goto close;
						}
						++failed;
						goto again;
					}

				failed = 0;
			}

			addr	+= len;
			offset	+= len;

			fprintf(diag,
				"\rWrote %saddress 0x%08x (%.2f%%) ",
				verify ? "and verified " : "",
				addr,
				(100.0f / size) * offset
			);
			fflush(diag);

		}

		fprintf(diag,	"Done.\n");
		ret = 0;
		goto close;
	} else
		ret = 0;

close:
	if (stm && exec_flag && ret == 0) {
		if (execute == 0)
			execute = stm->dev->fl_start;

		fprintf(diag, "\nStarting execution at address 0x%08x... ", execute);
		fflush(diag);
		if (stm32_go(stm, execute)) {
			reset_flag = 0;
			fprintf(diag, "done.\n");
		} else
			fprintf(diag, "failed.\n");
	}

	if (stm && reset_flag) {
		fprintf(diag, "\nResetting device... ");
		fflush(diag);
		if (init_bl_exit(stm, serial, gpio_seq))
			fprintf(diag, "done.\n");
		else	fprintf(diag, "failed.\n");
	}

	if (p_st  ) parser->close(p_st);
	if (stm   ) stm32_close  (stm);
	if (serial) serial_close (serial);

	fprintf(diag, "\n");
	return ret;
}