├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── examples ├── pinoccio.js └── uno.js ├── index.js ├── lib ├── README.md ├── constants-v2.js └── parser-v2.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | old 15 | npm-debug.log 16 | node_modules 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | old 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pinoccio 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | stk500-v2 2 | ========= 3 | 4 | [STK500](http://www.atmel.com/tools/stk500.aspx) javascript implementation for node and browserify 5 | 6 | Fully javascript stk500v2 programmer. Allows you to program Arduinos straight from node (or browser for that matter). No more avrdude system calls or using the arduino IDE. 7 | 8 | ###INSTALL 9 | ``` 10 | npm install stk500-v2 11 | ``` 12 | 13 | ####Program: 14 | 15 | * this may not be true. anymore update before 1.0.0 release * 16 | You need an *unconnected* instance of (my fork of) Chris Williams's Node Serial Port at the correct speed for your chip (commonly 115200) with a raw parser. 17 | 18 | ``` 19 | var serialPort = new SerialPort.SerialPort(port.comName, { 20 | baudrate: 115200, 21 | parser: SerialPort.parsers.raw 22 | }, false); 23 | 24 | ``` 25 | 26 | Then you can instantiate a programmer. 27 | 28 | ``` 29 | var stk500 = require('stk500-v2'); 30 | 31 | var programmerv2 = stk500(serialPort); 32 | 33 | ``` 34 | 35 | Beyond that you can send stk500 commands. For programming the process is a fairly strict series of async series including connect, reset, sync, setOptions (pagesize is the only necessary option), enterprogrammingmode, program, exitprogrammingmode, disconnect. See uno.js in examples. 36 | 37 | 38 | ###How to get a hex 39 | 40 | You can compile by hand yourself with avrdude if you know your stuff, or you can just steal one from Arduino. First make sure you have verbosity enabled in your Arduino preferences: Arduino Preferences -> check Show verbose output during Compilation. Now when you build you'll see a ton of lines on screen. The last couple lines have what you need: 41 | ``` 42 | /var/folders/zp/bpw8zd0141j5zf7l8m_qtt8w0000gp/T/build6252696906929781517.tmp/Blink.cpp.hex 43 | 44 | Sketch uses 896 bytes (2%) of program storage space. Maximum is 32,256 bytes. 45 | Global variables use 9 bytes (0%) of dynamic memory, leaving 2,039 bytes for local variables. Maximum is 2,048 bytes. 46 | ``` 47 | Grab that hex file and you're good to go. 48 | 49 | ###CHANGELOG 50 | 51 | 1.0.0 52 | removed support for stk500 v1 because that is now another project 53 | updated readme 54 | -------------------------------------------------------------------------------- /examples/pinoccio.js: -------------------------------------------------------------------------------- 1 | 2 | var stk500 = require('../'); 3 | var serialport = require('serialport'); 4 | var intel_hex = require('intel-hex'); 5 | var fs = require('fs'); 6 | 7 | var data = fs.readFileSync(__dirname+'/../../panda-attack/bootstrap.hex')+''; 8 | var hex = intel_hex.parse(data).data; 9 | 10 | 11 | var pageSize = 256; 12 | var baud = 115200; 13 | var delay1 = 10; 14 | var delay2 = 1; 15 | 16 | var signature = new Buffer([0x1e, 0xa8, 0x02]); 17 | 18 | var options = { 19 | timeout:0xc8, 20 | stabDelay:0x64, 21 | cmdexeDelay:0x19, 22 | synchLoops:0x20, 23 | byteDelay:0x00, 24 | pollValue:0x53, 25 | pollIndex:0x03 26 | }; 27 | 28 | 29 | var comName = '/dev/ttyACM0'; 30 | 31 | var serialPort = new serialport.SerialPort(comName, { 32 | baudrate: baud, 33 | parser: serialport.parsers.raw 34 | }, function(){ 35 | console.log('opened!',serialPort.opened); 36 | console.log(serialPort); 37 | serialPort.close(); 38 | }); 39 | 40 | 41 | var programmer = stk500(serialPort); 42 | 43 | // debug 44 | programmer.parser.on('rawinput',function(buf){ 45 | console.log("->",buf.toString('hex')); 46 | }) 47 | 48 | programmer.parser.on('raw',function(buf){ 49 | console.log("<-",buf.toString('hex')); 50 | }) 51 | 52 | // do it! 53 | programmer.sync(5,function(err,data){ 54 | console.log('callback sync',err," ",data) 55 | }); 56 | 57 | programmer.verifySignature(signature,function(err,data){ 58 | console.log('callback sig',err," ",data); 59 | }); 60 | 61 | 62 | programmer.enterProgrammingMode(options,function(err,data){ 63 | console.log('enter programming mode.',err,data); 64 | }); 65 | 66 | programmer.upload( hex, pageSize,function(err,data){ 67 | console.log('upload> ',err,data); 68 | 69 | programmer.exitProgrammingMode(function(err,data){ 70 | console.log('exitProgrammingMode> ',err,data) 71 | }) 72 | }); 73 | -------------------------------------------------------------------------------- /examples/uno.js: -------------------------------------------------------------------------------- 1 | var SerialPort = require("serialport"); 2 | var intel_hex = require('intel-hex'); 3 | 4 | // require version 1 of stk500 5 | var stk500 = require('../').v1; 6 | 7 | var async = require("async"); 8 | var fs = require('fs'); 9 | 10 | var usbttyRE = /(cu\.usb|ttyACM|COM\d+)/; 11 | 12 | var data = fs.readFileSync('arduino-1.0.6/uno/Blink.cpp.hex', { encoding: 'utf8' }); 13 | 14 | var hex = intel_hex.parse(data).data; 15 | 16 | //TODO standardize chip configs 17 | //uno 18 | var pageSize = 128; 19 | var baud = 115200; 20 | var delay1 = 1; //minimum is 2.5us, so anything over 1 fine? 21 | var delay2 = 1; 22 | var signature = new Buffer([0x1e, 0x95, 0x0f]); 23 | var options = { 24 | pagesizelow:pageSize 25 | }; 26 | 27 | SerialPort.list(function (err, ports) { 28 | ports.forEach(function(port) { 29 | 30 | console.log("found " + port.comName); 31 | 32 | if(usbttyRE.test(port.comName)) 33 | { 34 | 35 | console.log("trying" + port.comName); 36 | 37 | var serialPort = new SerialPort.SerialPort(port.comName, { 38 | baudrate: baud, 39 | parser: SerialPort.parsers.raw 40 | }, false); 41 | 42 | var programmer = new stk500(serialPort); 43 | 44 | async.series([ 45 | programmer.connect.bind(programmer), 46 | programmer.reset.bind(programmer,delay1, delay2), 47 | programmer.sync.bind(programmer, 3), 48 | programmer.verifySignature.bind(programmer, signature), 49 | programmer.setOptions.bind(programmer, options), 50 | programmer.enterProgrammingMode.bind(programmer), 51 | programmer.upload.bind(programmer, hex, pageSize), 52 | programmer.exitProgrammingMode.bind(programmer) 53 | 54 | ], function(error){ 55 | 56 | programmer.disconnect(); 57 | 58 | if(error){ 59 | console.log("programing FAILED: " + error); 60 | process.exit(1); 61 | }else{ 62 | console.log("programing SUCCESS!"); 63 | process.exit(0); 64 | } 65 | }); 66 | 67 | }else{ 68 | console.log("skipping " + port.comName); 69 | } 70 | 71 | }); 72 | }); 73 | 74 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | //use strict might have screwed up my this context, or might not have.. 2 | 3 | var async = require("async"); 4 | var parser = require('./lib/parser-v2.js'); 5 | var c = require('./lib/constants-v2.js'); 6 | 7 | var CMD_SIGN_ON = 0x01; 8 | var CMD_LOAD_ADDRESS = 0x06; 9 | var CMD_ENTER_PROGMODE_ISP = 0x10; 10 | var CMD_LEAVE_PROGMODE_ISP = 0x11; 11 | var CMD_PROGRAM_FLASH_ISP = 0x13; 12 | var CMD_SPI_MULTI = 0x1D; 13 | 14 | var _options = { 15 | timeout:0xc8, 16 | stabDelay:0x64, 17 | cmdexeDelay:0x19, 18 | synchLoops:0x20, 19 | byteDelay:0x00, 20 | pollValue:0x53, 21 | pollIndex:0x03 22 | }; 23 | 24 | function stk500(port) { 25 | if (!(this instanceof stk500)) 26 | return new stk500(port); 27 | 28 | var self = this; 29 | 30 | self.parser = parser(port); 31 | 32 | // use these constants. instead of requiring them above because that should be a different module. 33 | self.constants = self.parser.constants; 34 | self.serialPort = port; 35 | 36 | }; 37 | 38 | stk500.prototype.sync = function(attempts, done) { 39 | var self = this; 40 | var tries = 1; 41 | 42 | var cmd = Buffer.from([CMD_SIGN_ON]); 43 | 44 | attempt(); 45 | function attempt(){ 46 | tries=tries+1; 47 | 48 | self.parser.send(cmd, function(error, pkt){ 49 | 50 | 51 | var res; 52 | if(!error){ 53 | // message response format for CMD_SIGN_ON 54 | // 1 CMD_SIGN_ON 55 | // 1 STATUS_CMD_OK 56 | // 1 8 - length of sig string 57 | // 8 the signature string - "STK500_2" or "AVRISP_2" 58 | var response = pkt.message; 59 | 60 | if(response[0] !== c.CMD_SIGN_ON){ 61 | // something is wrong. look for error in constants. 62 | error = new Error('command response was not CMD_SIGN_ON. '+response[0]); 63 | error.code = "E_CMD_ERROR"; 64 | } else if(response[1] !== c.STATUS_CMD_OK){ 65 | // malformed. check command status constants and return error 66 | error = new Error('command status was not ok. '+response[1]); 67 | error.code = "E_CMD_STATUS"; 68 | } else { 69 | var len = response[2]; 70 | res = response.slice(3)+''; 71 | if(res.length != len) { 72 | // something is wrong but all signs point to right, 73 | } 74 | } 75 | } 76 | 77 | if(error && tries<=attempts){ 78 | //console.log("failed attempt again"); 79 | return attempt(); 80 | } 81 | 82 | done(error,res); 83 | }); 84 | } 85 | }; 86 | 87 | 88 | ////// BELOW HERE IS TODO i'm mid refactor. 89 | 90 | 91 | stk500.prototype.reset = function(delay1, delay2, done){ 92 | //console.log("reset"); 93 | 94 | var self = this; 95 | 96 | async.series([ 97 | function(cbdone) { 98 | //console.log("asserting"); 99 | self.serialPort.set({rts:true, dtr:true}, function(result){ 100 | //console.log("asserted"); 101 | if(result) cbdone(result); 102 | else cbdone(); 103 | }); 104 | }, 105 | function(cbdone) { 106 | //console.log("wait"); 107 | setTimeout(cbdone, delay1); 108 | }, 109 | function(cbdone) { 110 | //console.log("clearing"); 111 | self.serialPort.set({rts:false, dtr:false}, function(result){ 112 | //console.log("clear"); 113 | if(result) cbdone(result); 114 | else cbdone(); 115 | }); 116 | }, 117 | function(cbdone) { 118 | //console.log("wait"); 119 | setTimeout(cbdone, delay2); 120 | }], 121 | function(error) { 122 | done(error); 123 | } 124 | ); 125 | }; 126 | 127 | 128 | stk500.prototype.verifySignature = function(signature, done) { 129 | //console.log("verify signature"); 130 | 131 | this.getSignature(function(error, reportedSignature){ 132 | 133 | //console.log(reportedSignature); 134 | //console.log(signature); 135 | if(!signature.equals(reportedSignature)){ 136 | done(new Error("signature doesnt match. Found: " + reportedSignature.toString('hex'), error)); 137 | }else{ 138 | done(); 139 | } 140 | 141 | }); 142 | } 143 | 144 | stk500.prototype.getSignature = function(done) { 145 | var self = this; 146 | 147 | var reportedSignature = Buffer.alloc(3); 148 | 149 | async.series([ 150 | function(cbdone){ 151 | 152 | var numTx = 0x04; 153 | var numRx = 0x04; 154 | var rxStartAddr = 0x00; 155 | 156 | var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x00, 0x00]); 157 | 158 | self.parser.send(cmd, function(error, pkt) { 159 | 160 | if (pkt && pkt.message && pkt.message.length >= 6) 161 | { 162 | var sig = pkt.message[5]; 163 | reportedSignature.writeUInt8(sig, 0); 164 | } 165 | 166 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 167 | cbdone(error); 168 | // }); 169 | }); 170 | 171 | }, 172 | function(cbdone){ 173 | 174 | var numTx = 0x04; 175 | var numRx = 0x04; 176 | var rxStartAddr = 0x00; 177 | 178 | var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x01, 0x00]); 179 | 180 | self.parser.send(cmd, function(error, pkt) { 181 | //console.log("sent sig2"); 182 | 183 | if (pkt && pkt.message && pkt.message.length >= 6) 184 | { 185 | var sig = pkt.message[5]; 186 | reportedSignature.writeUInt8(sig, 1); 187 | } 188 | 189 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 190 | cbdone(error); 191 | // }); 192 | }); 193 | 194 | }, 195 | function(cbdone){ 196 | 197 | var numTx = 0x04; 198 | var numRx = 0x04; 199 | var rxStartAddr = 0x00; 200 | 201 | var cmd = Buffer.from([CMD_SPI_MULTI, numTx, numRx, rxStartAddr, 0x30, 0x00, 0x02, 0x00]); 202 | 203 | self.parser.send(cmd, function(error, pkt) { 204 | //console.log("sent sig3"); 205 | 206 | if (pkt && pkt.message && pkt.message.length >= 6) 207 | { 208 | var sig = pkt.message[5]; 209 | reportedSignature.writeUInt8(sig, 2); 210 | } 211 | 212 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 213 | cbdone(error); 214 | // }); 215 | }); 216 | 217 | } 218 | ], 219 | function(error) { 220 | //console.log("read signature done"); 221 | done(error, reportedSignature); 222 | }); 223 | 224 | } 225 | 226 | 227 | stk500.prototype.enterProgrammingMode = function(options, done) { 228 | //console.log("send enter programming mode"); 229 | 230 | var self = this; 231 | 232 | var args = Array.prototype.slice.call(arguments); 233 | done = args.pop(); 234 | if (typeof(done) !== 'function') { 235 | done = null; 236 | } 237 | 238 | options = (typeof options !== 'function') && options || {}; 239 | 240 | options.timeout = options.timeout || _options.timeout; 241 | options.stabDelay = options.stabDelay || _options.stabDelay; 242 | options.cmdexeDelay = options.cmdexeDelay || _options.cmdexeDelay; 243 | options.synchLoops = options.synchLoops || _options.synchLoops; 244 | options.byteDelay = options.byteDelay || _options.byteDelay; 245 | options.pollValue = options.pollValue || _options.pollValue; 246 | options.pollIndex = options.pollIndex || _options.pollIndex; 247 | 248 | var cmd1 = 0xac; 249 | var cmd2 = 0x53; 250 | var cmd3 = 0x00; 251 | var cmd4 = 0x00; 252 | 253 | 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]); 254 | 255 | self.parser.send(cmd, function(error, results) { 256 | //console.log("sent enter programming mode"); 257 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 258 | done(error); 259 | // }); 260 | }); 261 | }; 262 | 263 | 264 | stk500.prototype.loadAddress = function(useaddr, done) { 265 | //console.log("load address"); 266 | var self = this; 267 | 268 | msb = (useaddr >> 24) & 0xff | 0x80; 269 | xsb = (useaddr >> 16) & 0xff; 270 | ysb = (useaddr >> 8) & 0xff; 271 | lsb = useaddr & 0xff; 272 | 273 | var cmdBuf = Buffer.from([CMD_LOAD_ADDRESS, msb, xsb, ysb, lsb]); 274 | 275 | self.parser.send(cmdBuf, function(error, results) { 276 | //console.log("confirm load address"); 277 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 278 | done(error); 279 | // }); 280 | 281 | }); 282 | 283 | }; 284 | 285 | 286 | stk500.prototype.loadPage = function(writeBytes, done) { 287 | //console.log("load page"); 288 | var self = this; 289 | 290 | var bytesMsb = writeBytes.length >> 8; //Total number of bytes to program, MSB first 291 | var bytesLsb = writeBytes.length & 0xff; //Total number of bytes to program, MSB first 292 | var mode = 0xc1; //paged, rdy/bsy polling, write page 293 | var delay = 0x0a; //Delay, used for different types of programming termination, according to mode byte 294 | var cmd1 = 0x40; // Load Page, Write Program Memory 295 | var cmd2 = 0x4c; // Write Program Memory Page 296 | var cmd3 = 0x20; //Read Program Memory 297 | var poll1 = 0x00; //Poll Value #1 298 | var poll2 = 0x00; //Poll Value #2 (not used for flash programming) 299 | 300 | 301 | var cmdBuf = Buffer.from([CMD_PROGRAM_FLASH_ISP, bytesMsb, bytesLsb, mode, delay, cmd1, cmd2, cmd3, poll1, poll2]); 302 | 303 | cmdBuf = Buffer.concat([cmdBuf,writeBytes]); 304 | 305 | self.parser.send(cmdBuf, function(error, results) { 306 | //console.log("loaded page"); 307 | 308 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 309 | done(error); 310 | // }); 311 | 312 | }); 313 | }; 314 | 315 | stk500.prototype.upload = function(hex, pageSize, done) { 316 | //console.log("program"); 317 | 318 | var pageaddr = 0; 319 | var writeBytes; 320 | var useaddr; 321 | 322 | var self = this; 323 | 324 | // program individual pages 325 | async.whilst( 326 | function() { return pageaddr < hex.length; }, 327 | function(pagedone) { 328 | //console.log("program page"); 329 | async.series([ 330 | function(cbdone){ 331 | useaddr = pageaddr >> 1; 332 | cbdone(); 333 | }, 334 | function(cbdone){ 335 | self.loadAddress(useaddr, cbdone); 336 | }, 337 | function(cbdone){ 338 | 339 | writeBytes = hex.slice(pageaddr, (hex.length > pageSize ? (pageaddr + pageSize) : hex.length - 1)) 340 | cbdone(); 341 | }, 342 | function(cbdone){ 343 | self.loadPage(writeBytes, cbdone); 344 | }, 345 | function(cbdone){ 346 | //console.log("programmed page"); 347 | pageaddr = pageaddr + writeBytes.length; 348 | setTimeout(cbdone, 4); 349 | } 350 | ], 351 | function(error) { 352 | //console.log("page done"); 353 | pagedone(error); 354 | }); 355 | }, 356 | function(error) { 357 | //console.log("upload done"); 358 | done(error); 359 | } 360 | ); 361 | }; 362 | 363 | stk500.prototype.exitProgrammingMode = function(done) { 364 | //console.log("send leave programming mode"); 365 | var self = this; 366 | 367 | var preDelay = 0x01; 368 | var postDelay = 0x01; 369 | 370 | var cmd = Buffer.from([CMD_LEAVE_PROGMODE_ISP, preDelay, postDelay]); 371 | 372 | self.parser.send(cmd, function(error, results) { 373 | //console.log("sent leave programming mode"); 374 | // self.matchReceive(Buffer.from([Resp_STK_INSYNC, Resp_STK_OK]), timeout, function(error){ 375 | done(error); 376 | // }); 377 | }); 378 | }; 379 | 380 | stk500.prototype.verify = function(hex, done) { 381 | // console.log("verify"); 382 | // var self = this; 383 | 384 | // serial.parser.send([Cmnd_STK_LOAD_ADDRESS, addr_low, addr_high, Sync_CRC_EOP]) n times 385 | // self.matchReceive([Resp_STK_INSYNC, Resp_STK_OK]); 386 | // serial.send ([Cmnd_STK_READ_PAGE, bytes_high, bytes_low, memtype, Sync_CRC_EOP]) n times 387 | // self.matchReceive([Resp_STK_INSYNC].concat(writeBytes)); 388 | done(); 389 | }; 390 | 391 | //todo convenience function 392 | stk500.prototype.bootload = function (chip, hex, done){ 393 | done(); 394 | }; 395 | 396 | 397 | // export the class 398 | module.exports = stk500; 399 | -------------------------------------------------------------------------------- /lib/README.md: -------------------------------------------------------------------------------- 1 | parsers export should be a function that accepts an open serialport as the first argument. and option options as the second. 2 | 3 | the parser object should be an event emitter 4 | 5 | if should expose a public send method that takes data,and callback arguments. 6 | an optional middle options arguments may be necessary 7 | 8 | all other protocol command implementation should be done in another file. 9 | 10 | -------------------------------------------------------------------------------- /lib/constants-v2.js: -------------------------------------------------------------------------------- 1 | 2 | // STK message constants 3 | module.exports.MESSAGE_START = 0x1B 4 | module.exports.TOKEN = 0x0E 5 | 6 | // STK general command constants 7 | module.exports.CMD_SIGN_ON = 0x01 8 | module.exports.CMD_SET_PARAMETER = 0x02 9 | module.exports.CMD_GET_PARAMETER = 0x03 10 | module.exports.CMD_SET_DEVICE_PARAMETERS = 0x04 11 | module.exports.CMD_OSCCAL = 0x05 12 | module.exports.CMD_LOAD_ADDRESS = 0x06 13 | module.exports.CMD_FIRMWARE_UPGRADE = 0x07 14 | 15 | // STK ISP command constants 16 | module.exports.CMD_ENTER_PROGMODE_ISP = 0x10 17 | module.exports.CMD_LEAVE_PROGMODE_ISP = 0x11 18 | module.exports.CMD_CHIP_ERASE_ISP = 0x12 19 | module.exports.CMD_PROGRAM_FLASH_ISP = 0x13 20 | module.exports.CMD_READ_FLASH_ISP = 0x14 21 | module.exports.CMD_PROGRAM_EEPROM_ISP = 0x15 22 | module.exports.CMD_READ_EEPROM_ISP = 0x16 23 | module.exports.CMD_PROGRAM_FUSE_ISP = 0x17 24 | module.exports.CMD_READ_FUSE_ISP = 0x18 25 | module.exports.CMD_PROGRAM_LOCK_ISP = 0x19 26 | module.exports.CMD_READ_LOCK_ISP = 0x1A 27 | module.exports.CMD_READ_SIGNATURE_ISP = 0x1B 28 | module.exports.CMD_READ_OSCCAL_ISP = 0x1C 29 | module.exports.CMD_SPI_MULTI = 0x1D 30 | 31 | // STK PP command constants 32 | module.exports.CMD_ENTER_PROGMODE_PP = 0x20 33 | module.exports.CMD_LEAVE_PROGMODE_PP = 0x21 34 | module.exports.CMD_CHIP_ERASE_PP = 0x22 35 | module.exports.CMD_PROGRAM_FLASH_PP = 0x23 36 | module.exports.CMD_READ_FLASH_PP = 0x24 37 | module.exports.CMD_PROGRAM_EEPROM_PP = 0x25 38 | module.exports.CMD_READ_EEPROM_PP = 0x26 39 | module.exports.CMD_PROGRAM_FUSE_PP = 0x27 40 | module.exports.CMD_READ_FUSE_PP = 0x28 41 | module.exports.CMD_PROGRAM_LOCK_PP = 0x29 42 | module.exports.CMD_READ_LOCK_PP = 0x2A 43 | module.exports.CMD_READ_SIGNATURE_PP = 0x2B 44 | module.exports.CMD_READ_OSCCAL_PP = 0x2C 45 | module.exports.CMD_SET_CONTROL_STACK = 0x2D 46 | 47 | // STK HVSP command constants 48 | module.exports.CMD_ENTER_PROGMODE_HVSP = 0x30 49 | module.exports.CMD_LEAVE_PROGMODE_HVSP = 0x31 50 | module.exports.CMD_CHIP_ERASE_HVSP = 0x32 51 | module.exports.CMD_PROGRAM_FLASH_HVSP = 0x33 52 | module.exports.CMD_READ_FLASH_HVSP = 0x34 53 | module.exports.CMD_PROGRAM_EEPROM_HVSP = 0x35 54 | module.exports.CMD_READ_EEPROM_HVSP = 0x36 55 | module.exports.CMD_PROGRAM_FUSE_HVSP = 0x37 56 | module.exports.CMD_READ_FUSE_HVSP = 0x38 57 | module.exports.CMD_PROGRAM_LOCK_HVSP = 0x39 58 | module.exports.CMD_READ_LOCK_HVSP = 0x3A 59 | module.exports.CMD_READ_SIGNATURE_HVSP = 0x3B 60 | module.exports.CMD_READ_OSCCAL_HVSP = 0x3C 61 | 62 | // STK status constants 63 | // Success 64 | module.exports.STATUS_CMD_OK = 0x00 65 | // Warnings 66 | module.exports.STATUS_CMD_TOUT = 0x80 67 | module.exports.STATUS_RDY_BSY_TOUT = 0x81 68 | module.exports.STATUS_SET_PARAM_MISSING = 0x82 69 | // Errors 70 | module.exports.STATUS_CMD_FAILED = 0xC0 71 | module.exports.STATUS_CKSUM_ERROR = 0xC1 72 | module.exports.STATUS_CMD_UNKNOWN = 0xC9 73 | 74 | // STK parameter constants 75 | module.exports.STATUS_BUILD_NUMBER_LOW = 0x80 76 | module.exports.STATUS_BUILD_NUMBER_HIGH = 0x81 77 | module.exports.STATUS_HW_VER = 0x90 78 | module.exports.STATUS_SW_MAJOR = 0x91 79 | module.exports.STATUS_SW_MINOR = 0x92 80 | module.exports.STATUS_VTARGET = 0x94 81 | module.exports.STATUS_VADJUST = 0x95 82 | module.exports.STATUS_OSC_PSCALE = 0x96 83 | module.exports.STATUS_OSC_CMATCH = 0x97 84 | module.exports.STATUS_SCK_DURATION = 0x98 85 | module.exports.STATUS_TOPCARD_DETECT = 0x9A 86 | module.exports.STATUS_STATUS = 0x9C 87 | module.exports.STATUS_DATA = 0x9D 88 | module.exports.STATUS_RESET_POLARITY = 0x9E 89 | module.exports.STATUS_CONTROLLER_INIT = 0x9F 90 | 91 | // STK answer constants 92 | module.exports.ANSWER_CKSUM_ERROR = 0xB0 93 | -------------------------------------------------------------------------------- /lib/parser-v2.js: -------------------------------------------------------------------------------- 1 | var c = require('./constants-v2'); 2 | var EventEmitter = require("events").EventEmitter; 3 | 4 | module.exports = function(serialPort){ 5 | 6 | var o = ext( 7 | new EventEmitter, 8 | { 9 | constants:c, 10 | port:serialPort, 11 | boundOpen:false, 12 | closed:false, 13 | // write 14 | _inc:-1, 15 | _queue:[], 16 | _current:false, 17 | // parser. 18 | states:["Start", "GetSequenceNumber", "GetMessageSize1", "GetMessageSize2", "GetToken", "GetData", "GetChecksum", "Done"], 19 | state:0, 20 | pkt:false, 21 | // public interface, 22 | send:function(body,cb){ 23 | if(this.closed) return setImmediate(function(){ 24 | var e = new Error('this parser is closed.'); 25 | e.code = "E_CLOSED"; 26 | cb(e); 27 | }); 28 | 29 | if(!Buffer.isBuffer(body)) body = Buffer.from(body); 30 | 31 | var timeout = this._commandTimeout(body[0]); 32 | 33 | var messageLen = Buffer.from([0,0]); 34 | messageLen.writeUInt16BE(body.length,0); 35 | 36 | //MESSAGE_START,SEQUENCE_NUMBER,MESSAGE_SIZE,TOKEN,MESSAGE_BODY,CMD_READ/PROGRAM_FLASH/EEPROM,CHECKSUM 37 | var out = Buffer.concat([Buffer.from([c.MESSAGE_START,this._seq(),messageLen[0],messageLen[1],c.TOKEN]),body]); 38 | 39 | 40 | var checksum = this.checksum(out); 41 | 42 | 43 | this._queue.push({buf:Buffer.concat([out,Buffer.from([checksum])]),seq:this._inc,cb:cb,timeout:timeout}); 44 | 45 | // if not waiting for another command to return. send this command 46 | this._send(); 47 | }, 48 | checksum:function(buf){ 49 | 50 | var checksum = 0; 51 | for(var i=0;i 0xff) this._inc = 0; 60 | return this._inc; 61 | }, 62 | _commandTimeout:function(typeByte){ 63 | //The total timeout period is from a command is sent to the answer must be completely 64 | //received. The total timeout period is 200 ms for the CMD_SIGN_ON command, 5 65 | //seconds for the CMD_READ/PROGRAM_FLASH/EEPROM commands, and 1 66 | //second for all other commands. 67 | timeout = 1000; 68 | if(typeByte === c.CMD_SIGN_ON) timeout = 200; 69 | else { 70 | // grab the constant names. 71 | var keys = Object.keys(c); 72 | for(var i=0;i -1 || keys[i].indexOf('PROGRAM_FLASH') > -1 || keys[i].indexOf('EEPROM') > -1) { 75 | timeout = 5000; 76 | } 77 | break; 78 | } 79 | } 80 | } 81 | return timeout; 82 | }, 83 | _send:function(){ 84 | if(this.closed) return false; 85 | if(this._current) return; 86 | if(!this._queue.length) return; 87 | 88 | var portIsOpen = typeof serialPort.isOpen === 'function' ? serialPort.isOpen() : serialPort.isOpen; 89 | 90 | // if the serialport is not open yet. Check on node && chrome. 91 | if(!portIsOpen){ 92 | var z = this; 93 | if(!this.boundOpen) serialPort.once('open',function(){ 94 | z._send(); 95 | }); 96 | return; 97 | } 98 | 99 | var message = this._queue.shift(); 100 | var current = this._current = { 101 | timeout:false, 102 | seq:message.seq, 103 | cb:message.cb 104 | }; 105 | 106 | this._current 107 | this.state = 0; 108 | var z = this; 109 | 110 | this.port.write(message.buf); 111 | this.port.drain(function(){ 112 | if(current !== z._current) return z.emit('log',"current was no longer the current message after drain callback"); 113 | current.timeout = setTimeout(function(){ 114 | var err = new Error("stk500 timeout. "+message.timeout+"ms") 115 | err.code = "E_TIMEOUT"; 116 | z._resolveCurrent(err); 117 | },message.timeout); 118 | }); 119 | this.emit('rawinput',message.buf); 120 | }, 121 | _handle:function(data){ 122 | var current = this._current; 123 | this.emit('raw',data); 124 | if(!current) return this.emit('log','notice',"dropping data",'data'); 125 | // put state machine here. proove this works foolio. 126 | 127 | for(var i=0;i (https://github.com/soldair/)", 25 | "Jeremie Miller (http://jeremie.com/)", 26 | "Jacob Rosenthal (https://github.com/jacobrosenthal/)" 27 | ], 28 | "license": "MIT", 29 | "bugs": { 30 | "url": "https://github.com/Pinoccio/js-stk500/issues" 31 | }, 32 | "homepage": "https://github.com/Pinoccio/js-stk500", 33 | "dependencies": { 34 | "async": "^0.9.0" 35 | }, 36 | "devDependencies": { 37 | "intel-hex": "~0.1.1", 38 | "serialport": "^6.2.0", 39 | "tape": "~2.12.2" 40 | } 41 | } 42 | --------------------------------------------------------------------------------