Quelltext /~heha/hsn/bl/stm32flash.zip/src/main.cpp

#include "init.h"
#include "stm32.h"
#include "parsers/parser.h"
#include "port.h"
#include "gpsystem.h"	// advanced getopt: excerpt from gputils project

#define VERSION "STM32duino_0.5.1"

// global object pointers
static stm32	*stm;		// one class
static Parser	*parser;	// either Binary or Intel-Hex
static Port	*port;		// either Serial or I²C

// settings
static port_options port_opts = {
  NULL,
  57600,"8e1",
  0,
  stm32::MAX_RX_FRAME,
  stm32::MAX_TX_FRAME,
};

enum actions {
 ACT_NONE,
 ACT_READ,
 ACT_WRITE,
 ACT_WRITE_UNPROTECT,
 ACT_READ_PROTECT,
 ACT_READ_UNPROTECT,
 ACT_ERASE_ONLY,
 ACT_CRC
};

static	actions	action = ACT_NONE;
static	int	npages;
static	int	spage;
static	bool	no_erase        = false;
static	bool	verify		= false;
static	bool	init_flag	= true;
static	bool	use_stdinout	= false;
static	bool	force_binary	= false;
static	bool	exec_flag	= false;
static	bool	reset_flag	= false;
static	int	retry		= 10;
static	uint32_t execute;
	FILE	*diag;
static	char	*filename;
static	char	*gpio_seq;
static uint32_t start_addr;
static uint32_t readwrite_len;

static const char *action2str(enum actions act) {
 switch (act) {
  case ACT_READ		: return "memory read";
  case ACT_WRITE	: return "memory write";
  case ACT_WRITE_UNPROTECT:return "write unprotect";
  case ACT_READ_PROTECT	: return "read protect";
  case ACT_READ_UNPROTECT:return "read unprotect";
  case ACT_ERASE_ONLY	: return "flash erase";
  case ACT_CRC		: return "memory crc";
  default		: return "";
 }
}

static void err_multi_action(enum actions _new) {
 fprintf(stderr,
	"ERROR: Invalid options !\n"
	"\tCan't execute \"%s\" and \"%s\" at the same time.\n",
	action2str(action), action2str(_new));
}

#ifdef _WIN32
BOOL CtrlHandler( DWORD fdwCtrlType ) {
 fprintf(stderr, "\nCaught signal %lu\n",fdwCtrlType);
#else
void sighandler(int s){
 fprintf(stderr, "\nCaught signal %d\n",s);
#endif
 if (parser) delete parser;
 if (stm) delete stm;
 if (port) delete port;
 exit(1);
}

static void show_help(const char*name) {
 fprintf(stderr,
	"Usage: %s [-bvngfhc] [-[rw] filename] {tty_device | i2c_device}\n"
	"	-a bus_address	Bus address (for I2C port)\n"
	"	-b rate		Baud rate (default 57600)\n"
	"	-m mode		Serial port mode (default 8e1)\n"
	"	-r filename	Read flash to file (or - stdout)\n"
	"	-w filename	Write flash from file (or - stdout)\n"
	"	-C		Compute CRC of flash content\n"
	"	-u		Disable the flash write-protection\n"
	"	-j		Enable the flash read-protection\n"
	"	-k		Disable the flash read-protection\n"
	"	-o		Erase only\n"
	"	-e n		Only erase n pages before writing the flash\n"
	"	-v		Verify writes\n"
	"	-n count	Retry failed writes up to count times (default 10)\n"
	"	-g address	Start execution at specified address (0 = flash start)\n"
	"	-S address[:length]	Specify start address and optionally length for\n"
	"	                   	read/write/erase operations\n"
	"	-F RX_length[:TX_length]  Specify the max length of RX and TX frame\n"
	"	-s start_page	Flash at specified page (0 = flash start)\n"
	"	-f		Force binary parser\n"
	"	-h		Show this help\n"
	"	-c		Resume the connection (don't send initial INIT)\n"
	"			*Baud rate must be kept the same as the first init*\n"
	"			This is useful if the reset fails\n"
	"	-R		Reset device at exit.\n"
	"	-i GPIO_string	GPIO sequence to enter/exit bootloader mode\n"
	"			GPIO_string=[entry_seq][:[exit_seq]]\n"
	"			sequence=[[-]signal]&|,[sequence]\n"
	"\n"
	"GPIO sequence:\n"
	"	The following signals can appear in a sequence:\n"
	"	  Integer number representing GPIO pin\n"
	"	  'dtr', 'rts' or 'brk' representing serial port signal\n"
	"	The sequence can use the following delimiters:\n"
	"	  ',' adds 100 ms delay between signals\n"
	"	  '&' adds no delay between signals\n"
	"	The following modifiers can be prepended to a signal:\n"
	"	  '-' reset signal (low) instead of setting it (high)\n"
	"\n"
	"Examples:\n"
	"	Get device information:\n"
	"		%s /dev/ttyS0\n"
	"	  or:\n"
	"		%s /dev/i2c-0\n"
	"\n"
	"	Write with verify and then start execution:\n"
	"		%s -w filename -v -g 0x0 /dev/ttyS0\n"
	"\n"
	"	Read flash to file:\n"
	"		%s -r filename /dev/ttyS0\n"
	"\n"
	"	Read 100 bytes of flash from 0x1000 to stdout:\n"
	"		%s -r - -S 0x1000:100 /dev/ttyS0\n"
	"\n"
	"	Start execution:\n"
	"		%s -g 0x0 /dev/ttyS0\n"
	"\n"
	"	GPIO sequence:\n"
	"	- entry sequence: GPIO_3=low, GPIO_2=low, 100ms delay, GPIO_2=high\n"
	"	- exit sequence: GPIO_3=high, GPIO_2=low, 300ms delay, GPIO_2=high\n"
	"		%s -i '-3&-2,2:3&-2,,,2' /dev/ttyS0\n"
	"	GPIO sequence adding delay after port opening:\n"
	"	- entry sequence: delay 500ms\n"
	"	- exit sequence: rts=high, dtr=low, 300ms delay, GPIO_2=high\n"
	"		%s -R -i ',,,,,:rts&-dtr,,,2' /dev/ttyS0\n",
	name,name,name,name,name,name,name,name,name);
}

static const char opts[]=
  "a\1bus_address\0"
  "b\1rate\0"
  "m\1mode\0"
  "r\1filename\0"
  "w\1filename\0"
  "C\0"
  "u\0"
  "j\0"
  "k\0"
  "o\0"
  "e\1n\0"
  "v\0"
  "n\1count\0"
  "g\1address\0"
  "S\1address[:length]\0"
  "F\1RX_length[:TX_length]\0"
  "s\1start_page\0"
  "f\0"
  "h\0"
  "c\0"
  "R\0"
  "i\1GPIO_string\0";

static void parse_options(void*p,char c, const char *arg) {
 const char*argv0=reinterpret_cast<const char*>(p);
 switch(c) {
  case 'a': port_opts.bus_addr = strtoul(arg, NULL, 0); break;
  case 'b': port_opts.baudRate = strtoul(arg, NULL, 0);
  if (!port_opts.baudRate) {
   fprintf(stderr,"Invalid baud rate\n");
   exit(1);
  }break;
  case 'm': if (strlen(arg)!=3) {
   fprintf(stderr, "Invalid serial mode\n");
   exit(1);
  }
  memcpy(port_opts.mode,arg,3);	// allowed '5','6','7','8' / 'n','o','e','0','1' / '1','2','5'
  break;

  case 'r':
  case 'w':
	if (action != ACT_NONE) {
		err_multi_action((c == 'r') ? ACT_READ : ACT_WRITE);
		exit(1);
	}
	action = (c == 'r') ? ACT_READ : ACT_WRITE;
	filename = (char*)arg;
	if (filename[0] == '-' && filename[1] == '\0') {
		use_stdinout = true;
		force_binary = true;
	}
	break;
  case 'e':
	if (readwrite_len || start_addr) {
		fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n");
		exit(1);
	}
	npages = strtoul(arg, NULL, 0);
	if (npages > stm32::MAX_PAGES || npages < 0) {
		fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255");
		exit(1);
	}
	if (!npages)
		no_erase = true;
	break;
  case 'u':
	if (action != ACT_NONE) {
		err_multi_action(ACT_WRITE_UNPROTECT);
		exit(1);
	}
	action = ACT_WRITE_UNPROTECT;
	break;

  case 'j':
	if (action != ACT_NONE) {
		err_multi_action(ACT_READ_PROTECT);
		exit(1);
	}
	action = ACT_READ_PROTECT;
	break;

  case 'k':
	if (action != ACT_NONE) {
		err_multi_action(ACT_READ_UNPROTECT);
		exit(1);
	}
	action = ACT_READ_UNPROTECT;
	break;

  case 'o':
	if (action != ACT_NONE) {
		err_multi_action(ACT_ERASE_ONLY);
		exit(1);
	}
	action = ACT_ERASE_ONLY;
	break;

  case 'v':
	verify = true;
	break;

  case 'n':
	retry = strtoul(arg, NULL, 0);
	break;

  case 'g':
	exec_flag = true;
	execute   = strtoul(arg, NULL, 0);
	if (execute % 4 != 0) {
		fprintf(stderr, "ERROR: Execution address must be word-aligned\n");
		exit(1);
	}
	break;
  case 's':
	if (readwrite_len || start_addr) {
		fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n");
		exit(1);
	}
	spage    = strtoul(arg, NULL, 0);
	break;
  case 'S':
	if (spage || npages) {
		fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n");
		exit(1);
	} else {
	 char *pLen;
		start_addr = strtoul(arg, &pLen, 0);
		if (*pLen == ':') {
			pLen++;
			readwrite_len = strtoul(pLen, NULL, 0);
			if (readwrite_len == 0) {
				fprintf(stderr, "ERROR: Invalid options, can't specify zero length\n");
				exit(1);
			}
		}
	}
	break;
  case 'F': {
   char *pLen;
   port_opts.rx_frame_max = strtoul(arg, &pLen, 0);
   if (*pLen == ':') port_opts.tx_frame_max = strtoul(++pLen, NULL, 0);
   if (port_opts.rx_frame_max < 0
    || port_opts.tx_frame_max < 0) {
    fprintf(stderr, "ERROR: Invalid negative value for option -F\n");
    exit(1);
   }
   if (!port_opts.rx_frame_max) port_opts.rx_frame_max = stm32::MAX_RX_FRAME;
   if (!port_opts.tx_frame_max) port_opts.tx_frame_max = stm32::MAX_TX_FRAME;
   if (port_opts.rx_frame_max < 20
    || port_opts.tx_frame_max < 6) {
    fprintf(stderr, "ERROR: current code cannot work with small frames.\n");
    fprintf(stderr, "min(RX) = 20, min(TX) = 6\n");
    exit(1);
   }
   if (port_opts.rx_frame_max > stm32::MAX_RX_FRAME) {
    fprintf(stderr, "WARNING: Ignore RX length in option -F\n");
    port_opts.rx_frame_max = stm32::MAX_RX_FRAME;
   }
   if (port_opts.tx_frame_max > stm32::MAX_TX_FRAME) {
    fprintf(stderr, "WARNING: Ignore TX length in option -F\n");
    port_opts.tx_frame_max = stm32::MAX_TX_FRAME;
   }
  }break;
  case 'f': force_binary = true; break;
  case 'c': init_flag = false; break;
  case 'h': show_help(argv0); exit(0);
  case 'i': gpio_seq = (char*)arg; break;
  case 'R': reset_flag = true; break;
  case 'C': if (action != ACT_NONE) {
   err_multi_action(ACT_CRC);
   exit(1);
  }
  action = ACT_CRC;
  break;
  case 0: if (port_opts.device) {
   fprintf(stderr, "ERROR: Invalid parameter specified\n");
   show_help(argv0);
   exit(1);
  }
  port_opts.device = arg; break;

  default: {
   fprintf(stderr, "ERROR: Invalid parameter specified\n");
   show_help(argv0);
  }
 }
}

int __cdecl main(int argc, char* argv[]) {
 int ret = 1;
 int failed = 0;
 stm32::err_t s_err;
 Parser::err_t perr;
	diag = stdout;

 gp_getopt(argv,opts,parse_options,argv[0]);

 if (!port_opts.device) port_opts.device=Port::find_com();
 if (!port_opts.device) {
  fprintf(stderr, "ERROR: Device not specified\n");
  show_help(argv[0]);
  return 1;
 }

 if ((action != ACT_WRITE) && verify) {
  fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n");
  show_help(argv[0]);
  return 1;
 }

 if (action == ACT_READ && use_stdinout) {
  diag = stderr;
 }

//	fprintf(diag, "stm32flash " VERSION "\n\n");
//	fprintf(diag, "https://github.com/stm32duino/stm32flash\n\n");

#ifdef _WIN32
 SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE );
#else
 struct sigaction sigIntHandler;
 sigIntHandler.sa_handler = sighandler;
 sigemptyset(&sigIntHandler.sa_mask);
 sigIntHandler.sa_flags = 0;
 sigaction(SIGINT, &sigIntHandler, NULL);
#endif
 if (action == ACT_WRITE) {
		/* first try hex */
  if (!force_binary) {
   parser = new ParserHex;
  }
  if (force_binary || (perr = parser->open(filename, false))) {
   if (force_binary || perr == Parser::ERR_INVALID_FILE) {
    if (!force_binary) {
     delete parser;
     parser = 0;
    }
				/* now try binary */
    parser = new ParserBin;
    perr = parser->open(filename, 0);
   }
			/* if still have an error, fail */
   if (perr) {
    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 = new ParserBin;
 }
 port=port_open(port_opts);
 if (!port) {
  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());
 if (init_flag && init_bl_entry(*port, gpio_seq)){
  ret = 1;
  fprintf(stderr, "Failed to send boot enter sequence\n");
  goto close;
 }
 port->flush();

 stm = new stm32(*port, init_flag);
 if (!*stm) goto close;

 fprintf(diag, "Version      : 0x%02x\n", stm->bl_version);
  if (port->flags & Port::F_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%s)\n", stm->pid, stm->dev->flags&F_GEN?"":"STM32",stm->dev->sname);
  fprintf(diag, "- RAM        : Up to %dKiB  (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000);
  fprintf(diag, "- Flash      : Up to %dKiB (size first sector: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, 1<<stm->dev->fl_ppsh, 1<<*stm->dev->fl_psh);
  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, len;
   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 (stm->dev->addr_in_flash(start)) end = stm->dev->fl_end;
    else {
     no_erase = true;
    if (stm->dev->addr_in_ram(start)) end = stm->dev->ram_end;
    else if (stm->dev->addr_in_opt_bytes(start)) end = stm->dev->opt_end + 1;
    else if (stm->dev->addr_in_sysmem(start)) end = stm->dev->mem_end;
    else {				/* Unknown territory */
     if (readwrite_len) end = start + readwrite_len;
     else end = start + sizeof(uint32_t);
    }
   }
   if (readwrite_len && (end > start + readwrite_len)) end = start + readwrite_len;
   first_page = stm->dev->flash_addr_to_page(start);
   if (!first_page && end == stm->dev->fl_end) num_pages = stm32::MASS_ERASE;
   else num_pages = stm->dev->flash_addr_to_page(end,true) - first_page;
  }else if (!spage && !npages) {
   start = stm->dev->fl_start;
   end = stm->dev->fl_end;
   first_page = 0;
   num_pages = stm32::MASS_ERASE;
  }else{
   first_page = spage;
   start = stm->dev->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 = stm->dev->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 = stm->dev->flash_addr_to_page(end,true) - first_page;
   }
   if (!first_page && end == stm->dev->fl_end) num_pages = stm32::MASS_ERASE;
  }
  if (action == ACT_READ) {
   unsigned int max_len = port_opts.rx_frame_max;
   fprintf(diag, "Memory read\n");
   perr = parser->open(filename, true);
   if (perr) {
    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 = stm->read_memory(addr, buffer, len);
    if (s_err) {
     fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr);
     goto close;
    }
    if (parser->write(buffer, len)) {
     fprintf(stderr, "Failed to write data to file\n");
     goto close;
    }
    addr += uint32_t(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 (action == ACT_READ_PROTECT) {
   fprintf(diag, "Read-Protecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
   reset_flag = false;
   if (stm->readprot_memory()) {
    fprintf(stderr, "Failed to read-protect flash\n");
    goto close;
   }
   fprintf(diag,"Done.\n");
   ret = 0;
  }else if (action == ACT_READ_UNPROTECT) {
   fprintf(diag, "Read-UnProtecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
   reset_flag = false;
   if (stm->runprot_memory()) {
    fprintf(stderr, "Failed to read-unprotect flash\n");
    goto close;
   }
   fprintf(diag,"Done.\n");
   ret = 0;
  }else if (action == ACT_ERASE_ONLY) {
   ret = 0;
   fprintf(diag, "Erasing flash\n");
   if (num_pages != stm32::MASS_ERASE &&
	    (start != stm->dev->flash_page_to_addr(first_page)
	     || end != stm->dev->flash_page_to_addr(first_page + num_pages))) {
    fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n");
    ret = 1;
    goto close;
   }
   if (stm->erase_memory(first_page, num_pages)) {
    fprintf(stderr, "Failed to erase memory\n");
    ret = 1;
    goto close;
   }
   ret = 0;
  }else if (action == ACT_WRITE_UNPROTECT) {
   fprintf(diag, "Write-unprotecting flash\n");
		/* the device automatically performs a reset after the sending the ACK */
   reset_flag = false;
   if (stm->wunprot_memory()) {
    fprintf(stderr, "Failed to write-unprotect flash\n");
    goto close;
   }
   fprintf(diag,"Done.\n");
   ret = 0;
  }else if (action == ACT_WRITE) {
   uint32_t offset = 0,size;
   unsigned r;
   unsigned max_wlen, max_rlen;
   fprintf(diag, "Write to memory\n");
   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 (use_stdinout) size = end - start;
   else size = uint32_t(parser->size());
		// 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[i]) != 0 || (end % stm->dev->fl_ps[i]) != 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");
    if (stm->erase_memory(first_page, num_pages)) {
     fprintf(stderr, "Failed to erase memory\n");
     goto close;
    }
   }
   fflush(diag);
   addr = start;
   while(addr < end && offset < size) {
	uint32_t left	= end - addr;
	unsigned len	= max_wlen > left ? left : max_wlen;
	len		= len > size - offset ? size - offset : len;
    if (parser->read(buffer, len)) goto close;
    if (!len) {
     if (use_stdinout) {
      break;
     } else {
      fprintf(stderr, "Failed to read input file\n");
      goto close;
     }
    }
again:
    s_err = stm->write_memory(addr, buffer, len);
    if (s_err) {
     fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr);
     goto close;
    }
    if (verify) {
     uint8_t*compare=new uint8_t[len];
     unsigned offset=0, rlen;
     while (offset < len) {
      rlen = uint32_t(len) - offset;
      rlen = rlen < max_rlen ? rlen : max_rlen;
      s_err = stm->read_memory(addr + offset, compare + offset, rlen);
      if (s_err) {
       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 (action == ACT_CRC) {
   uint32_t crc_val = 0;
   fprintf(diag, "CRC computation\n");
   if (stm->crc_wrapper(start, end - start, crc_val)) {
    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) execute = stm->dev->fl_start;
   fprintf(diag, "\nStarting execution at address 0x%08x... ", execute);
   fflush(diag);
   if (!stm->go(execute)) {
    reset_flag = false;
    fprintf(diag, "done.\n");
   }else fprintf(diag, "failed.\n");
  }
  if (stm && reset_flag) {
   fprintf(diag, "\nResetting device... \n");
   fflush(diag);
   if (init_bl_exit(*stm,*port, gpio_seq)) {
    ret = 1;
    fprintf(diag, "Reset failed.\n");
   }else fprintf(diag, "Reset done.\n");
  }else if (port) {
		/* Always run exit sequence if present */
   if (gpio_seq && strchr(gpio_seq, ':')) ret = gpio_bl_exit(*port, gpio_seq) || ret;
  }
  if (parser) delete parser;
  if (stm) delete stm;
  if (port) delete port;
  fprintf(diag, "\n");
  return ret;
 }
}

EXTERN_C void __cdecl _fltused(void) {}
#ifdef UNICODE
void mainCRTStartup() {
 int argc;
 wchar_t**argvW=CommandLineToArgvW(GetCommandLine(),&argc);
 char**argv=new char*[argc+1],**argvP=argv;
 for (int i=0; i<argc; i++,argvP++) {
  int len=WideCharToMultiByte(CP_UTF8,0,argvW[i],-1,0,0,0,0);
  *argvP=new char[len];
  WideCharToMultiByte(CP_UTF8,0,argvW[i],-1,*argvP,len,0,0);
 }
 *argvP=0;
 LocalFree(argvW);
 ExitProcess(main(argc,argv));	// argv in UTF-8 übergeben
}
#else
EXTERN_C _CRTIMP int __cdecl __getmainargs(int*,char***,char***,int);
void mainCRTStartup() {
 int argc;
 char**argv,**envp;
 __getmainargs(&argc,&argv,&envp,TRUE);	// geht irgendwie nicht in x64
 ExitProcess(main(argc,argv));
}
#endif
Vorgefundene Kodierung: ANSI (CP1252)4
Umlaute falsch? - Datei sei ANSI-kodiert (CP1252)