Extending remote upload. Sketch merge with bootloader is done by the IDE (using "noblink" bootloader if board definition provides one). If platform provides a "remote" upload tool, that tool is used, otherwise falls back to hardcoded "run-avrdude"

This commit is contained in:
Federico Fissore 2015-06-18 12:22:55 +02:00
parent 1f8c9642a3
commit 88e8019419
14 changed files with 663 additions and 90 deletions

View File

@ -101,6 +101,7 @@
<fileset dir="test" includes="**/*.ino" />
<fileset dir="test" includes="**/*.json*" />
<fileset dir="test" includes="**/*.key" />
<fileset dir="test" includes="**/*.hex" />
</copy>
<junit printsummary="yes" dir="${work.dir}" fork="true">

View File

@ -0,0 +1,67 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.uploaders;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import processing.app.helpers.FileUtils;
import java.io.File;
import static org.junit.Assert.assertEquals;
public class MergeSketchWithUploaderTest {
private File sketch;
@Before
public void setup() throws Exception {
File originalSketch = new File(MergeSketchWithUploaderTest.class.getResource("/sketch.hex").getFile());
sketch = new File(System.getProperty("java.io.tmpdir"), "sketch.hex");
FileUtils.copyFile(originalSketch, sketch);
}
@After
public void removeTmpFile() {
sketch.delete();
}
@Test
public void shouldMergeWithOptiboot() throws Exception {
assertEquals(11720, sketch.length());
File bootloader = new File(MergeSketchWithUploaderTest.class.getResource("/optiboot_atmega328.hex").getFile());
new MergeSketchWithBooloader().merge(sketch, bootloader);
assertEquals(13140, sketch.length());
}
}

View File

@ -0,0 +1,35 @@
:107E0000112484B714BE81FFF0D085E080938100F7
:107E100082E08093C00088E18093C10086E0809377
:107E2000C20080E18093C4008EE0C9D0259A86E02C
:107E300020E33CEF91E0309385002093840096BBD3
:107E4000B09BFECF1D9AA8958150A9F7CC24DD24C4
:107E500088248394B5E0AB2EA1E19A2EF3E0BF2EE7
:107E6000A2D0813461F49FD0082FAFD0023811F036
:107E7000013811F484E001C083E08DD089C08234E0
:107E800011F484E103C0853419F485E0A6D080C0E4
:107E9000853579F488D0E82EFF2485D0082F10E0AE
:107EA000102F00270E291F29000F111F8ED06801E7
:107EB0006FC0863521F484E090D080E0DECF843638
:107EC00009F040C070D06FD0082F6DD080E0C81688
:107ED00080E7D80618F4F601B7BEE895C0E0D1E017
:107EE00062D089930C17E1F7F0E0CF16F0E7DF06D8
:107EF00018F0F601B7BEE89568D007B600FCFDCFD4
:107F0000A601A0E0B1E02C9130E011968C91119780
:107F100090E0982F8827822B932B1296FA010C0160
:107F200087BEE89511244E5F5F4FF1E0A038BF0790
:107F300051F7F601A7BEE89507B600FCFDCF97BE46
:107F4000E89526C08437B1F42ED02DD0F82E2BD052
:107F50003CD0F601EF2C8F010F5F1F4F84911BD097
:107F6000EA94F801C1F70894C11CD11CFA94CF0C13
:107F7000D11C0EC0853739F428D08EE10CD085E9AC
:107F80000AD08FE07ACF813511F488E018D01DD067
:107F900080E101D065CF982F8091C00085FFFCCF94
:107FA0009093C60008958091C00087FFFCCF809118
:107FB000C00084FD01C0A8958091C6000895E0E648
:107FC000F0E098E1908380830895EDDF803219F02E
:107FD00088E0F5DFFFCF84E1DECF1F93182FE3DFCA
:107FE0001150E9F7F2DF1F91089580E0E8DFEE27F6
:047FF000FF270994CA
:027FFE00040479
:0400000300007E007B
:00000001FF

View File

@ -47,7 +47,6 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
@Test
public void shouldCreateAnInstanceOfSSHUploader() throws Exception {
TargetBoard board = new LegacyTargetBoard("yun", new PreferencesMap(new HashMap<String, String>()), new TargetPlatformStub("id", new TargetPackageStub("id")));
board.getPreferences().put("upload.via_ssh", "true");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("yun");
@ -58,24 +57,9 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest {
assertTrue(uploader instanceof SSHUploader);
}
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenSSHIsUnsupported() throws Exception {
TargetBoard board = new LegacyTargetBoard("uno", new PreferencesMap(new HashMap<String, String>()), new TargetPlatformStub("id", new TargetPackageStub("id")));
board.getPreferences().put("upload.via_ssh", "false");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("myyun");
boardPort.setAddress("192.168.0.1");
boardPort.setProtocol("network");
Uploader uploader = new UploaderFactory().newUploader(board, boardPort, false);
assertTrue(uploader instanceof SerialUploader);
}
@Test
public void shouldCreateAnInstanceOfBasicUploaderWhenPortIsSerial() throws Exception {
TargetBoard board = new LegacyTargetBoard("uno", new PreferencesMap(new HashMap<String, String>()), new TargetPlatformStub("id", new TargetPackageStub("id")));
board.getPreferences().put("upload.via_ssh", "false");
BoardPort boardPort = new BoardPort();
boardPort.setBoardName("Arduino Leonardo");

View File

@ -0,0 +1,42 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package processing.app.helpers;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class StringUtilsTest {
@Test
public void shouldJoinAnArray() {
assertEquals("1 - 2 - 3", StringUtils.join(new String[]{"1", "2", "3"}, " - "));
}
}

268
app/test/sketch.hex Normal file
View File

@ -0,0 +1,268 @@
:100000000C941D010C9445010C9445010C94450180
:100010000C9445010C9445010C9445010C94450148
:100020000C9445010C9445010C9479050C944504FD
:100030000C9445010C9445010C9445010C94450128
:100040000C9445010C9445010C9445010C94450118
:100050000C9445010C9445010C9445010C945D01F0
:100060000C9445010C9445010C9445010C944501F8
:100070000C9445010C9445010C9445010C944501E8
:100080000C9445010C9445010C9445010C944501D8
:100090000C9445010C9445010C9445010C944501C8
:1000A0000C9445010C9445010C94450100C18081DC
:1000B000C11201000202000040412336800001010C
:1000C00002000112010002000000404123368000BE
:1000D000010102000141726475696E6F204C4C434E
:1000E0000041726475696E6F204C656F6E61726459
:1000F0006F000403090400000000000000002A2B28
:1001000028000000000000000000000000000000C7
:100110000000000000002C9EB4A0A1A2A434A6A759
:10012000A5AE362D3738271E1F2021222324252651
:10013000B333B62EB7B89F8485868788898A8B8C1F
:100140008D8E8F909192939495969798999A9B9C67
:100150009D2F3130A3AD350405060708090A0B0CA5
:100160000D0E0F101112131415161718191A1B1C47
:100170001DAFB1B0B5000904020001030000000981
:1001800021010100012265000705840340000105EB
:10019000010902A1010901A100850105091901292F
:1001A00003150025019503750181029501750581EF
:1001B0000305010930093109381581257F75089536
:1001C000038106C0C005010906A1018502050719C2
:1001D000E029E71500250175019508810295017553
:1001E000088103950675081500256505071900297E
:1001F000658100C0080B0002020201000904000032
:10020000010202000005240010010524010101047F
:100210002402060524060001070581031000400999
:10022000040100020A000000070502024000000766
:100230000583024000002307150811241FBECFEFDD
:10024000DAE0DEBFCDBF11E0A0E0B1E0E4E7F0E12D
:1002500002C005900D92A832B107D9F721E0A8E2BB
:10026000B1E001C01D92A739B207E1F712E0CAE37D
:10027000D2E004C02297FE010E943408C633D107A1
:10028000C9F70E944A010C9438080C9400000895A4
:10029000089508950E94F2010E94490181E391E0CE
:1002A0000E94CF050E944701C0E0D0E00E944801B3
:1002B0002097E1F30E940000F9CF1F920F920FB632
:1002C0000F9211242F933F938F939F93AF93BF93DC
:1002D0008091290190912A01A0912B01B0912C01CC
:1002E0003091280123E0230F2D3720F40196A11D22
:1002F000B11D05C026E8230F0296A11DB11D209354
:1003000028018093290190932A01A0932B01B09397
:100310002C0180912D0190912E01A0912F01B0917F
:1003200030010196A11DB11D80932D0190932E01E6
:10033000A0932F01B0933001BF91AF919F918F9106
:100340003F912F910F900FBE0F901F9018953FB7C0
:10035000F89480912D0190912E01A0912F01B091E0
:10036000300126B5A89B05C02F3F19F00196A11DAD
:10037000B11D3FBF6627782F892F9A2F620F711DFD
:10038000811D911D42E0660F771F881F991F4A95B6
:10039000D1F70895CF92DF92EF92FF92CF93DF9340
:1003A0006B017C010E94A701EB01C114D104E1049F
:1003B000F10489F00E9448020E94A7016C1B7D0B8A
:1003C000683E734090F381E0C81AD108E108F10853
:1003D000C851DC4FEACFDF91CF91FF90EF90DF90D3
:1003E000CF900895789484B5826084BD84B581608F
:1003F00084BD85B5826085BD85B5816085BDEEE62D
:10040000F0E0808181608083E1E8F0E0108280810B
:1004100082608083808181608083E0E8F0E0808179
:1004200081608083E1E9F0E0808182608083808167
:1004300081608083E0E9F0E0808181608083E1EC8D
:10044000F0E080818460808380818260808380810D
:1004500081608083E3ECF0E0808181608083E0EC68
:10046000F0E0808182608083E2ECF0E08081816056
:100470008083EAE7F0E0808184608083808182600D
:1004800080838081816080838081806880830895FB
:1004900008954091350150913601209133013091FA
:1004A000340142175307B4F49091E8009570E1F3DA
:1004B0009091E80092FD19C08093F1008091350180
:1004C0009091360101968F739927892B19F48EEF3D
:1004D0008093E800809135019091360101969093C8
:1004E00036018093350181E0089580E00895CF9230
:1004F000DF92FF920F931F93CF93DF931F92CDB79D
:10050000DEB7082F162F862F880F8E5F99830E94E3
:10051000490283E00E944902F02EC02E9981D92E13
:100520008C2D8F19811778F4F60184910E9449026D
:10053000082F80E00E9449028023FFEFCF1ADF0AD4
:100540008111EECF01C081E00F90DF91CF911F911B
:100550000F91FF90DF90CF900895615030F020917F
:10056000F100FC0120830196F8CF289884E680935F
:10057000380108952FB7FC012083F89467706093C9
:10058000E9000895CF93DF931F92CDB7DEB7682FB0
:10059000CE0101960E94BA028091F20099819FBF1C
:1005A0000F90DF91CF910895FF920F931F93CF93F8
:1005B000DF9300D0CDB7DEB7F62E8A0190913701D8
:1005C000992311F057FF03C08FEF9FEF2BC0682FC7
:1005D000CE0101967A830E94BA028091F20090E0E7
:1005E000A8017A81801791070CF4AC01EF2DF72F49
:1005F000F40E84E6FE1639F0289880933801909125
:10060000F1009193F7CF4115510521F08091F2004F
:10061000882321F089818FBFCA0104C08BE68093B3
:10062000E800F8CF0F900F90DF91CF911F910F91BD
:10063000FF900895CF93DF931F92CDB7DEB741E0CF
:1006400050E0BE016F5F7F4F0E94D402019719F402
:10065000898190E002C08FEF9FEF0F90DF91CF91E3
:100660000895CF93DF931F92CDB7DEB7682FCE01E9
:1006700001960E94BA029091E800892F807295FF3E
:1006800004C09091F20080E4891B99819FBF0F9074
:10069000DF91CF9108956F927F928F929F92AF9248
:1006A000BF92CF92DF92EF92FF920F931F93CF935F
:1006B000DF931F92CDB7DEB7782E7B01C42EB52E07
:1006C00080913701882369F0042F152F8AEFD82EE7
:1006D000872D8072982E9AE3A92E872D8074882EFC
:1006E00011C08FEF9FEF57C0872D0E943103682EF6
:1006F00081110CC0DA94A9F361E070E080E090E031
:100700000E94CA010115110579F73BC0282F30E07E
:10071000021713070CF4602E672DCE0101960E947C
:10072000BA028091E80085FF29C0262D30E0021B27
:10073000130B992039F06A948FEF6816B1F010927C
:10074000F100F9CFF701862D77FE07C0815058F0F0
:1007500094919093F1003196F9CF815020F09191CE
:100760009093F100FACFE20EF31E8091E80085FF2E
:100770000FC00115110511F481100AC089818FBFC6
:10078000C1CF5D9884E6809339018C2D9B2D03C0E9
:10079000A092E800F3CF0F90DF91CF911F910F91BE
:1007A000FF90EF90DF90CF90BF90AF909F908F9091
:1007B0007F906F9008951092E90010923601109288
:1007C000350190933401809333010895CF92DF92E5
:1007D000FF920F931F93CF93DF9300D0CDB7DEB777
:1007E000F82E8A016B0101151105B1F0F601F7FE33
:1007F00002C0849101C0808149835A830E944902CA
:1008000001501109FFEFCF1ADF0A49815A81811186
:10081000EACF8FEF9FEF01C0CA010F900F90DF91D9
:10082000CF911F910F91FF90DF90CF9008951F936C
:10083000CF93DF931F92CDB7DEB7162F2091E8003C
:1008400022FFFCCF612F79830E94AD028BEF809352
:10085000E800812F7981972F0F90DF91CF911F9121
:100860000895CF93DF931F92CDB7DEB71982CE01E3
:1008700001960E94B507CE0101960E940B06898160
:1008800090E00F90DF91CF9108951F920F920FB6D5
:100890000F921124EF92FF920F931F932F933F9388
:1008A0004F935F936F937F938F939F93AF93BF9378
:1008B000EF93FF93CF93DF93CDB7DEB76297DEBFA1
:1008C000CDBF1092E9008091E80083FFEBC068E0A3
:1008D000CE010A960E94AD0282EF8093E8009A85CD
:1008E00097FF05C08091E80080FFFCCF03C08EEF2A
:1008F0008093E800892F807609F0B9C08B8581113B
:1009000005C01092F1001092F100C5C0282F2D7F74
:10091000213009F4C0C0853049F48091E80080FF9F
:10092000FCCF8C8580688093E300B5C0863009F0E9
:1009300076C02D85E888F988223071F580E090E056
:100940002A8B0E94DB030E94310499E08E010F5F25
:100950001F4FF801392F11923A95E9F799832A89A7
:100960002A8391E09E8390E898879AEF9987209157
:10097000350130913601275F3F4F3C832B838D83B8
:10098000C7010E94DB0349E050E0B80180E00E940B
:10099000E6030E9431047FC0C7012A8B0E94DB035B
:1009A0002A89223241F482E290E00E941606892BC5
:1009B00009F071C074C0213069F488899989089759
:1009C00011F42093320180913201811118C063EC3F
:1009D00070E01AC0233009F062C08C85882391F042
:1009E000823021F460E181EE90E006C0813009F0B0
:1009F00056C06BE085ED90E00E9477024AC061EB43
:100A000070E002C062EF70E06115710509F447C043
:100A1000FB01449150E080E80E94E6033CC087302F
:100A200009F43DC0883021F481E08093F10033C0A7
:100A3000893089F5937099F5EDEAF0E081E021E0E5
:100A400096E38093E9002093EB0034913093EC001F
:100A50009093ED008F5F3196853099F78EE7809304
:100A6000EA001092EA008C858093370114C08889CF
:100A700099890E94DB038E85811105C0CE010A96FB
:100A80000E94C00706C0823051F4CE010A960E942F
:100A90003E06882321F08EEF8093E80003C081E2B8
:100AA0008093EB0062960FB6F894DEBF0FBECDBF09
:100AB000DF91CF91FF91EF91BF91AF919F918F9176
:100AC0007F916F915F914F913F912F911F910F9166
:100AD000FF90EF900F900FBE0F901F90189580938E
:100AE000E9008091F200882319F08AE38093E800FE
:100AF00008951F920F920FB60F9211242F933F93D8
:100B00004F935F936F937F938F939F93AF93BF9315
:100B1000EF93FF938091E1001092E10083FF0FC0FB
:100B20001092E90091E09093EB001092EC0092E3B8
:100B30009093ED001092370198E09093F00082FFBF
:100B40001DC083E00E946F0580913901882339F030
:100B500080913901815080933901882369F0809117
:100B60003801882359F080913801815080933801F1
:100B7000811104C0289A02C05D9AF1CFFF91EF91D4
:100B8000BF91AF919F918F917F916F915F914F91A5
:100B90003F912F910F900FBE0F901F9018951092BC
:100BA000370181E08093D70080EA8093D80082E10A
:100BB00089BD09B400FEFDCF61E070E080E090E007
:100BC0000E94CA0180E98093D8008CE08093E20003
:100BD0001092E000559A209A0895FF920F931F9368
:100BE000CF93DF93EC01F62EE881F9810480F58143
:100BF000E02D09958C01E881F9810680F781E02DCF
:100C00006F2DCE010995C8019927DF91CF911F91D2
:100C10000F91FF900895FC0120812F5F208349E10F
:100C200050E066E771E080E80C94E60345E650E0AA
:100C30006FE871E080E80C94E603EF92FF920F9367
:100C40001F93CF93DF931F92CDB7DEB789838B01BC
:100C50007A0141E050E0BE016F5F7F4F84E00E9467
:100C60004B03A701B80184E40E944B030F90DF916E
:100C7000CF911F910F91FF90EF900895FC0191810A
:100C80008081813A31F481E0913091F0933089F4A0
:100C900011C0813271F49B3021F482818093010173
:100CA00005C09A3031F482818093000181E008957B
:100CB000089580E0089548E050E082E00C941D061D
:100CC000CF93DF93DC01683818F0E8E7E60F25C022
:100CD000E62FF0E067FF11C0E058F10981E090E0F5
:100CE00001C0880FEA95EAF714969C911497982B07
:100CF00014969C931497E0E010C0EA50FF4FE491E3
:100D0000EE2309F440C0E7FF08C014968C911497B5
:100D1000826014968C931497EF7716968C911697A1
:100D20008E1741F117968C9117978E1719F1189617
:100D30008C9118978E17F1F019968C9119978E1740
:100D4000C9F01A968C911A978E17A1F01B968C9168
:100D50001B978E1779F080E090E0ED01C80FD91F46
:100D60002E81211102C0EE8305C0019686309105C7
:100D7000A1F709C0BD016C5F7F4FCD010E945B06EA
:100D800081E090E008C081E090E013969C938E9300
:100D9000129780E090E0DF91CF910895683818F0C5
:100DA000E8E7E60F25C0E62FF0E067FF12C0E05845
:100DB000F10921E030E001C0220FEA95EAF7209521
:100DC000DC0114963C911497322314963C93E0E096
:100DD0000FC0EA50FF4FE491EE2329F1E7FF08C06E
:100DE000DC0114962C9114972D7F14962C93EF7799
:100DF00020E030E0EE2351F0DC01A20FB31F169685
:100E00004C9116974E1302C016961C922F5F3F4FBF
:100E10002630310579F7BC016C5F7F4F0E945B067D
:100E200081E090E0089580E090E00895FC01168252
:100E3000178210861186128613861482BC016C5F9D
:100E40007F4F0C945B061092460110923D01109268
:100E50003C018EE091E090933B0180933A0108952C
:100E6000CF92DF92EF92FF920F931F93CF93DF9376
:100E70006C017A01EB01E60EF71E00E010E0CE15E2
:100E8000DF0561F06991D601ED91FC910190F0814F
:100E9000E02DC6010995080F191FF1CFC801DF9198
:100EA000CF911F910F91FF90EF90DF90CF90089519
:100EB000CF93DF931F92CDB7DEB76983DC01ED914D
:100EC000FC910280F381E02D41E050E0BE016F5FB4
:100ED0007F4F09950F90DF91CF910895CF93DF93C6
:100EE000EC018C859D8597FF05C082E00E941A0366
:100EF0009D878C878C859D85DF91CF91089583E0B8
:100F00000C946F05FC018485958597FD06C082E0F1
:100F10000E94C20290E00196089582E00E94C202FF
:100F200090E00895FC018485958597FD05C02FEF1D
:100F30003FEF35872487089582E00C941A03CF93FE
:100F4000DF93EC0180910901882331F083E00E9456
:100F50004B031816190634F081E090E09B838A83D6
:100F600080E090E0DF91CF910895FC0120812E5F19
:100F7000208342E450E064EF71E080E80C94E603E3
:100F8000FC0181819081913A59F4813209F03CC091
:100F900047E050E062E071E080E00E94E60343C079
:100FA000913291F5803239F467E070E082E091E0AF
:100FB0000E94170406C0823209F035C082818093F6
:100FC00009018091020190910301A0910401B09167
:100FD0000501803B9440A105B105C1F48091090150
:100FE00080FD14C087E797E790930108809300087D
:100FF0002BE088E190E00FB6F894A895809360000C
:101000000FBE209360000FC080E0089588E10FB606
:10101000F89480936000109260000FBEA895109223
:1010200001081092000881E0089510924A01109280
:10103000490188EE93E0A0E0B0E080934B019093EB
:101040004C01A0934D01B0934E018CE191E090933F
:101050004801809347018FEF9FEF90935401809355
:1010600053010895EE0FFF1F0590F491E02D0994B0
:04107000F894FFCF22
:10107400010100E100000000000000000000ED0597
:1010840030076006CE0616070000000058079F07C9
:08109400820792076E077F0737
:00000001FF

View File

@ -40,7 +40,7 @@ public class UploaderFactory {
return new SerialUploader(true);
}
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && port != null && "network".equals(port.getProtocol())) {
if (port != null && "network".equals(port.getProtocol())) {
return new SSHUploader(port);
}

View File

@ -141,9 +141,11 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
PreferencesMap prefs = null;
String board = null;
String description = null;
if (info.hasData()) {
prefs = new PreferencesMap();
board = info.getPropertyString("board");
description = info.getPropertyString("description");
prefs.put("board", board);
prefs.put("distro_version", info.getPropertyString("distro_version"));
prefs.put("port", "" + info.getPort());
@ -155,6 +157,8 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
if (boardName != null) {
label += " (" + boardName + ")";
}
} else if (description != null) {
label += " (" + description + ")";
}
BoardPort port = new BoardPort();

View File

@ -0,0 +1,60 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.uploaders;
import processing.app.helpers.FileUtils;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
public class MergeSketchWithBooloader {
public void merge(File sketch, File bootloader) throws IOException {
List<String> mergedSketch = FileUtils.readFileToListOfStrings(sketch);
mergedSketch.remove(mergedSketch.size() - 1);
mergedSketch.addAll(FileUtils.readFileToListOfStrings(bootloader));
FileWriter writer = null;
try {
writer = new FileWriter(sketch);
for (String line : mergedSketch) {
writer.write(line);
writer.write("\n");
}
} finally {
if (writer != null) {
writer.close();
}
}
}
}

View File

@ -38,10 +38,8 @@ import com.jcraft.jsch.Session;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.PreferencesData;
import processing.app.debug.RunnerException;
import processing.app.debug.TargetPlatform;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.StringUtils;
import processing.app.debug.*;
import processing.app.helpers.*;
import java.io.File;
import java.io.IOException;
@ -70,11 +68,33 @@ public class SSHUploader extends Uploader {
}
@Override
public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws RunnerException {
public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List<String> warningsAccumulator) throws RunnerException, PreferencesMapException {
if (usingProgrammer) {
throw new RunnerException(_("Network upload using programmer not supported"));
}
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
PreferencesMap prefs = PreferencesData.getMap();
prefs.putAll(BaseNoGui.getBoardPreferences());
String tool = prefs.getOrExcept("upload.tool");
if (tool.contains(":")) {
String[] split = tool.split(":", 2);
targetPlatform = BaseNoGui.getCurrentTargetPlatformFromPackage(split[0]);
tool = split[1];
}
prefs.putAll(targetPlatform.getTool(tool));
boolean coreMissesRemoteUploadTool = targetPlatform.getTool(tool + "_remote").isEmpty();
if (coreMissesRemoteUploadTool) {
prefs.put("upload.pattern", "/usr/bin/run-avrdude /tmp/sketch.hex");
} else {
prefs.putAll(targetPlatform.getTool(tool + "_remote"));
}
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
Session session = null;
SCP scp = null;
try {
@ -88,9 +108,21 @@ public class SSHUploader extends Uploader {
scp = new SCP(session);
SSH ssh = new SSH(session);
scpFiles(scp, ssh, sourcePath, buildPath, className, warningsAccumulator);
File mergedSketch = new File(buildPath, className + ".with_bootloader.hex");
return runAVRDude(ssh);
File sketchToCopy;
if (!coreMissesRemoteUploadTool && mergedSketch.exists()) {
sketchToCopy = mergedSketch;
} else {
sketchToCopy = processing.app.debug.Compiler.findCompiledSketch(prefs);
}
scpFiles(scp, ssh, sourcePath, sketchToCopy, warningsAccumulator);
if (coreMissesRemoteUploadTool) {
ssh.execSyncCommand("merge-sketch-with-bootloader.lua /tmp/sketch.hex", System.out, System.err);
}
return runUploadTool(ssh, prefs);
} catch (JSchException e) {
String message = e.getMessage();
if ("Auth cancel".equals(message) || "Auth fail".equals(message)) {
@ -116,28 +148,32 @@ public class SSHUploader extends Uploader {
}
}
private boolean runAVRDude(SSH ssh) throws IOException, JSchException {
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
PreferencesMap prefs = PreferencesData.getMap();
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
if (boardPreferences != null) {
prefs.putAll(boardPreferences);
}
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
String additionalParams = verbose ? prefs.get("upload.params.verbose") : prefs.get("upload.params.quiet");
boolean success = ssh.execSyncCommand("merge-sketch-with-bootloader.lua /tmp/sketch.hex", System.out, System.err);
private boolean runUploadTool(SSH ssh, PreferencesMap prefs) throws Exception {
ssh.execSyncCommand("kill-bridge");
success = success && ssh.execSyncCommand("run-avrdude /tmp/sketch.hex '" + additionalParams + "'", System.out, System.err);
return success;
if (verbose) {
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.verbose"));
} else {
prefs.put("upload.verbose", prefs.getOrExcept("upload.params.quiet"));
}
String pattern = prefs.getOrExcept("upload.pattern");
String[] cmd = StringReplacer.formatAndSplit(pattern, prefs, true);
return ssh.execSyncCommand(StringUtils.join(cmd, " "), System.out, System.err);
}
private void scpFiles(SCP scp, SSH ssh, File sourcePath, String buildPath, String className, List<String> warningsAccumulator) throws JSchException, IOException {
private void scpFiles(SCP scp, SSH ssh, File sourcePath, File sketch, List<String> warningsAccumulator) throws JSchException, IOException {
String uploadedSketchFileName;
if (sketch.getName().endsWith("hex")) {
uploadedSketchFileName = "sketch.hex";
} else {
uploadedSketchFileName = "sketch.bin";
}
try {
scp.open();
scp.startFolder("tmp");
scp.sendFile(new File(buildPath, className + ".hex"), "sketch.hex");
scp.sendFile(sketch, uploadedSketchFileName);
scp.endFolder();
if (canUploadWWWFiles(sourcePath, ssh, warningsAccumulator)) {

View File

@ -26,22 +26,14 @@ package processing.app.debug;
import static processing.app.I18n._;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.*;
import cc.arduino.MyStreamPumper;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderFactory;
import cc.arduino.packages.uploaders.MergeSketchWithBooloader;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.exec.*;
import processing.app.BaseNoGui;
@ -81,7 +73,7 @@ public class Compiler implements MessageConsumer {
* Listener interface for progress update on the GUI
*/
public interface ProgressListener {
public void progress(int percent);
void progress(int percent);
}
private ProgressListener progressListener;
@ -180,6 +172,17 @@ public class Compiler implements MessageConsumer {
return success;
}
static public File findCompiledSketch(PreferencesMap prefs) throws PreferencesMapException {
List<String> paths = Arrays.asList("{build.path}/{build.project_name}.hex", "{build.path}/{build.project_name}.bin");
Optional<File> sketch = paths.stream().
map(path -> StringReplacer.replaceFromMapping(path, prefs)).
map(File::new).
filter(File::exists).
findFirst();
return sketch.orElseThrow(() -> new IllegalStateException(_("No compiled sketch found")));
}
/**
* Create a new Compiler
* @param _sketch Sketch object to be compiled.
@ -454,6 +457,14 @@ public class Compiler implements MessageConsumer {
runActions("hooks.objcopy.postobjcopy", prefs);
progressListener.progress(70);
try {
mergeSketchWithBootloaderIfAppropriate(sketch.getName() + ".cpp", prefs);
} catch (IOException e) {
e.printStackTrace();
// ignore
}
// 7. save the hex file
if (saveHex) {
runActions("hooks.savehex.presavehex", prefs);
@ -545,20 +556,26 @@ public class Compiler implements MessageConsumer {
p.put("compiler.path", BaseNoGui.getAvrBasePath());
}
TargetPlatform referencePlatform = null;
if (corePlatform != null) {
referencePlatform = corePlatform;
} else {
referencePlatform = targetPlatform;
}
p.put("build.platform.path", referencePlatform.getFolder().getAbsolutePath());
// Core folder
TargetPlatform tp = corePlatform;
if (tp == null)
tp = targetPlatform;
File coreFolder = new File(tp.getFolder(), "cores");
File coreFolder = new File(referencePlatform.getFolder(), "cores");
coreFolder = new File(coreFolder, core);
p.put("build.core", core);
p.put("build.core.path", coreFolder.getAbsolutePath());
// System Folder
File systemFolder = tp.getFolder();
File systemFolder = referencePlatform.getFolder();
systemFolder = new File(systemFolder, "system");
p.put("build.system.path", systemFolder.getAbsolutePath());
// Variant Folder
String variant = p.get("build.variant");
if (variant != null) {
@ -1169,7 +1186,33 @@ public class Compiler implements MessageConsumer {
}
execAsynchronously(cmdArray);
}
private File mergeSketchWithBootloaderIfAppropriate(String className, PreferencesMap prefs) throws IOException {
if (!prefs.containsKey("bootloader.noblink") && !prefs.containsKey("bootloader.file")) {
return null;
}
String buildPath = prefs.get("build.path");
File sketch = new File(buildPath, className + ".hex");
if (!sketch.exists()) {
return null;
}
File mergedSketch = new File(buildPath, className + ".with_bootloader.hex");
FileUtils.copyFile(sketch, mergedSketch);
String bootloaderNoBlink = prefs.get("bootloader.noblink");
if (bootloaderNoBlink == null) {
bootloaderNoBlink = prefs.get("bootloader.file");
}
File bootloader = new File(new File(prefs.get("build.platform.path"), "bootloaders"), bootloaderNoBlink);
new MergeSketchWithBooloader().merge(mergedSketch, bootloader);
return mergedSketch;
}
//7. Save the .hex file
void saveHex() throws RunnerException {
if (!prefs.containsKey("recipe.output.tmp_file") || !prefs.containsKey("recipe.output.save_file")) {
@ -1181,9 +1224,23 @@ public class Compiler implements MessageConsumer {
dict.put("ide_version", "" + BaseNoGui.REVISION);
try {
String compiledSketch = prefs.getOrExcept("recipe.output.tmp_file");
List<String> compiledSketches = new ArrayList<String>(prefs.subTree("recipe.output.tmp_file", 1).values());
if (!compiledSketches.isEmpty()) {
List<String> copyOfCompiledSketches = new ArrayList<String>(prefs.subTree("recipe.output.save_file", 1).values());
for (int i = 0; i < compiledSketches.size(); i++) {
saveHex(compiledSketches.get(i), copyOfCompiledSketches.get(i), prefs);
}
} else {
saveHex(prefs.getOrExcept("recipe.output.tmp_file"), prefs.getOrExcept("recipe.output.save_file"), prefs);
}
} catch (Exception e) {
throw new RunnerException(e);
}
}
private void saveHex(String compiledSketch, String copyOfCompiledSketch, PreferencesMap dict) throws RunnerException {
try {
compiledSketch = StringReplacer.replaceFromMapping(compiledSketch, dict);
String copyOfCompiledSketch = prefs.getOrExcept("recipe.output.save_file");
copyOfCompiledSketch = StringReplacer.replaceFromMapping(copyOfCompiledSketch, dict);
File compiledSketchFile = new File(prefs.get("build.path"), compiledSketch);
@ -1194,7 +1251,6 @@ public class Compiler implements MessageConsumer {
throw new RunnerException(e);
}
}
private static String prepareIncludes(List<File> includeFolders) {
String res = "";

View File

@ -3,10 +3,7 @@ package processing.app.helpers;
import org.apache.commons.compress.utils.IOUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.*;
import java.util.regex.Pattern;
public class FileUtils {
@ -91,8 +88,7 @@ public class FileUtils {
}
public static File createTempFolderIn(File parent) throws IOException {
File tmpFolder = new File(parent, "arduino_"
+ new Random().nextInt(1000000));
File tmpFolder = new File(parent, "arduino_" + new Random().nextInt(1000000));
if (!tmpFolder.mkdir()) {
throw new IOException("Unable to create temp folder " + tmpFolder);
}
@ -195,27 +191,46 @@ public class FileUtils {
}
}
public static List<String> readFileToListOfStrings(File file) throws IOException {
List<String> strings = new LinkedList<String>();
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
line = line.replaceAll("\r", "").replaceAll("\n", "").replaceAll(" ", "");
strings.add(line);
}
return strings;
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Returns true if the given file has any of the given extensions.
* @param file
* File whose name to look at
* @param extensions
* Extensions to consider (just the extension, without the
* dot). Should all be lowercase, case insensitive matching
* is used.
*
* @param file File whose name to look at
* @param extensions Extensions to consider (just the extension, without the
* dot). Should all be lowercase, case insensitive matching
* is used.
*/
public static boolean hasExtension(File file, String... extensions) {
return hasExtension(file, Arrays.asList(extensions));
}
public static boolean hasExtension(File file, List<String> extensions) {
String pieces[] = file.getName().split("\\.");
if (pieces.length < 2)
return false;
String pieces[] = file.getName().split("\\.");
if (pieces.length < 2) {
return false;
}
String extension = pieces[pieces.length - 1];
String extension = pieces[pieces.length - 1];
return extensions.contains(extension.toLowerCase());
return extensions.contains(extension.toLowerCase());
}
@ -224,15 +239,12 @@ public class FileUtils {
* extension. Excludes hidden files and folders and
* source control folders.
*
* @param folder
* Folder to look into
* @param recursive
* <b>true</b> will recursively find all files in sub-folders
* @param extensions
* A list of file extensions to search (just the extension,
* without the dot). Should all be lowercase, case
* insensitive matching is used. If no extensions are
* passed, all files are returned.
* @param folder Folder to look into
* @param recursive <b>true</b> will recursively find all files in sub-folders
* @param extensions A list of file extensions to search (just the extension,
* without the dot). Should all be lowercase, case
* insensitive matching is used. If no extensions are
* passed, all files are returned.
* @return
*/
public static List<File> listFiles(File folder, boolean recursive,

View File

@ -92,9 +92,9 @@ public class StringReplacer {
public static String replaceFromMapping(String src, Map<String, String> map,
String leftDelimiter,
String rightDelimiter) {
for (String k : map.keySet()) {
String keyword = leftDelimiter + k + rightDelimiter;
src = src.replace(keyword, map.get(k));
for (Map.Entry<String, String> entry : map.entrySet()) {
String keyword = leftDelimiter + entry.getKey() + rightDelimiter;
src = src.replace(keyword, entry.getValue());
}
return src;
}

View File

@ -40,4 +40,12 @@ public class StringUtils {
}
return s.substring(0, i + 1);
}
public static String join(String[] arr, String separator) {
StringBuffer sb = new StringBuffer();
for (String s : arr) {
sb.append(s).append(separator);
}
return sb.substring(0, sb.length() - separator.length());
}
}