UNPKG

stk500-v2

Version:

STK500 v2 programmer in javascript

399 lines (309 loc) 10.5 kB
//use strict might have screwed up my this context, or might not have.. var async = require("async"); var parser = require('./lib/parser-v2.js'); var c = require('./lib/constants-v2.js'); var CMD_SIGN_ON = 0x01; var CMD_LOAD_ADDRESS = 0x06; var CMD_ENTER_PROGMODE_ISP = 0x10; var CMD_LEAVE_PROGMODE_ISP = 0x11; var CMD_PROGRAM_FLASH_ISP = 0x13; var CMD_SPI_MULTI = 0x1D; var _options = { timeout:0xc8, stabDelay:0x64, cmdexeDelay:0x19, synchLoops:0x20, byteDelay:0x00, pollValue:0x53, pollIndex:0x03 }; function stk500(port) { if (!(this instanceof stk500)) return new stk500(port); var self = this; self.parser = parser(port); // use these constants. instead of requiring them above because that should be a different module. self.constants = self.parser.constants; self.serialPort = port; }; stk500.prototype.sync = function(attempts, done) { var self = this; var tries = 1; var cmd = Buffer.from([CMD_SIGN_ON]); attempt(); function attempt(){ tries=tries+1; self.parser.send(cmd, function(error, pkt){ var res; if(!error){ // message response format for CMD_SIGN_ON // 1 CMD_SIGN_ON // 1 STATUS_CMD_OK // 1 8 - length of sig string // 8 the signature string - "STK500_2" or "AVRISP_2" var response = pkt.message; if(response[0] !== c.CMD_SIGN_ON){ // something is wrong. look for error in constants. error = new Error('command response was not CMD_SIGN_ON. '+response[0]); error.code = "E_CMD_ERROR"; } else if(response[1] !== c.STATUS_CMD_OK){ // malformed. check command status constants and return error error = new Error('command status was not ok. '+response[1]); error.code = "E_CMD_STATUS"; } else { var len = response[2]; res = response.slice(3)+''; if(res.length != len) { // something is wrong but all signs point to right, } } } if(error && tries<=attempts){ //console.log("failed attempt again"); return attempt(); } done(error,res); }); } }; ////// BELOW HERE IS TODO i'm mid refactor. stk500.prototype.reset = function(delay1, delay2, done){ //console.log("reset"); var self = this; async.series([ function(cbdone) { //console.log("asserting"); self.serialPort.set({rts:true, dtr:true}, function(result){ //console.log("asserted"); if(result) cbdone(result); else cbdone(); }); }, function(cbdone) { //console.log("wait"); setTimeout(cbdone, delay1); }, function(cbdone) { //console.log("clearing"); self.serialPort.set({rts:false, dtr:false}, function(result){ //console.log("clear"); if(result) cbdone(result); else cbdone(); }); }, function(cbdone) { //console.log("wait"); setTimeout(cbdone, delay2); }], function(error) { done(error); } ); }; stk500.prototype.verifySignature = function(signature, done) { //console.log("verify signature"); this.getSignature(function(error, reportedSignature){ //console.log(reportedSignature); //console.log(signature); if(!signature.equals(reportedSignature)){ done(new Error("signature doesnt match. Found: " + reportedSignature.toString('hex'), error)); }else{ done(); } }); } stk500.prototype.getSignature = function(done) { var self = this; var reportedSignature = Buffer.alloc(3); async.series([ function(cbdone){ var numTx = 0x04; var numRx = 0x04; var rxStartAddr = 0x00; var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x00, 0x00]); self.parser.send(cmd, function(error, pkt) { if (pkt && pkt.message && pkt.message.length >= 6) { var sig = pkt.message[5]; reportedSignature.writeUInt8(sig, 0); } // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ cbdone(error); // }); }); }, function(cbdone){ var numTx = 0x04; var numRx = 0x04; var rxStartAddr = 0x00; var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x01, 0x00]); self.parser.send(cmd, function(error, pkt) { //console.log("sent sig2"); if (pkt && pkt.message && pkt.message.length >= 6) { var sig = pkt.message[5]; reportedSignature.writeUInt8(sig, 1); } // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ cbdone(error); // }); }); }, function(cbdone){ var numTx = 0x04; var numRx = 0x04; var rxStartAddr = 0x00; var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x02, 0x00]); self.parser.send(cmd, function(error, pkt) { //console.log("sent sig3"); if (pkt && pkt.message && pkt.message.length >= 6) { var sig = pkt.message[5]; reportedSignature.writeUInt8(sig, 2); } // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ cbdone(error); // }); }); } ], function(error) { //console.log("read signature done"); done(error, reportedSignature); }); } stk500.prototype.enterProgrammingMode = function(options, done) { //console.log("send enter programming mode"); var self = this; var args = Array.prototype.slice.call(arguments); done = args.pop(); if (typeof(done) !== 'function') { done = null; } options = (typeof options !== 'function') && options || {}; options.timeout = options.timeout || _options.timeout; options.stabDelay = options.stabDelay || _options.stabDelay; options.cmdexeDelay = options.cmdexeDelay || _options.cmdexeDelay; options.synchLoops = options.synchLoops || _options.synchLoops; options.byteDelay = options.byteDelay || _options.byteDelay; options.pollValue = options.pollValue || _options.pollValue; options.pollIndex = options.pollIndex || _options.pollIndex; var cmd1 = 0xac; var cmd2 = 0x53; var cmd3 = 0x00; var cmd4 = 0x00; var cmd = Buffer.from([CMD_ENTER_PROGMODE_ISP, options.timeout, options.stabDelay, options.cmdexeDelay, options.synchLoops, options.byteDelay, options.pollValue, options.pollIndex, cmd1, cmd2, cmd3, cmd4]); self.parser.send(cmd, function(error, results) { //console.log("sent enter programming mode"); // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ done(error); // }); }); }; stk500.prototype.loadAddress = function(useaddr, done) { //console.log("load address"); var self = this; msb = (useaddr >> 24) & 0xff | 0x80; xsb = (useaddr >> 16) & 0xff; ysb = (useaddr >> 8) & 0xff; lsb = useaddr & 0xff; var cmdBuf = Buffer.from([CMD_LOAD_ADDRESS, msb, xsb, ysb, lsb]); self.parser.send(cmdBuf, function(error, results) { //console.log("confirm load address"); // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ done(error); // }); }); }; stk500.prototype.loadPage = function(writeBytes, done) { //console.log("load page"); var self = this; var bytesMsb = writeBytes.length >> 8; //Total number of bytes to program, MSB first var bytesLsb = writeBytes.length & 0xff; //Total number of bytes to program, MSB first var mode = 0xc1; //paged, rdy/bsy polling, write page var delay = 0x0a; //Delay, used for different types of programming termination, according to mode byte var cmd1 = 0x40; // Load Page, Write Program Memory var cmd2 = 0x4c; // Write Program Memory Page var cmd3 = 0x20; //Read Program Memory var poll1 = 0x00; //Poll Value #1 var poll2 = 0x00; //Poll Value #2 (not used for flash programming) var cmdBuf = Buffer.from([CMD_PROGRAM_FLASH_ISP, bytesMsb, bytesLsb, mode, delay, cmd1, cmd2, cmd3, poll1, poll2]); cmdBuf = Buffer.concat([cmdBuf,writeBytes]); self.parser.send(cmdBuf, function(error, results) { //console.log("loaded page"); // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ done(error); // }); }); }; stk500.prototype.upload = function(hex, pageSize, done) { //console.log("program"); var pageaddr = 0; var writeBytes; var useaddr; var self = this; // program individual pages async.whilst( function() { return pageaddr < hex.length; }, function(pagedone) { //console.log("program page"); async.series([ function(cbdone){ useaddr = pageaddr >> 1; cbdone(); }, function(cbdone){ self.loadAddress(useaddr, cbdone); }, function(cbdone){ writeBytes = hex.slice(pageaddr, (hex.length > pageSize ? (pageaddr + pageSize) : hex.length - 1)) cbdone(); }, function(cbdone){ self.loadPage(writeBytes, cbdone); }, function(cbdone){ //console.log("programmed page"); pageaddr = pageaddr + writeBytes.length; setTimeout(cbdone, 4); } ], function(error) { //console.log("page done"); pagedone(error); }); }, function(error) { //console.log("upload done"); done(error); } ); }; stk500.prototype.exitProgrammingMode = function(done) { //console.log("send leave programming mode"); var self = this; var preDelay = 0x01; var postDelay = 0x01; var cmd = Buffer.from([CMD_LEAVE_PROGMODE_ISP, preDelay, postDelay]); self.parser.send(cmd, function(error, results) { //console.log("sent leave programming mode"); // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ done(error); // }); }); }; stk500.prototype.verify = function(hex, done) { // console.log("verify"); // var self = this; // serial.parser.send([Cmnd_STK_LOAD_ADDRESS, addr_low, addr_high, Sync_CRC_EOP]) n times // self.matchReceive([Resp_STK_INSYNC, Resp_STK_OK]); // serial.send ([Cmnd_STK_READ_PAGE, bytes_high, bytes_low, memtype, Sync_CRC_EOP]) n times // self.matchReceive([Resp_STK_INSYNC].concat(writeBytes)); done(); }; //todo convenience function stk500.prototype.bootload = function (chip, hex, done){ done(); }; // export the class module.exports = stk500;