Here’s a fun project – rewriting avrdude in CoffeesCript, as I did a while back with Tcl:
{SerialPort} = require 'serialport'
pageBytes = 128
avrUploader = (bytes, tty, cb) ->
serial = new SerialPort tty, baudrate: 115200
done = (err) ->
serial.close ->
cb err
timer = null
state = offset = 0
reply = ''
states = [ # Finite State Machine, one function per state
->
['0 ']
->
buf = new Buffer(20)
buf.fill 0
buf.writeInt16BE pageBytes, 12
['B', buf, ' ']
->
['P ']
->
state += 1 if offset >= bytes.length
buf = new Buffer(2)
buf.writeInt16LE offset >> 1, 0
['U', buf, ' ']
->
state -= 2
count = Math.min bytes.length - offset, pageBytes
buf = new Buffer(2)
buf.writeInt16BE count, 0
pos = offset
offset += count
['d', buf, 'F', bytes.slice(pos, offset), ' ']
->
['Q ']
]
next = ->
if state < states.length
serial.write x for x in states[state++]()
serial.flush()
reply = ''
timer = setTimeout (-> done state), 300
else
done()
serial.on 'open', next
serial.on 'error', done
serial.on 'data', (data) ->
reply += data
if reply.slice(-2) is '\x14\x10'
clearTimeout timer
next()
And here’s a little test which uploads the RF12demo sketch into a JeeNode over serial:
fs = require 'fs'
hex = fs.readFileSync '/Users/jcw/Desktop/RF12demo.cpp.hex', 'ascii'
hexToBin = (code) ->
data = ''
for line in code.split '\n'
count = parseInt line.slice(1, 3), 16
if count and line.slice(7, 9) is '00'
data += line.slice 9, 9 + 2 * count
new Buffer(data, 'hex')
avrUploader hexToBin(hex), '/dev/tty.usbserial-AH01A0GD', (err) ->
console.error 'err', err if err
console.log hexToBin(hex).length
Just copy it all into a file upload.coffee and run it as: coffee upload.coffee
It’s fairly dense code, but as you can see, the stk500v1 protocol requires very little logic!
JavaScript continues to amaze me with its power. The fact that I haven’t paid closer attention to how it was beiog used and what my browser was allowing it to do leaves me unsettled. Javascript books are now on my must read list.
Why are there no commas in the states array?