Implement Burn Bootloader

This commit is contained in:
Matthias Neeracher 2015-01-07 10:30:28 +01:00 committed by Matthias Neeracher
parent 533471fba8
commit e13c7f5757
5 changed files with 95 additions and 37 deletions

View File

@ -57,25 +57,19 @@ class ASBuilder {
let libPath = (ASLibraries.instance().directories as NSArray).componentsJoinedByString(":")
var args = [NSString]()
let boardProp = ASHardware.instance().boards[board]!
var corePath = ""
let library = boardProp["library"]!
var corePath = library+"/cores/"+boardProp["build.core"]!
var variantPath : NSString?
for hw in ASHardware.instance().directories {
corePath = hw+"/cores/"+boardProp["build.core"]!
if fileManager.fileExistsAtPath(corePath) {
if let variantName = boardProp["build.variant"] {
variantPath = hw+"/variants/"+variantName
variantPath = library+"/variants/"+variantName
if fileManager.fileExistsAtPath(variantPath!) {
args.append("variant="+variantName)
} else {
variantPath = nil
}
}
break
} else {
corePath = ""
}
}
if corePath == "" {
NSLog("Unable to find core %s\n", boardProp["build.core"]!)
return
}
@ -99,7 +93,15 @@ class ASBuilder {
task!.launch()
}
func uploadProject(board: String, programmer: String, port: String, terminal: Bool = false) {
enum Mode {
case Upload
case BurnBootloader
case Interactive
}
func uploadProject(board: String, programmer: String, port: String, mode: Mode = .Upload) {
let useProgrammer = mode != .Upload
let interactive = mode == .Interactive
let portPath = ASSerial.fileNameForPort(port)
let toolChain = (NSApplication.sharedApplication().delegate as ASApplication).preferences.toolchainPath
task = NSTask()
@ -108,7 +110,7 @@ class ASBuilder {
let fileManager = NSFileManager.defaultManager()
var logOut : NSFileHandle
if terminal {
if interactive {
let inputPipe = NSPipe()
let outputPipe = NSPipe()
logOut = outputPipe.fileHandleForWriting
@ -116,6 +118,7 @@ class ASBuilder {
task!.standardOutput = outputPipe
task!.standardError = outputPipe
} else {
ASSerialWin.portNeededForUpload(port)
let logURL = dir.URLByAppendingPathComponent("build/upload.log")
fileManager.createFileAtPath(logURL.path!, contents: NSData(), attributes: nil)
logOut = NSFileHandle(forWritingAtPath: logURL.path!)!
@ -126,7 +129,7 @@ class ASBuilder {
let libPath = (ASLibraries.instance().directories as NSArray).componentsJoinedByString(":")
let boardProp = ASHardware.instance().boards[board]!
let progProp = ASHardware.instance().programmers[programmer]
let hasBootloader = boardProp["upload.protocol"] != nil
let hasBootloader = !useProgrammer && boardProp["upload.protocol"] != nil
let leonardish = hasBootloader && (boardProp["bootloader.path"] ?? "").hasPrefix("caterina")
let proto = hasBootloader ? boardProp["upload.protocol"] : progProp?["protocol"]
let speed = hasBootloader ? boardProp["upload.speed"] : progProp?["speed"]
@ -135,10 +138,59 @@ class ASBuilder {
args += [
"-C", toolChain+"/etc/avrdude.conf",
"-p", boardProp["build.mcu"]!, "-c", proto!, "-P", portPath]
if terminal {
args += ["-t"]
} else {
switch mode {
case .Upload:
if hasBootloader {
args += ["-D"]
}
args += ["-U", "flash:w:build/"+board+"/"+dir.lastPathComponent+".hex:i"]
continuation = {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2*NSEC_PER_SEC)), dispatch_get_main_queue(), {
ASSerialWin.portAvailableAfterUpload(port)
})
}
case .BurnBootloader:
var loaderArgs = args
args += ["-e"]
if let unlock = boardProp["bootloader.unlock_bits"] {
args += ["-Ulock:w:"+unlock+":m"]
}
if let efuse = boardProp["bootloader.extended_fuses"] {
args += ["-Uefuse:w:"+efuse+":m"]
}
let hfuse = boardProp["bootloader.high_fuses"]!
let lfuse = boardProp["bootloader.low_fuses"]!
args += ["-Uhfuse:w:"+hfuse+":m", "-Ulfuse:w:"+lfuse+":m"]
var needPhase2 = false
if let loaderPath = boardProp["bootloader.path"] {
let loader = boardProp["library"]!+"/bootloaders/"+loaderPath+"/"+boardProp["bootloader.file"]!
loaderArgs += ["-Uflash:w:"+loader+":i"]
needPhase2 = true
}
if let lock = boardProp["bootloader.lock_bits"] {
loaderArgs += ["-Ulock:w:"+lock+":m"]
needPhase2 = true
}
if needPhase2 {
let task2 = NSTask()
task2.currentDirectoryPath = dir.path!
task2.launchPath = toolChain+"/bin/avrdude"
task2.arguments = loaderArgs
task2.standardOutput = logOut
task2.standardError = logOut
continuation = {
let cmdLine = task2.launchPath+" "+(loaderArgs as NSArray).componentsJoinedByString(" ")+"\n"
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task2.launch()
self.continuation = {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2*NSEC_PER_SEC)), dispatch_get_main_queue(), {
ASSerialWin.portAvailableAfterUpload(port)
})
}
}
}
case .Interactive:
args += ["-t"]
}
if speed != nil {
args.append("-b")
@ -171,7 +223,7 @@ class ASBuilder {
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task!.arguments = args;
task!.launch()
if terminal {
if interactive {
let intSpeed = speed?.toInt() ?? 19200
ASSerialWin.showWindowWithPort(port, task:task!, speed:intSpeed)
task = nil

View File

@ -72,6 +72,7 @@ class ASHardware {
if seen.updateValue(true, forKey: board) == nil {
boards[board] = ASPropertyEntry()
boards[board]!["provenience"] = provenience
boards[board]!["library"] = dir
}
boards[board]![property] = value
}

View File

@ -468,12 +468,6 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate {
@IBAction func uploadProject(sender: AnyObject) {
builder.continuation = {
self.selectNodeInOutline(self.files.uploadLog)
ASSerialWin.portNeededForUpload(self.port)
self.builder.continuation = {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2*NSEC_PER_SEC)), dispatch_get_main_queue(), {
ASSerialWin.portAvailableAfterUpload(self.port)
})
}
dispatch_async(dispatch_get_main_queue(), {
self.builder.uploadProject(self.board, programmer:self.programmer, port:self.port)
})
@ -482,7 +476,12 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate {
}
@IBAction func uploadTerminal(sender: AnyObject) {
builder.uploadProject(board, programmer:programmer, port:port, terminal:true)
builder.uploadProject(board, programmer:programmer, port:port, mode:.Interactive)
}
@IBAction func burnBootloader(sender: AnyObject) {
self.selectNodeInOutline(self.files.uploadLog)
builder.uploadProject(board, programmer:programmer, port:port, mode:.BurnBootloader)
}
@IBAction func disassembleProject(sender: AnyObject) {

View File

@ -22,8 +22,8 @@
<rect key="frame" x="0.0" y="0.0" width="751" height="403"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rIR-2b-lAh">
<rect key="frame" x="0.0" y="0.0" width="651" height="22"/>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rIR-2b-lAh">
<rect key="frame" x="0.0" y="2" width="601" height="22"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="EBj-i4-UsA">
<font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -39,10 +39,10 @@
</connections>
</textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MOe-eO-fyb">
<rect key="frame" x="651" y="0.0" width="50" height="20"/>
<rect key="frame" x="601" y="0.0" width="75" height="20"/>
<constraints>
<constraint firstAttribute="height" constant="20" id="eLx-yy-gCn"/>
<constraint firstAttribute="width" constant="50" id="vaT-Kd-3pn"/>
<constraint firstAttribute="width" constant="75" id="vaT-Kd-3pn"/>
</constraints>
<buttonCell key="cell" type="square" title="Send" bezelStyle="shadowlessSquare" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Xt6-lT-b4z">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -58,9 +58,9 @@
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="H05-Rp-UzR">
<rect key="frame" x="701" y="0.0" width="50" height="20"/>
<rect key="frame" x="676" y="0.0" width="75" height="20"/>
<constraints>
<constraint firstAttribute="width" constant="50" id="FWw-BQ-WKa"/>
<constraint firstAttribute="width" constant="75" id="FWw-BQ-WKa"/>
<constraint firstAttribute="height" constant="20" id="s7i-ZT-S7W"/>
</constraints>
<buttonCell key="cell" type="square" title="Now" bezelStyle="shadowlessSquare" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="vZ4-fd-aE8">

View File

@ -395,6 +395,12 @@
<action selector="uploadProject:" target="-1" id="Un4-q1-nWg"/>
</connections>
</menuItem>
<menuItem title="Burn Bootloader/Fuses" id="vvl-LN-SXu">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="burnBootloader:" target="-1" id="FYp-at-8g4"/>
</connections>
</menuItem>
<menuItem title="Upload Terminal" keyEquivalent="U" id="jAF-od-ZFb">
<connections>
<action selector="uploadTerminal:" target="-1" id="hth-ZZ-S3I"/>