diff --git a/app/build.xml b/app/build.xml index f6cf1c33e..7ad00d3cb 100644 --- a/app/build.xml +++ b/app/build.xml @@ -101,6 +101,7 @@ + diff --git a/app/test/cc/arduino/packages/uploaders/MergeSketchWithUploaderTest.java b/app/test/cc/arduino/packages/uploaders/MergeSketchWithUploaderTest.java new file mode 100644 index 000000000..384aa169d --- /dev/null +++ b/app/test/cc/arduino/packages/uploaders/MergeSketchWithUploaderTest.java @@ -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()); + } + + +} diff --git a/app/test/optiboot_atmega328.hex b/app/test/optiboot_atmega328.hex new file mode 100644 index 000000000..2a09a245d --- /dev/null +++ b/app/test/optiboot_atmega328.hex @@ -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 diff --git a/app/test/processing/app/debug/UploaderFactoryTest.java b/app/test/processing/app/debug/UploaderFactoryTest.java index 827025265..f20df78d4 100644 --- a/app/test/processing/app/debug/UploaderFactoryTest.java +++ b/app/test/processing/app/debug/UploaderFactoryTest.java @@ -47,7 +47,6 @@ public class UploaderFactoryTest extends AbstractWithPreferencesTest { @Test public void shouldCreateAnInstanceOfSSHUploader() throws Exception { TargetBoard board = new LegacyTargetBoard("yun", new PreferencesMap(new HashMap()), 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()), 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()), new TargetPlatformStub("id", new TargetPackageStub("id"))); - board.getPreferences().put("upload.via_ssh", "false"); BoardPort boardPort = new BoardPort(); boardPort.setBoardName("Arduino Leonardo"); diff --git a/app/test/processing/app/helpers/StringUtilsTest.java b/app/test/processing/app/helpers/StringUtilsTest.java new file mode 100644 index 000000000..1ddbf51b3 --- /dev/null +++ b/app/test/processing/app/helpers/StringUtilsTest.java @@ -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"}, " - ")); + } +} diff --git a/app/test/sketch.hex b/app/test/sketch.hex new file mode 100644 index 000000000..e6c812c07 --- /dev/null +++ b/app/test/sketch.hex @@ -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 diff --git a/arduino-core/src/cc/arduino/packages/UploaderFactory.java b/arduino-core/src/cc/arduino/packages/UploaderFactory.java index 56828a753..860d3da8f 100644 --- a/arduino-core/src/cc/arduino/packages/UploaderFactory.java +++ b/arduino-core/src/cc/arduino/packages/UploaderFactory.java @@ -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); } diff --git a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java index 48d9cdd4b..7413062a8 100644 --- a/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java +++ b/arduino-core/src/cc/arduino/packages/discoverers/NetworkDiscovery.java @@ -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(); diff --git a/arduino-core/src/cc/arduino/packages/uploaders/MergeSketchWithBooloader.java b/arduino-core/src/cc/arduino/packages/uploaders/MergeSketchWithBooloader.java new file mode 100644 index 000000000..a6f34b265 --- /dev/null +++ b/arduino-core/src/cc/arduino/packages/uploaders/MergeSketchWithBooloader.java @@ -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 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(); + } + } + } + +} diff --git a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java index cadb05736..99f5a51c7 100644 --- a/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java +++ b/arduino-core/src/cc/arduino/packages/uploaders/SSHUploader.java @@ -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 warningsAccumulator) throws RunnerException { + public boolean uploadUsingPreferences(File sourcePath, String buildPath, String className, boolean usingProgrammer, List 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 warningsAccumulator) throws JSchException, IOException { + private void scpFiles(SCP scp, SSH ssh, File sourcePath, File sketch, List 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)) { diff --git a/arduino-core/src/processing/app/debug/Compiler.java b/arduino-core/src/processing/app/debug/Compiler.java index 3de715384..42393add1 100644 --- a/arduino-core/src/processing/app/debug/Compiler.java +++ b/arduino-core/src/processing/app/debug/Compiler.java @@ -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 paths = Arrays.asList("{build.path}/{build.project_name}.hex", "{build.path}/{build.project_name}.bin"); + Optional 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 compiledSketches = new ArrayList(prefs.subTree("recipe.output.tmp_file", 1).values()); + if (!compiledSketches.isEmpty()) { + List copyOfCompiledSketches = new ArrayList(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 includeFolders) { String res = ""; diff --git a/arduino-core/src/processing/app/helpers/FileUtils.java b/arduino-core/src/processing/app/helpers/FileUtils.java index 9d138b841..fdc0b2570 100644 --- a/arduino-core/src/processing/app/helpers/FileUtils.java +++ b/arduino-core/src/processing/app/helpers/FileUtils.java @@ -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 readFileToListOfStrings(File file) throws IOException { + List strings = new LinkedList(); + 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 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 - * true 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 true 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 listFiles(File folder, boolean recursive, diff --git a/arduino-core/src/processing/app/helpers/StringReplacer.java b/arduino-core/src/processing/app/helpers/StringReplacer.java index 19f7bce58..f51bfd7b6 100644 --- a/arduino-core/src/processing/app/helpers/StringReplacer.java +++ b/arduino-core/src/processing/app/helpers/StringReplacer.java @@ -92,9 +92,9 @@ public class StringReplacer { public static String replaceFromMapping(String src, Map 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 entry : map.entrySet()) { + String keyword = leftDelimiter + entry.getKey() + rightDelimiter; + src = src.replace(keyword, entry.getValue()); } return src; } diff --git a/arduino-core/src/processing/app/helpers/StringUtils.java b/arduino-core/src/processing/app/helpers/StringUtils.java index fb60df330..d17e7022c 100644 --- a/arduino-core/src/processing/app/helpers/StringUtils.java +++ b/arduino-core/src/processing/app/helpers/StringUtils.java @@ -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()); + } }