diff options
author | bubnikv <bubnikv@gmail.com> | 2018-07-16 18:07:49 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2018-07-16 18:07:49 +0300 |
commit | 6dc1bf5c08b7935dfbc55d35dea31148d09732f8 (patch) | |
tree | 862e4d4149e6cd7fceb03208c3f3bcbfa1625301 /xs/src/avrdude | |
parent | 0bbd1dbc4f80ee4909f84d91931c13d757ba0af7 (diff) | |
parent | d99b484ac6e67f00666530a1d7b78e7506e2ce6c (diff) |
Merge branch 'master' into stable
Diffstat (limited to 'xs/src/avrdude')
-rw-r--r-- | xs/src/avrdude/arduino.c | 56 | ||||
-rw-r--r-- | xs/src/avrdude/avrdude-slic3r.cpp | 48 | ||||
-rw-r--r-- | xs/src/avrdude/avrdude-slic3r.hpp | 23 | ||||
-rw-r--r-- | xs/src/avrdude/avrpart.c | 10 | ||||
-rw-r--r-- | xs/src/avrdude/fileio.c | 69 | ||||
-rw-r--r-- | xs/src/avrdude/libavrdude.h | 7 | ||||
-rw-r--r-- | xs/src/avrdude/main.c | 4 | ||||
-rw-r--r-- | xs/src/avrdude/ser_posix.c | 4 | ||||
-rw-r--r-- | xs/src/avrdude/stk500.c | 123 | ||||
-rw-r--r-- | xs/src/avrdude/stk500v2.c | 17 | ||||
-rw-r--r-- | xs/src/avrdude/update.c | 37 |
11 files changed, 286 insertions, 112 deletions
diff --git a/xs/src/avrdude/arduino.c b/xs/src/avrdude/arduino.c index 566f56abd..5a9cb465e 100644 --- a/xs/src/avrdude/arduino.c +++ b/xs/src/avrdude/arduino.c @@ -80,6 +80,49 @@ static int arduino_read_sig_bytes(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m) return 3; } +static int prusa_init_external_flash(PROGRAMMER * pgm) +{ + // Note: send/receive as in _the firmare_ send & receives + const char entry_magic_send [] = "start\n"; + const char entry_magic_receive[] = "w25x20cl_enter\n"; + const char entry_magic_cfm [] = "w25x20cl_cfm\n"; + const size_t buffer_len = 32; // Should be large enough for the above messages + + int res; + size_t recv_size; + char *buffer = alloca(buffer_len); + + // 1. receive the "start" command + recv_size = sizeof(entry_magic_send) - 1; + res = serial_recv(&pgm->fd, buffer, recv_size); + if (res < 0) { + avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname); + return -1; + } else if (strncmp(buffer, entry_magic_send, recv_size) != 0) { + avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer emitted incorrect start code: `%*s`\n", progname, recv_size, buffer); + return -1; + } + + // 2. Send the external flash programmer enter command + if (serial_send(&pgm->fd, entry_magic_receive, sizeof(entry_magic_receive) - 1) < 0) { + avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): Failed to send command to the printer\n",progname); + return -1; + } + + // 3. Receive the entry confirmation command + recv_size = sizeof(entry_magic_cfm) - 1; + res = serial_recv(&pgm->fd, buffer, recv_size); + if (res < 0) { + avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer did not boot up on time or serial communication failed\n", progname); + return -1; + } else if (strncmp(buffer, entry_magic_cfm, recv_size) != 0) { + avrdude_message(MSG_INFO, "%s: prusa_init_external_flash(): MK3 printer emitted incorrect cfm code: `%*s`\n", progname, recv_size, buffer); + return -1; + } + + return 0; +} + static int arduino_open(PROGRAMMER * pgm, char * port) { union pinfo pinfo; @@ -97,11 +140,24 @@ static int arduino_open(PROGRAMMER * pgm, char * port) serial_set_dtr_rts(&pgm->fd, 1); usleep(50*1000); + // Sometimes there may be line noise generating input on the printer's USB-to-serial IC + // Here we try to clean its input buffer with a sequence of newlines (a minimum of 9 is needed): + const char cleanup_newlines[] = "\n\n\n\n\n\n\n\n\n\n"; + if (serial_send(&pgm->fd, cleanup_newlines, sizeof(cleanup_newlines) - 1) < 0) { + return -1; + } + /* * drain any extraneous input */ stk500_drain(pgm, 0); + // Initialization sequence for programming the external FLASH on the Prusa MK3 + if (prusa_init_external_flash(pgm) < 0) { + avrdude_message(MSG_INFO, "%s: arduino_open(): Failed to initialize MK3 external flash programming mode\n", progname); + return -1; + } + if (stk500_getsync(pgm) < 0) return -1; diff --git a/xs/src/avrdude/avrdude-slic3r.cpp b/xs/src/avrdude/avrdude-slic3r.cpp index a859200fb..030353413 100644 --- a/xs/src/avrdude/avrdude-slic3r.cpp +++ b/xs/src/avrdude/avrdude-slic3r.cpp @@ -1,5 +1,6 @@ #include "avrdude-slic3r.hpp" +#include <deque> #include <thread> extern "C" { @@ -33,17 +34,22 @@ static void avrdude_progress_handler_closure(const char *task, unsigned progress struct AvrDude::priv { std::string sys_config; - std::vector<std::string> args; + std::deque<std::vector<std::string>> args; + size_t current_args_set = 0; + RunFn run_fn; MessageFn message_fn; ProgressFn progress_fn; CompleteFn complete_fn; std::thread avrdude_thread; + priv(std::string &&sys_config) : sys_config(sys_config) {} + + int run_one(const std::vector<std::string> &args); int run(); }; -int AvrDude::priv::run() { +int AvrDude::priv::run_one(const std::vector<std::string> &args) { std::vector<char*> c_args {{ const_cast<char*>(PACKAGE_NAME) }}; for (const auto &arg : args) { c_args.push_back(const_cast<char*>(arg.data())); @@ -68,10 +74,22 @@ int AvrDude::priv::run() { return res; } +int AvrDude::priv::run() { + for (; args.size() > 0; current_args_set++) { + int res = run_one(args.front()); + args.pop_front(); + if (res != 0) { + return res; + } + } + + return 0; +} + // Public -AvrDude::AvrDude() : p(new priv()) {} +AvrDude::AvrDude(std::string sys_config) : p(new priv(std::move(sys_config))) {} AvrDude::AvrDude(AvrDude &&other) : p(std::move(other.p)) {} @@ -82,15 +100,15 @@ AvrDude::~AvrDude() } } -AvrDude& AvrDude::sys_config(std::string sys_config) +AvrDude& AvrDude::push_args(std::vector<std::string> args) { - if (p) { p->sys_config = std::move(sys_config); } + if (p) { p->args.push_back(std::move(args)); } return *this; } -AvrDude& AvrDude::args(std::vector<std::string> args) +AvrDude& AvrDude::on_run(RunFn fn) { - if (p) { p->args = std::move(args); } + if (p) { p->run_fn = std::move(fn); } return *this; } @@ -123,11 +141,17 @@ AvrDude::Ptr AvrDude::run() if (self->p) { auto avrdude_thread = std::thread([self]() { - auto res = self->p->run(); - if (self->p->complete_fn) { - self->p->complete_fn(res); - } - }); + if (self->p->run_fn) { + self->p->run_fn(); + } + + auto res = self->p->run(); + + if (self->p->complete_fn) { + self->p->complete_fn(res, self->p->current_args_set); + } + }); + self->p->avrdude_thread = std::move(avrdude_thread); } diff --git a/xs/src/avrdude/avrdude-slic3r.hpp b/xs/src/avrdude/avrdude-slic3r.hpp index 8d881b094..273aa2378 100644 --- a/xs/src/avrdude/avrdude-slic3r.hpp +++ b/xs/src/avrdude/avrdude-slic3r.hpp @@ -12,22 +12,28 @@ class AvrDude { public: typedef std::shared_ptr<AvrDude> Ptr; + typedef std::function<void()> RunFn; typedef std::function<void(const char * /* msg */, unsigned /* size */)> MessageFn; typedef std::function<void(const char * /* task */, unsigned /* progress */)> ProgressFn; - typedef std::function<void(int /* exit status */)> CompleteFn; + typedef std::function<void(int /* exit status */, size_t /* args_id */)> CompleteFn; - AvrDude(); + // Main c-tor, sys_config is the location of avrdude's main configuration file + AvrDude(std::string sys_config); AvrDude(AvrDude &&); AvrDude(const AvrDude &) = delete; AvrDude &operator=(AvrDude &&) = delete; AvrDude &operator=(const AvrDude &) = delete; ~AvrDude(); - // Set location of avrdude's main configuration file - AvrDude& sys_config(std::string sys_config); + // Push a set of avrdude cli arguments + // Each set makes one avrdude invocation - use this method multiple times to push + // more than one avrdude invocations. + AvrDude& push_args(std::vector<std::string> args); - // Set avrdude cli arguments - AvrDude& args(std::vector<std::string> args); + // Set a callback to be called just after run() before avrdude is ran + // This can be used to perform any needed setup tasks from the background thread. + // This has no effect when using run_sync(). + AvrDude& on_run(RunFn fn); // Set message output callback AvrDude& on_message(MessageFn fn); @@ -36,7 +42,10 @@ public: // Progress is reported per each task (reading / writing) in percents. AvrDude& on_progress(ProgressFn fn); - // Called when avrdude's main function finishes + // Called when the last avrdude invocation finishes with the exit status of zero, + // or earlier, if one of the invocations return a non-zero status. + // The second argument contains the sequential id of the last avrdude invocation argument set. + // This has no effect when using run_sync(). AvrDude& on_complete(CompleteFn fn); int run_sync(); diff --git a/xs/src/avrdude/avrpart.c b/xs/src/avrdude/avrpart.c index 621a85b98..b04851ac1 100644 --- a/xs/src/avrdude/avrpart.c +++ b/xs/src/avrdude/avrpart.c @@ -378,7 +378,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type, char * optr; if (m == NULL) { - fprintf(f, + avrdude_message(MSG_INFO, "%s Block Poll Page Polled\n" "%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" "%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", @@ -386,13 +386,13 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type, } else { if (verbose > 2) { - fprintf(f, + avrdude_message(MSG_INFO, "%s Block Poll Page Polled\n" "%sMemory Type Mode Delay Size Indx Paged Size Size #Pages MinW MaxW ReadBack\n" "%s----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------\n", prefix, prefix, prefix); } - fprintf(f, + avrdude_message(MSG_INFO, "%s%-11s %4d %5d %5d %4d %-6s %6d %4d %6d %5d %5d 0x%02x 0x%02x\n", prefix, m->desc, m->mode, m->delay, m->blocksize, m->pollindex, m->paged ? "yes" : "no", @@ -415,7 +415,7 @@ void avr_mem_display(const char * prefix, FILE * f, AVRMEM * m, int type, optr = avr_op_str(i); else optr = " "; - fprintf(f, + avrdude_message(MSG_INFO, "%s %-11s %8d %8s %5d %5d\n", prefix, optr, j, bittype(m->op[i]->bit[j].type), @@ -620,7 +620,7 @@ void avr_display(FILE * f, AVRPART * p, const char * prefix, int verbose) LNODEID ln; AVRMEM * m; - fprintf(f, + avrdude_message(MSG_INFO, "%sAVR Part : %s\n" "%sChip Erase delay : %d us\n" "%sPAGEL : P%02X\n" diff --git a/xs/src/avrdude/fileio.c b/xs/src/avrdude/fileio.c index f2d617823..aa57f5587 100644 --- a/xs/src/avrdude/fileio.c +++ b/xs/src/avrdude/fileio.c @@ -45,6 +45,8 @@ #define MAX_LINE_LEN 256 /* max line length for ASCII format input files */ +#define MAX_MODE_LEN 32 // For fopen_and_seek() + struct ihexrec { unsigned char reclen; @@ -96,8 +98,40 @@ static int fileio_num(struct fioparms * fio, char * filename, FILE * f, AVRMEM * mem, int size, FILEFMT fmt); -static int fmt_autodetect(char * fname); +static int fmt_autodetect(char * fname, size_t offset); + + + +static FILE *fopen_and_seek(const char *filename, const char *mode, size_t offset) +{ + FILE *file; + // On Windows we need to convert the filename to UTF-16 +#if defined(WIN32NATIVE) + static wchar_t fname_buffer[PATH_MAX]; + static wchar_t mode_buffer[MAX_MODE_LEN]; + + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, fname_buffer, PATH_MAX) == 0) { return NULL; } + if (MultiByteToWideChar(CP_ACP, 0, mode, -1, mode_buffer, MAX_MODE_LEN) == 0) { return NULL; } + + file = _wfopen(fname_buffer, mode_buffer); +#else + file = fopen(filename, mode); +#endif + + if (file != NULL) { + // Some systems allow seeking past the end of file, so we need check for that first and disallow + if (fseek(file, 0, SEEK_END) != 0 + || offset >= ftell(file) + || fseek(file, offset, SEEK_SET) != 0 + ) { + fclose(file); + file = NULL; + errno = EINVAL; + } + } + return file; +} char * fmtstr(FILEFMT format) @@ -1358,7 +1392,7 @@ int fileio_setparms(int op, struct fioparms * fp, -static int fmt_autodetect(char * fname) +static int fmt_autodetect(char * fname, size_t offset) { FILE * f; unsigned char buf[MAX_LINE_LEN]; @@ -1368,10 +1402,11 @@ static int fmt_autodetect(char * fname) int first = 1; #if defined(WIN32NATIVE) - f = fopen(fname, "r"); + f = fopen_and_seek(fname, "r", offset); #else - f = fopen(fname, "rb"); + f = fopen_and_seek(fname, "rb", offset); #endif + if (f == NULL) { avrdude_message(MSG_INFO, "%s: error opening %s: %s\n", progname, fname, strerror(errno)); @@ -1445,7 +1480,7 @@ static int fmt_autodetect(char * fname) int fileio(int op, char * filename, FILEFMT format, - struct avrpart * p, char * memtype, int size) + struct avrpart * p, char * memtype, int size, size_t offset) { int rc; FILE * f; @@ -1477,15 +1512,17 @@ int fileio(int op, char * filename, FILEFMT format, using_stdio = 0; if (strcmp(filename, "-")==0) { - if (fio.op == FIO_READ) { - fname = "<stdin>"; - f = stdin; - } - else { - fname = "<stdout>"; - f = stdout; - } - using_stdio = 1; + return -1; + // Note: we don't want to read stdin or write to stdout as part of Slic3r + // if (fio.op == FIO_READ) { + // fname = "<stdin>"; + // f = stdin; + // } + // else { + // fname = "<stdout>"; + // f = stdout; + // } + // using_stdio = 1; } else { fname = filename; @@ -1502,7 +1539,7 @@ int fileio(int op, char * filename, FILEFMT format, return -1; } - format_detect = fmt_autodetect(fname); + format_detect = fmt_autodetect(fname, offset); if (format_detect < 0) { avrdude_message(MSG_INFO, "%s: can't determine file format for %s, specify explicitly\n", progname, fname); @@ -1533,7 +1570,7 @@ int fileio(int op, char * filename, FILEFMT format, if (format != FMT_IMM) { if (!using_stdio) { - f = fopen(fname, fio.mode); + f = fopen_and_seek(fname, fio.mode, offset); if (f == NULL) { avrdude_message(MSG_INFO, "%s: can't open %s file %s: %s\n", progname, fio.iodesc, fname, strerror(errno)); diff --git a/xs/src/avrdude/libavrdude.h b/xs/src/avrdude/libavrdude.h index e8197f9c2..536f1a2f7 100644 --- a/xs/src/avrdude/libavrdude.h +++ b/xs/src/avrdude/libavrdude.h @@ -737,7 +737,7 @@ extern bool cancel_flag; #define RETURN_IF_CANCEL() \ do { \ if (cancel_flag) { \ - avrdude_message(MSG_INFO, "%s(): Cancelled, exiting...\n", __func__); \ + avrdude_message(MSG_INFO, "avrdude: %s(): Cancelled, exiting...\n", __func__); \ return -99; \ } \ } while (0) @@ -821,7 +821,7 @@ extern "C" { char * fmtstr(FILEFMT format); int fileio(int op, char * filename, FILEFMT format, - struct avrpart * p, char * memtype, int size); + struct avrpart * p, char * memtype, int size, size_t offset); #ifdef __cplusplus } @@ -870,6 +870,7 @@ enum updateflags { typedef struct update_t { char * memtype; int op; + size_t offset; char * filename; int format; } UPDATE; @@ -881,7 +882,7 @@ extern "C" { extern UPDATE * parse_op(char * s); extern UPDATE * dup_update(UPDATE * upd); extern UPDATE * new_update(int op, char * memtype, int filefmt, - char * filename); + char * filename, size_t offset); extern void free_update(UPDATE * upd); extern int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags flags); diff --git a/xs/src/avrdude/main.c b/xs/src/avrdude/main.c index 0550ceff1..d4c34fe44 100644 --- a/xs/src/avrdude/main.c +++ b/xs/src/avrdude/main.c @@ -194,7 +194,7 @@ static void usage(void) " -F Override invalid signature check.\n" " -e Perform a chip erase.\n" " -O Perform RC oscillator calibration (see AVR053). \n" - " -U <memtype>:r|w|v:<filename>[:format]\n" + " -U <memtype>:r|w|v:<offset>:<filename>[:format]\n" " Memory operation specification.\n" " Multiple -U options are allowed, each request\n" " is performed in the order specified.\n" @@ -374,7 +374,7 @@ static void list_parts(FILE * f, const char *prefix, LISTID avrparts) static int cleanup_main(int status) { - if (pgm_setup && pgm->teardown) { + if (pgm_setup && pgm != NULL && pgm->teardown) { pgm->teardown(pgm); } diff --git a/xs/src/avrdude/ser_posix.c b/xs/src/avrdude/ser_posix.c index 91b18e945..cb0fc0385 100644 --- a/xs/src/avrdude/ser_posix.c +++ b/xs/src/avrdude/ser_posix.c @@ -376,6 +376,10 @@ static int ser_recv(union filedescriptor *fd, unsigned char * buf, size_t buflen FD_SET(fd->ifd, &rfds); nfds = select(fd->ifd + 1, &rfds, NULL, NULL, &to2); + // FIXME: The timeout has different behaviour on Linux vs other Unices + // On Linux, the timeout is modified by subtracting the time spent, + // on OS X (for example), it is not modified. + // POSIX recommends re-initializing it before selecting. if (nfds == 0) { avrdude_message(MSG_NOTICE2, "%s: ser_recv(): programmer is not responding\n", progname); diff --git a/xs/src/avrdude/stk500.c b/xs/src/avrdude/stk500.c index 5d2d3c1df..63deb228f 100644 --- a/xs/src/avrdude/stk500.c +++ b/xs/src/avrdude/stk500.c @@ -716,11 +716,14 @@ static int stk500_loadaddr(PROGRAMMER * pgm, AVRMEM * mem, unsigned int addr) } buf[0] = Cmnd_STK_LOAD_ADDRESS; - buf[1] = addr & 0xff; - buf[2] = (addr >> 8) & 0xff; - buf[3] = Sync_CRC_EOP; - - stk500_send(pgm, buf, 4); + // Workaround for the infamous ';' bug in the Prusa3D usb to serial converter. + // Send the binary data by nibbles to avoid transmitting the ';' character. + buf[1] = addr & 0x0f; + buf[2] = addr & 0xf0; + buf[3] = (addr >> 8) & 0x0f; + buf[4] = (addr >> 8) & 0xf0; + buf[5] = Sync_CRC_EOP; + stk500_send(pgm, buf, 6); if (stk500_recv(pgm, buf, 1) < 0) return -1; @@ -765,7 +768,9 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, int block_size; int tries; unsigned int n; - unsigned int i; + unsigned int i, j; + unsigned int prusa3d_semicolon_workaround_round = 0; + bool has_semicolon = false; if (strcmp(m->desc, "flash") == 0) { memtype = 'F'; @@ -806,44 +811,64 @@ static int stk500_paged_write(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, tries++; stk500_loadaddr(pgm, m, addr/a_div); - /* build command block and avoid multiple send commands as it leads to a crash - of the silabs usb serial driver on mac os x */ - i = 0; - buf[i++] = Cmnd_STK_PROG_PAGE; - buf[i++] = (block_size >> 8) & 0xff; - buf[i++] = block_size & 0xff; - buf[i++] = memtype; - memcpy(&buf[i], &m->buf[addr], block_size); - i += block_size; - buf[i++] = Sync_CRC_EOP; - stk500_send( pgm, buf, i); + for (i = 0; i < n_bytes; ++ i) + if (m->buf[addr + i] == ';') { + has_semicolon = true; + break; + } - if (stk500_recv(pgm, buf, 1) < 0) - return -1; - if (buf[0] == Resp_STK_NOSYNC) { - if (tries > 33) { - avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): can't get into sync\n", - progname); - return -3; + for (prusa3d_semicolon_workaround_round = 0; prusa3d_semicolon_workaround_round < (has_semicolon ? 2 : 1); ++ prusa3d_semicolon_workaround_round) { + /* build command block and avoid multiple send commands as it leads to a crash + of the silabs usb serial driver on mac os x */ + i = 0; + buf[i++] = Cmnd_STK_PROG_PAGE; + // Workaround for the infamous ';' bug in the Prusa3D usb to serial converter. + // Send the binary data by nibbles to avoid transmitting the ';' character. + buf[i++] = (block_size >> 8) & 0xf0; + buf[i++] = (block_size >> 8) & 0x0f; + buf[i++] = block_size & 0xf0; + buf[i++] = block_size & 0x0f; + buf[i++] = memtype; + if (has_semicolon) { + for (j = 0; j < block_size; ++i, ++ j) { + buf[i] = m->buf[addr + j]; + if (buf[i] == ';') + buf[i] |= (prusa3d_semicolon_workaround_round ? 0xf0 : 0x0f); + } + } else { + memcpy(&buf[i], &m->buf[addr], block_size); + i += block_size; + } + buf[i++] = Sync_CRC_EOP; + stk500_send( pgm, buf, i); + + if (stk500_recv(pgm, buf, 1) < 0) + return -1; + if (buf[0] == Resp_STK_NOSYNC) { + if (tries > 33) { + avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): can't get into sync\n", + progname); + return -3; + } + if (stk500_getsync(pgm) < 0) + return -1; + goto retry; + } + else if (buf[0] != Resp_STK_INSYNC) { + avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -4; + } + + if (stk500_recv(pgm, buf, 1) < 0) + return -1; + if (buf[0] != Resp_STK_OK) { + avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, " + "expect=0x%02x, resp=0x%02x\n", + progname, Resp_STK_INSYNC, buf[0]); + return -5; } - if (stk500_getsync(pgm) < 0) - return -1; - goto retry; - } - else if (buf[0] != Resp_STK_INSYNC) { - avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, " - "expect=0x%02x, resp=0x%02x\n", - progname, Resp_STK_INSYNC, buf[0]); - return -4; - } - - if (stk500_recv(pgm, buf, 1) < 0) - return -1; - if (buf[0] != Resp_STK_OK) { - avrdude_message(MSG_INFO, "\n%s: stk500_paged_write(): (a) protocol error, " - "expect=0x%02x, resp=0x%02x\n", - progname, Resp_STK_INSYNC, buf[0]); - return -5; } } @@ -893,11 +918,15 @@ static int stk500_paged_load(PROGRAMMER * pgm, AVRPART * p, AVRMEM * m, tries++; stk500_loadaddr(pgm, m, addr/a_div); buf[0] = Cmnd_STK_READ_PAGE; - buf[1] = (block_size >> 8) & 0xff; - buf[2] = block_size & 0xff; - buf[3] = memtype; - buf[4] = Sync_CRC_EOP; - stk500_send(pgm, buf, 5); + // Workaround for the infamous ';' bug in the Prusa3D usb to serial converter. + // Send the binary data by nibbles to avoid transmitting the ';' character. + buf[1] = (block_size >> 8) & 0xf0; + buf[2] = (block_size >> 8) & 0x0f; + buf[3] = block_size & 0xf0; + buf[4] = block_size & 0x0f; + buf[5] = memtype; + buf[6] = Sync_CRC_EOP; + stk500_send(pgm, buf, 7); if (stk500_recv(pgm, buf, 1) < 0) return -1; diff --git a/xs/src/avrdude/stk500v2.c b/xs/src/avrdude/stk500v2.c index d3acb639c..4d62640c0 100644 --- a/xs/src/avrdude/stk500v2.c +++ b/xs/src/avrdude/stk500v2.c @@ -79,7 +79,7 @@ #define SERIAL_TIMEOUT 2 // Retry count -#define RETRIES 5 +#define RETRIES 0 #if 0 #define DEBUG(...) avrdude_message(MSG_INFO, __VA_ARGS__) @@ -745,7 +745,7 @@ static int stk500v2_recv(PROGRAMMER * pgm, unsigned char *msg, size_t maxsize) { -static int stk500v2_getsync_internal(PROGRAMMER * pgm, int retries) { +int stk500v2_getsync(PROGRAMMER * pgm) { int tries = 0; unsigned char buf[1], resp[32]; int status; @@ -804,7 +804,7 @@ retry: progname, pgmname[PDATA(pgm)->pgmtype]); return 0; } else { - if (tries > retries) { + if (tries > RETRIES) { avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): can't communicate with device: resp=0x%02x\n", progname, resp[0]); return -6; @@ -814,7 +814,7 @@ retry: // or if we got a timeout } else if (status == -1) { - if (tries > retries) { + if (tries > RETRIES) { avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): timeout communicating with programmer\n", progname); return -1; @@ -823,7 +823,7 @@ retry: // or any other error } else { - if (tries > retries) { + if (tries > RETRIES) { avrdude_message(MSG_INFO, "%s: stk500v2_getsync(): error communicating with programmer: (%d)\n", progname,status); } else @@ -833,11 +833,6 @@ retry: return 0; } -int stk500v2_getsync(PROGRAMMER * pgm) { - // This is to avoid applying RETRIES exponentially - return stk500v2_getsync_internal(pgm, RETRIES); -} - static int stk500v2_command(PROGRAMMER * pgm, unsigned char * buf, size_t len, size_t maxlen) { int i; @@ -947,7 +942,7 @@ retry: } // otherwise try to sync up again - status = stk500v2_getsync_internal(pgm, 1); + status = stk500v2_getsync(pgm); if (status != 0) { if (tries > RETRIES) { avrdude_message(MSG_INFO, "%s: stk500v2_command(): failed miserably to execute command 0x%02x\n", diff --git a/xs/src/avrdude/update.c b/xs/src/avrdude/update.c index a73461dfa..e9dd6e325 100644 --- a/xs/src/avrdude/update.c +++ b/xs/src/avrdude/update.c @@ -101,6 +101,24 @@ UPDATE * parse_op(char * s) p++; + // Extension: Parse file contents offset + size_t offset = 0; + + for (; *p != ':'; p++) { + if (*p >= '0' && *p <= '9') { + offset *= 10; + offset += *p - 0x30; + } else { + avrdude_message(MSG_INFO, "%s: invalid update specification: offset is not a number\n", progname); + free(upd->memtype); + free(upd); + return NULL; + } + } + + upd->offset = offset; + p++; + /* * Now, parse the filename component. Instead of looking for the * leftmost possible colon delimiter, we look for the rightmost one. @@ -176,7 +194,7 @@ UPDATE * dup_update(UPDATE * upd) return u; } -UPDATE * new_update(int op, char * memtype, int filefmt, char * filename) +UPDATE * new_update(int op, char * memtype, int filefmt, char * filename, size_t offset) { UPDATE * u; @@ -190,6 +208,7 @@ UPDATE * new_update(int op, char * memtype, int filefmt, char * filename) u->filename = strdup(filename); u->op = op; u->format = filefmt; + u->offset = offset; return u; } @@ -250,7 +269,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f progname, strcmp(upd->filename, "-")==0 ? "<stdout>" : upd->filename); } - rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size); + rc = fileio(FIO_WRITE, upd->filename, upd->format, p, upd->memtype, size, 0); if (rc < 0) { avrdude_message(MSG_INFO, "%s: write to file '%s' failed\n", progname, upd->filename); @@ -267,7 +286,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f progname, strcmp(upd->filename, "-")==0 ? "<stdin>" : upd->filename); } - rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1); + rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset); if (rc < 0) { avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", progname, upd->filename); @@ -296,11 +315,11 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f report_progress(1,1,NULL); } else { - /* - * test mode, don't actually write to the chip, output the buffer - * to stdout in intel hex instead - */ - rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size); + // /* + // * test mode, don't actually write to the chip, output the buffer + // * to stdout in intel hex instead + // */ + // rc = fileio(FIO_WRITE, "-", FMT_IHEX, p, upd->memtype, size, 0); } if (rc < 0) { @@ -332,7 +351,7 @@ int do_op(PROGRAMMER * pgm, struct avrpart * p, UPDATE * upd, enum updateflags f progname, mem->desc, upd->filename); } - rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1); + rc = fileio(FIO_READ, upd->filename, upd->format, p, upd->memtype, -1, upd->offset); if (rc < 0) { avrdude_message(MSG_INFO, "%s: read from file '%s' failed\n", progname, upd->filename); |