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(":") let libPath = (ASLibraries.instance().directories as NSArray).componentsJoinedByString(":")
var args = [NSString]() var args = [NSString]()
let boardProp = ASHardware.instance().boards[board]! let boardProp = ASHardware.instance().boards[board]!
var corePath = "" let library = boardProp["library"]!
var corePath = library+"/cores/"+boardProp["build.core"]!
var variantPath : NSString? var variantPath : NSString?
for hw in ASHardware.instance().directories {
corePath = hw+"/cores/"+boardProp["build.core"]!
if fileManager.fileExistsAtPath(corePath) { if fileManager.fileExistsAtPath(corePath) {
if let variantName = boardProp["build.variant"] { if let variantName = boardProp["build.variant"] {
variantPath = hw+"/variants/"+variantName variantPath = library+"/variants/"+variantName
if fileManager.fileExistsAtPath(variantPath!) { if fileManager.fileExistsAtPath(variantPath!) {
args.append("variant="+variantName) args.append("variant="+variantName)
} else { } else {
variantPath = nil variantPath = nil
} }
} }
break
} else { } else {
corePath = ""
}
}
if corePath == "" {
NSLog("Unable to find core %s\n", boardProp["build.core"]!) NSLog("Unable to find core %s\n", boardProp["build.core"]!)
return return
} }
@ -99,7 +93,15 @@ class ASBuilder {
task!.launch() 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 portPath = ASSerial.fileNameForPort(port)
let toolChain = (NSApplication.sharedApplication().delegate as ASApplication).preferences.toolchainPath let toolChain = (NSApplication.sharedApplication().delegate as ASApplication).preferences.toolchainPath
task = NSTask() task = NSTask()
@ -108,7 +110,7 @@ class ASBuilder {
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
var logOut : NSFileHandle var logOut : NSFileHandle
if terminal { if interactive {
let inputPipe = NSPipe() let inputPipe = NSPipe()
let outputPipe = NSPipe() let outputPipe = NSPipe()
logOut = outputPipe.fileHandleForWriting logOut = outputPipe.fileHandleForWriting
@ -116,6 +118,7 @@ class ASBuilder {
task!.standardOutput = outputPipe task!.standardOutput = outputPipe
task!.standardError = outputPipe task!.standardError = outputPipe
} else { } else {
ASSerialWin.portNeededForUpload(port)
let logURL = dir.URLByAppendingPathComponent("build/upload.log") let logURL = dir.URLByAppendingPathComponent("build/upload.log")
fileManager.createFileAtPath(logURL.path!, contents: NSData(), attributes: nil) fileManager.createFileAtPath(logURL.path!, contents: NSData(), attributes: nil)
logOut = NSFileHandle(forWritingAtPath: logURL.path!)! logOut = NSFileHandle(forWritingAtPath: logURL.path!)!
@ -126,7 +129,7 @@ class ASBuilder {
let libPath = (ASLibraries.instance().directories as NSArray).componentsJoinedByString(":") let libPath = (ASLibraries.instance().directories as NSArray).componentsJoinedByString(":")
let boardProp = ASHardware.instance().boards[board]! let boardProp = ASHardware.instance().boards[board]!
let progProp = ASHardware.instance().programmers[programmer] 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 leonardish = hasBootloader && (boardProp["bootloader.path"] ?? "").hasPrefix("caterina")
let proto = hasBootloader ? boardProp["upload.protocol"] : progProp?["protocol"] let proto = hasBootloader ? boardProp["upload.protocol"] : progProp?["protocol"]
let speed = hasBootloader ? boardProp["upload.speed"] : progProp?["speed"] let speed = hasBootloader ? boardProp["upload.speed"] : progProp?["speed"]
@ -135,10 +138,59 @@ class ASBuilder {
args += [ args += [
"-C", toolChain+"/etc/avrdude.conf", "-C", toolChain+"/etc/avrdude.conf",
"-p", boardProp["build.mcu"]!, "-c", proto!, "-P", portPath] "-p", boardProp["build.mcu"]!, "-c", proto!, "-P", portPath]
if terminal { switch mode {
args += ["-t"] case .Upload:
} else { if hasBootloader {
args += ["-D"]
}
args += ["-U", "flash:w:build/"+board+"/"+dir.lastPathComponent+".hex:i"] 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 { if speed != nil {
args.append("-b") args.append("-b")
@ -171,7 +223,7 @@ class ASBuilder {
logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) logOut.writeData(cmdLine.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!)
task!.arguments = args; task!.arguments = args;
task!.launch() task!.launch()
if terminal { if interactive {
let intSpeed = speed?.toInt() ?? 19200 let intSpeed = speed?.toInt() ?? 19200
ASSerialWin.showWindowWithPort(port, task:task!, speed:intSpeed) ASSerialWin.showWindowWithPort(port, task:task!, speed:intSpeed)
task = nil task = nil

View File

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

View File

@ -468,12 +468,6 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate {
@IBAction func uploadProject(sender: AnyObject) { @IBAction func uploadProject(sender: AnyObject) {
builder.continuation = { builder.continuation = {
self.selectNodeInOutline(self.files.uploadLog) 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(), { dispatch_async(dispatch_get_main_queue(), {
self.builder.uploadProject(self.board, programmer:self.programmer, port:self.port) 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) { @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) { @IBAction func disassembleProject(sender: AnyObject) {

View File

@ -22,8 +22,8 @@
<rect key="frame" x="0.0" y="0.0" width="751" height="403"/> <rect key="frame" x="0.0" y="0.0" width="751" height="403"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rIR-2b-lAh"> <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="rIR-2b-lAh">
<rect key="frame" x="0.0" y="0.0" width="651" height="22"/> <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"> <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"/> <font key="font" metaFont="system"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/> <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -39,10 +39,10 @@
</connections> </connections>
</textField> </textField>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MOe-eO-fyb"> <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> <constraints>
<constraint firstAttribute="height" constant="20" id="eLx-yy-gCn"/> <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> </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"> <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"/> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
@ -58,9 +58,9 @@
</connections> </connections>
</button> </button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="H05-Rp-UzR"> <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> <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"/> <constraint firstAttribute="height" constant="20" id="s7i-ZT-S7W"/>
</constraints> </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"> <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"/> <action selector="uploadProject:" target="-1" id="Un4-q1-nWg"/>
</connections> </connections>
</menuItem> </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"> <menuItem title="Upload Terminal" keyEquivalent="U" id="jAF-od-ZFb">
<connections> <connections>
<action selector="uploadTerminal:" target="-1" id="hth-ZZ-S3I"/> <action selector="uploadTerminal:" target="-1" id="hth-ZZ-S3I"/>