diff --git a/app/exportapplet.txt b/app/exportapplet.txt
deleted file mode 100644
index 0176121ef..000000000
--- a/app/exportapplet.txt
+++ /dev/null
@@ -1,300 +0,0 @@
- /*
- // make sure the user didn't hide the sketch folder
- ensureExistence();
-
- zipFileContents = new Hashtable();
-
- // nuke the old applet folder because it can cause trouble
- File appletFolder = new File(folder, "applet");
- Base.removeDir(appletFolder);
- appletFolder.mkdirs();
-
- // build the sketch
- String foundName = build(appletFolder.getPath(), name);
-
- // (already reported) error during export, exit this function
- if (foundName == null) return false;
-
- // if name != exportSketchName, then that's weirdness
- // BUG unfortunately, that can also be a bug in the preproc :(
- if (!name.equals(foundName)) {
- Base.showWarning("Error during export",
- "Sketch name is " + name + " but the sketch\n" +
- "name in the code was " + foundName, null);
- return false;
- }
-
- int wide = PApplet.DEFAULT_WIDTH;
- int high = PApplet.DEFAULT_HEIGHT;
-
- PatternMatcher matcher = new Perl5Matcher();
- PatternCompiler compiler = new Perl5Compiler();
-
- // this matches against any uses of the size() function,
- // whether they contain numbers of variables or whatever.
- // this way, no warning is shown if size() isn't actually
- // used in the applet, which is the case especially for
- // beginners that are cutting/pasting from the reference.
- // modified for 83 to match size(XXX, ddd so that it'll
- // properly handle size(200, 200) and size(200, 200, P3D)
- String sizing =
- "[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)";
- Pattern pattern = compiler.compile(sizing);
-
- // adds a space at the beginning, in case size() is the very
- // first thing in the program (very common), since the regexp
- // needs to check for things in front of it.
- PatternMatcherInput input =
- new PatternMatcherInput(" " + code[0].program);
- if (matcher.contains(input, pattern)) {
- MatchResult result = matcher.getMatch();
- try {
- wide = Integer.parseInt(result.group(1).toString());
- high = Integer.parseInt(result.group(2).toString());
-
- } catch (NumberFormatException e) {
- // found a reference to size, but it didn't
- // seem to contain numbers
- final String message =
- "The size of this applet could not automatically be\n" +
- "determined from your code. You'll have to edit the\n" +
- "HTML file to set the size of the applet.";
-
- Base.showWarning("Could not find applet size", message, null);
- }
- } // else no size() command found
-
- // originally tried to grab this with a regexp matcher,
- // but it wouldn't span over multiple lines for the match.
- // this could prolly be forced, but since that's the case
- // better just to parse by hand.
- StringBuffer dbuffer = new StringBuffer();
- String lines[] = PApplet.split(code[0].program, '\n');
- for (int i = 0; i < lines.length; i++) {
- if (lines[i].trim().startsWith("/**")) { // this is our comment
- // some smartass put the whole thing on the same line
- //if (lines[j].indexOf("*/") != -1) break;
-
- for (int j = i+1; j < lines.length; j++) {
- if (lines[j].trim().endsWith("*/")) {
- // remove the */ from the end, and any extra *s
- // in case there's also content on this line
- // nah, don't bother.. make them use the three lines
- break;
- }
-
- int offset = 0;
- while ((offset < lines[j].length()) &&
- ((lines[j].charAt(offset) == '*') ||
- (lines[j].charAt(offset) == ' '))) {
- offset++;
- }
- // insert the return into the html to help w/ line breaks
- dbuffer.append(lines[j].substring(offset) + "\n");
- }
- }
- }
- String description = dbuffer.toString();
-
- StringBuffer sources = new StringBuffer();
- for (int i = 0; i < codeCount; i++) {
- sources.append("" +
- code[i].name + " ");
- }
-
- File htmlOutputFile = new File(appletFolder, "index.html");
- FileOutputStream fos = new FileOutputStream(htmlOutputFile);
- PrintStream ps = new PrintStream(fos);
-
- // @@sketch@@, @@width@@, @@height@@, @@archive@@, @@source@@
- // and now @@description@@
-
- InputStream is = null;
- // if there is an applet.html file in the sketch folder, use that
- File customHtml = new File(folder, "applet.html");
- if (customHtml.exists()) {
- is = new FileInputStream(customHtml);
- }
- if (is == null) {
- is = Base.getStream("applet.html");
- }
- BufferedReader reader = new BufferedReader(new InputStreamReader(is));
-
- String line = null;
- while ((line = reader.readLine()) != null) {
- if (line.indexOf("@@") != -1) {
- StringBuffer sb = new StringBuffer(line);
- int index = 0;
- while ((index = sb.indexOf("@@sketch@@")) != -1) {
- sb.replace(index, index + "@@sketch@@".length(),
- name);
- }
- while ((index = sb.indexOf("@@source@@")) != -1) {
- sb.replace(index, index + "@@source@@".length(),
- sources.toString());
- }
- while ((index = sb.indexOf("@@archive@@")) != -1) {
- sb.replace(index, index + "@@archive@@".length(),
- name + ".jar");
- }
- while ((index = sb.indexOf("@@width@@")) != -1) {
- sb.replace(index, index + "@@width@@".length(),
- String.valueOf(wide));
- }
- while ((index = sb.indexOf("@@height@@")) != -1) {
- sb.replace(index, index + "@@height@@".length(),
- String.valueOf(high));
- }
- while ((index = sb.indexOf("@@description@@")) != -1) {
- sb.replace(index, index + "@@description@@".length(),
- description);
- }
- line = sb.toString();
- }
- ps.println(line);
- }
-
- reader.close();
- ps.flush();
- ps.close();
-
- // copy the loading gif to the applet
- String LOADING_IMAGE = "loading.gif";
- File loadingImage = new File(folder, LOADING_IMAGE);
- if (!loadingImage.exists()) {
- loadingImage = new File("lib", LOADING_IMAGE);
- }
- Base.copyFile(loadingImage, new File(appletFolder, LOADING_IMAGE));
-
- // copy the source files to the target, since we like
- // to encourage people to share their code
- for (int i = 0; i < codeCount; i++) {
- try {
- Base.copyFile(code[i].file,
- new File(appletFolder, code[i].file.getName()));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- // create new .jar file
- FileOutputStream zipOutputFile =
- new FileOutputStream(new File(appletFolder, name + ".jar"));
- ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
- ZipEntry entry;
-
- // add the manifest file
- addManifest(zos);
-
- // add the contents of the code folder to the jar
- // unpacks all jar files
- //File codeFolder = new File(folder, "code");
- if (codeFolder.exists()) {
- String includes = Compiler.contentsToClassPath(codeFolder);
- packClassPathIntoZipFile(includes, zos);
- }
-
- // add contents of 'library' folders to the jar file
- // if a file called 'export.txt' is in there, it contains
- // a list of the files that should be exported.
- // otherwise, all files are exported.
- Enumeration en = importedLibraries.elements();
- while (en.hasMoreElements()) {
- // in the list is a File object that points the
- // library sketch's "library" folder
- File libraryFolder = (File)en.nextElement();
- File exportSettings = new File(libraryFolder, "export.txt");
- String exportList[] = null;
- if (exportSettings.exists()) {
- String info[] = Base.loadStrings(exportSettings);
- for (int i = 0; i < info.length; i++) {
- if (info[i].startsWith("applet")) {
- int idx = info[i].indexOf('='); // get applet= or applet =
- String commas = info[i].substring(idx+1).trim();
- exportList = PApplet.split(commas, ", ");
- }
- }
- } else {
- exportList = libraryFolder.list();
- }
- for (int i = 0; i < exportList.length; i++) {
- if (exportList[i].equals(".") ||
- exportList[i].equals("..")) continue;
-
- exportList[i] = PApplet.trim(exportList[i]);
- if (exportList[i].equals("")) continue;
-
- File exportFile = new File(libraryFolder, exportList[i]);
- if (!exportFile.exists()) {
- System.err.println("File " + exportList[i] + " does not exist");
-
- } else if (exportFile.isDirectory()) {
- System.err.println("Ignoring sub-folder \"" + exportList[i] + "\"");
-
- } else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
- exportFile.getName().toLowerCase().endsWith(".jar")) {
- packClassPathIntoZipFile(exportFile.getAbsolutePath(), zos);
-
- } else { // just copy the file over.. prolly a .dll or something
- Base.copyFile(exportFile,
- new File(appletFolder, exportFile.getName()));
- }
- }
- }
-
- String bagelJar = "lib/core.jar";
- packClassPathIntoZipFile(bagelJar, zos);
-
- // files to include from data directory
- // TODO this needs to be recursive
- if (dataFolder.exists()) {
- String dataFiles[] = dataFolder.list();
- for (int i = 0; i < dataFiles.length; i++) {
- // don't export hidden files
- // skipping dot prefix removes all: . .. .DS_Store
- if (dataFiles[i].charAt(0) == '.') continue;
-
- entry = new ZipEntry(dataFiles[i]);
- zos.putNextEntry(entry);
- zos.write(Base.grabFile(new File(dataFolder, dataFiles[i])));
- zos.closeEntry();
- }
- }
-
- // add the project's .class files to the jar
- // just grabs everything from the build directory
- // since there may be some inner classes
- // (add any .class files from the applet dir, then delete them)
- // TODO this needs to be recursive (for packages)
- String classfiles[] = appletFolder.list();
- for (int i = 0; i < classfiles.length; i++) {
- if (classfiles[i].endsWith(".class")) {
- entry = new ZipEntry(classfiles[i]);
- zos.putNextEntry(entry);
- zos.write(Base.grabFile(new File(appletFolder, classfiles[i])));
- zos.closeEntry();
- }
- }
-
- // remove the .class files from the applet folder. if they're not
- // removed, the msjvm will complain about an illegal access error,
- // since the classes are outside the jar file.
- for (int i = 0; i < classfiles.length; i++) {
- if (classfiles[i].endsWith(".class")) {
- File deadguy = new File(appletFolder, classfiles[i]);
- if (!deadguy.delete()) {
- Base.showWarning("Could not delete",
- classfiles[i] + " could not \n" +
- "be deleted from the applet folder. \n" +
- "You'll need to remove it by hand.", null);
- }
- }
- }
-
- // close up the jar file
- zos.flush();
- zos.close();
-
- Base.openFolder(appletFolder);
- return true;
- */
diff --git a/bootloader/ATmegaBOOT.bin b/bootloader/ATmegaBOOT.bin
new file mode 100755
index 000000000..8cd79b8fa
Binary files /dev/null and b/bootloader/ATmegaBOOT.bin differ
diff --git a/bootloader/ATmegaBOOT.c b/bootloader/ATmegaBOOT.c
new file mode 100755
index 000000000..407abd8bd
--- /dev/null
+++ b/bootloader/ATmegaBOOT.c
@@ -0,0 +1,555 @@
+/**********************************************************/
+/* Serial Bootloader for Atmel megaAVR Controllers */
+/* */
+/* ATmegaBOOT.c */
+/* */
+/* build: 050123 */
+/* */
+/* Hacked by DojoCorp - ZGZ - MMX - IVR */
+/* */
+/* For the latest version see: */
+/* http://www.0j0.org and */
+/* http://www.potemkin.org */
+/* */
+/* ------------------------------------------------------ */
+/* */
+/* Copyleft (c) 2005, DojoDave */
+/* Creative Commons . */
+/* see avr1.org for original file and information */
+/* */
+/* This program 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., */
+/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* */
+/* Licence can be viewed at */
+/* http://www.fsf.org/licenses/gpl.txt */
+/* */
+/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
+/* m8515,m8535. ATmega161 has a very small boot block so */
+/* isn't supported. */
+/* */
+/* Tested with m8 - */
+/* */
+/**********************************************************/
+
+#include
+#include
+#include
+#include
+#include
+
+#define F_CPU 16000000
+
+/* We, Malmoitians, like slow interaction
+ * therefore the slow baud rate ;-)
+ */
+#define BAUD_RATE 19200
+
+/* 6.000.000 is more or less 8 seconds at the
+ * speed configured here
+ */
+#define MAX_TIME_COUNT 6000000
+#define MAX_TIME_COUNT_MORATORY 1600000
+
+#define DECRYPT 0
+#define ENCRYPT 1
+/* #define DES_ENCRYPTION */
+
+/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
+#define HW_VER 0x02
+#define SW_MAJOR 0x01
+#define SW_MINOR 0x12
+
+// AVR-GCC compiler compatibility
+// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
+// if necessary, convert outb and inb to outp and inp
+#ifndef outb
+ #define outb(sfr,val) (_SFR_BYTE(sfr) = (val))
+#endif
+#ifndef inb
+ #define inb(sfr) _SFR_BYTE(sfr)
+#endif
+
+/* defines for future compatibility */
+#ifndef cbi
+#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
+#endif
+#ifndef sbi
+#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
+#endif
+
+/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
+#define eeprom_rb(addr) eeprom_read_byte ((uint8_t *)(addr))
+#define eeprom_rw(addr) eeprom_read_word ((uint16_t *)(addr))
+#define eeprom_wb(addr, val) eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))
+
+/* other ATmegas have only one UART, so only one pin is defined to enter bootloader */
+#define BL_DDR DDRD
+#define BL_PORT PORTD
+#define BL_PIN PIND
+#define BL PIND6
+
+/* define pin for onboard LED */
+/* depends on product */
+
+/* Onboard LED is connected to pin PB5 */
+#define LED_DDR DDRB
+#define LED_PORT PORTB
+#define LED_PIN PINB
+#define LED PINB5
+
+
+#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
+#define SIG2 0x93
+#define SIG3 0x07
+#define PAGE_SIZE 0x20U //32 words
+
+
+void putch(char);
+char getch(void);
+void getNch(uint8_t);
+void byte_response(uint8_t);
+void nothing_response(void);
+char gethex(void);
+void puthex(char);
+
+union address_union {
+ uint16_t word;
+ uint8_t byte[2];
+} address;
+
+union length_union {
+ uint16_t word;
+ uint8_t byte[2];
+} length;
+
+struct flags_struct {
+ unsigned eeprom : 1;
+ unsigned rampz : 1;
+} flags;
+
+uint8_t buff[256];
+uint8_t address_high;
+
+uint8_t pagesz=0x80;
+
+uint8_t i;
+uint8_t bootuart0=0,bootuart1=0;
+
+
+void (*app_start)(void) = 0x0000;
+
+int main(void)
+{
+ uint8_t ch,ch2;
+ uint16_t w;
+
+ cbi(BL_DDR,BL);
+ sbi(BL_PORT,BL);
+
+ asm volatile("nop\n\t");
+
+ /* check if flash is programmed already, if not start bootloader anyway */
+ if(pgm_read_byte_near(0x0000) != 0xFF) {
+
+ /* check if bootloader pin is set low */
+ //if(bit_is_set(BL_PIN,BL)) app_start();
+ }
+
+ /* initialize UART(s) depending on CPU defined */
+ /* m8 */
+ UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate
+ UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
+ UCSRB =(1<> 8;
+ //UCSRA = 0x00;
+ //UCSRC = 0x86;
+ //UCSRB = _BV(TXEN)|_BV(RXEN);
+
+ putch('\0');
+
+ uint32_t l;
+ uint32_t time_count;
+ time_count=0;
+
+ /* set LED pin as output */
+ sbi(LED_DDR,LED);
+
+ /* flash onboard LED three times to signal entering of bootloader */
+ for(i=0; i<3; ++i) {
+ for(l=0; l<40000000; ++l);
+ sbi(LED_PORT,LED);
+ for(l=0; l<40000000; ++l);
+ cbi(LED_PORT,LED);
+ }
+ putch('\0'); // this line is needed for the synchronization of the programmer
+
+ /* forever */
+ for (;;) {
+ if((inb(UCSRA) & _BV(RXC))){
+ /* get character from UART */
+ ch = getch();
+
+ /* A bunch of if...else if... gives smaller code than switch...case ! */
+
+ /* Hello is anyone home ? */
+ if(ch=='0') {
+ nothing_response();
+ }
+
+ if(ch=='l') {
+ if (getch() == 'o') {
+ if (getch() == 'l') {
+ if (getch() == 'a') {
+ app_start();
+ }
+ }
+ }
+ }
+
+ /* Request programmer ID */
+ /* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
+ /* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
+ else if(ch=='1') {
+ if (getch() == ' ') {
+ putch(0x14);
+ putch('A');
+ putch('V');
+ putch('R');
+ putch(' ');
+ putch('I');
+ putch('S');
+ putch('P');
+ putch(0x10);
+ }
+ }
+
+ /* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
+ else if(ch=='@') {
+ ch2 = getch();
+ if (ch2>0x85) getch();
+ nothing_response();
+ }
+
+ /* AVR ISP/STK500 board requests */
+ else if(ch=='A') {
+ ch2 = getch();
+ if(ch2==0x80) byte_response(HW_VER); // Hardware version
+ else if(ch2==0x81) byte_response(SW_MAJOR); // Software major version
+ else if(ch2==0x82) byte_response(SW_MINOR); // Software minor version
+ else if(ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
+ else byte_response(0x00); // Covers various unnecessary responses we don't care about
+ }
+
+ /* Device Parameters DON'T CARE, DEVICE IS FIXED */
+ else if(ch=='B') {
+ getNch(20);
+ nothing_response();
+ }
+
+ /* Parallel programming stuff DON'T CARE */
+ else if(ch=='E') {
+ getNch(5);
+ nothing_response();
+ }
+
+ /* Enter programming mode */
+ else if(ch=='P') {
+ nothing_response();
+ // FIXME: modified only here by DojoCorp, Mumbai, India, 20050626
+ time_count=0; // exted the delay once entered prog.mode
+ }
+
+ /* Leave programming mode */
+ else if(ch=='Q') {
+ nothing_response();
+ time_count=MAX_TIME_COUNT_MORATORY; // once the programming is done,
+ // we should start the application
+ // but uisp has problems with this,
+ // therefore we just change the times
+ // and give the programmer 1 sec to react
+ }
+
+ /* Erase device, don't care as we will erase one page at a time anyway. */
+ else if(ch=='R') {
+ nothing_response();
+ }
+
+ /* Set address, little endian. EEPROM in bytes, FLASH in words */
+ /* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
+ /* This might explain why little endian was used here, big endian used everywhere else. */
+ else if(ch=='U') {
+ address.byte[0] = getch();
+ address.byte[1] = getch();
+ nothing_response();
+ }
+
+ /* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
+ else if(ch=='V') {
+ getNch(4);
+ byte_response(0x00);
+ }
+
+ /* Write memory, length is big endian and is in bytes */
+ else if(ch=='d') {
+ length.byte[1] = getch();
+ length.byte[0] = getch();
+ flags.eeprom = 0;
+ if (getch() == 'E') flags.eeprom = 1;
+ for (w=0;w127) address_high = 0x01; //Only possible with m128, m256 will need 3rd address byte. FIXME
+ else address_high = 0x00;
+
+ address.word = address.word << 1; //address * 2 -> byte location
+ /* if ((length.byte[0] & 0x01) == 0x01) length.word++; //Even up an odd number of bytes */
+ if ((length.byte[0] & 0x01)) length.word++; //Even up an odd number of bytes
+ cli(); //Disable interrupts, just to be sure
+ while(bit_is_set(EECR,EEWE)); //Wait for previous EEPROM writes to complete
+ asm volatile("clr r17 \n\t" //page_word_count
+ "lds r30,address \n\t" //Address of FLASH location (in bytes)
+ "lds r31,address+1 \n\t"
+ "ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
+ "ldi r29,hi8(buff) \n\t"
+ "lds r24,length \n\t" //Length of data to be written (in bytes)
+ "lds r25,length+1 \n\t"
+ "length_loop: \n\t" //Main loop, repeat for number of words in block
+ "cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
+ "brne no_page_erase \n\t"
+ "wait_spm1: \n\t"
+ "lds r16,%0 \n\t" //Wait for previous spm to complete
+ "andi r16,1 \n\t"
+ "cpi r16,1 \n\t"
+ "breq wait_spm1 \n\t"
+ "ldi r16,0x03 \n\t" //Erase page pointed to by Z
+ "sts %0,r16 \n\t"
+ "spm \n\t"
+ "wait_spm2: \n\t"
+ "lds r16,%0 \n\t" //Wait for previous spm to complete
+ "andi r16,1 \n\t"
+ "cpi r16,1 \n\t"
+ "breq wait_spm2 \n\t"
+
+ "ldi r16,0x11 \n\t" //Re-enable RWW section
+ "sts %0,r16 \n\t"
+ "spm \n\t"
+ "no_page_erase: \n\t"
+ "ld r0,Y+ \n\t" //Write 2 bytes into page buffer
+ "ld r1,Y+ \n\t"
+
+ "wait_spm3: \n\t"
+ "lds r16,%0 \n\t" //Wait for previous spm to complete
+ "andi r16,1 \n\t"
+ "cpi r16,1 \n\t"
+ "breq wait_spm3 \n\t"
+ "ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
+ "sts %0,r16 \n\t"
+ "spm \n\t"
+
+ "inc r17 \n\t" //page_word_count++
+ "cpi r17,%1 \n\t"
+ "brlo same_page \n\t" //Still same page in FLASH
+ "write_page: \n\t"
+ "clr r17 \n\t" //New page, write current one first
+ "wait_spm4: \n\t"
+ "lds r16,%0 \n\t" //Wait for previous spm to complete
+ "andi r16,1 \n\t"
+ "cpi r16,1 \n\t"
+ "breq wait_spm4 \n\t"
+ "ldi r16,0x05 \n\t" //Write page pointed to by Z
+ "sts %0,r16 \n\t"
+ "spm \n\t"
+ "wait_spm5: \n\t"
+ "lds r16,%0 \n\t" //Wait for previous spm to complete
+ "andi r16,1 \n\t"
+ "cpi r16,1 \n\t"
+ "breq wait_spm5 \n\t"
+ "ldi r16,0x11 \n\t" //Re-enable RWW section
+ "sts %0,r16 \n\t"
+ "spm \n\t"
+ "same_page: \n\t"
+ "adiw r30,2 \n\t" //Next word in FLASH
+ "sbiw r24,2 \n\t" //length-2
+ "breq final_write \n\t" //Finished
+ "rjmp length_loop \n\t"
+ "final_write: \n\t"
+ "cpi r17,0 \n\t"
+ "breq block_done \n\t"
+ "adiw r24,2 \n\t" //length+2, fool above check on length after short page write
+ "rjmp write_page \n\t"
+ "block_done: \n\t"
+ "clr __zero_reg__ \n\t" //restore zero register
+ : "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31");
+
+ /* Should really add a wait for RWW section to be enabled, don't actually need it since we never */
+ /* exit the bootloader without a power cycle anyhow */
+ }
+ putch(0x14);
+ putch(0x10);
+ }
+ }
+
+ /* Read memory block mode, length is big endian. */
+ else if(ch=='t') {
+ length.byte[1] = getch();
+ length.byte[0] = getch();
+ if (getch() == 'E') flags.eeprom = 1;
+ else {
+ flags.eeprom = 0;
+ address.word = address.word << 1; // address * 2 -> byte location
+ }
+ if (getch() == ' ') { // Command terminator
+ putch(0x14);
+ for (w=0;w < length.word;w++) { // Can handle odd and even lengths okay
+ if (flags.eeprom) { // Byte access EEPROM read
+ putch(eeprom_rb(address.word));
+ address.word++;
+ }
+ else {
+
+ if (!flags.rampz) putch(pgm_read_byte_near(address.word));
+ address.word++;
+ }
+ }
+ putch(0x10);
+ }
+ }
+
+ /* Get device signature bytes */
+ else if(ch=='u') {
+ if (getch() == ' ') {
+ putch(0x14);
+ putch(SIG1);
+ putch(SIG2);
+ putch(SIG3);
+ putch(0x10);
+ }
+ }
+
+ /* Read oscillator calibration byte */
+ else if(ch=='v') {
+ byte_response(0x00);
+ }
+ }
+ else {
+ time_count++;
+ if (time_count>=MAX_TIME_COUNT) {
+ app_start();
+ }
+ }
+
+ }
+ /* end of forever loop */
+
+}
+
+
+char gethex(void) {
+ char ah,al;
+
+ ah = getch(); putch(ah);
+ al = getch(); putch(al);
+ if(ah >= 'a') {
+ ah = ah - 'a' + 0x0a;
+ } else if(ah >= '0') {
+ ah -= '0';
+ }
+ if(al >= 'a') {
+ al = al - 'a' + 0x0a;
+ } else if(al >= '0') {
+ al -= '0';
+ }
+ return (ah << 4) + al;
+}
+
+void puthex(char ch) {
+ char ah,al;
+
+ ah = (ch & 0xf0) >> 4;
+ if(ah >= 0x0a) {
+ ah = ah - 0x0a + 'a';
+ } else {
+ ah += '0';
+ }
+ al = (ch & 0x0f);
+ if(al >= 0x0a) {
+ al = al - 0x0a + 'a';
+ } else {
+ al += '0';
+ }
+ putch(ah);
+ putch(al);
+}
+
+void putch(char ch)
+{
+ /* m8 */
+ while (!(inb(UCSRA) & _BV(UDRE)));
+ outb(UDR,ch);
+}
+
+char getch(void)
+{
+ /* m8 */
+ while(!(inb(UCSRA) & _BV(RXC))) {
+ /* HACKME:: here is a good place to count times*/
+ }
+ return (inb(UDR));
+}
+
+void getNch(uint8_t count)
+{
+ uint8_t i;
+ for(i=0;i $@
+
+# Rules for building the .text rom images
+
+text: hex bin srec
+
+hex: $(PROGRAM).hex
+bin: $(PROGRAM).bin
+srec: $(PROGRAM).srec
+
+%.hex: %.elf
+ $(OBJCOPY) -j .text -j .data -O ihex $< $@
+
+%.srec: %.elf
+ $(OBJCOPY) -j .text -j .data -O srec $< $@
+
+%.bin: %.elf
+ $(OBJCOPY) -j .text -j .data -O binary $< $@
diff --git a/bootloader/build.bat b/bootloader/build.bat
new file mode 100755
index 000000000..cf8682070
--- /dev/null
+++ b/bootloader/build.bat
@@ -0,0 +1,6 @@
+avr-gcc -g -Wall -O3 -mmcu=atmega8 -DCRUMB8 -c -o ATmegaBOOT.o ATmegaBOOT.c
+avr-gcc -g -Wall -O3 -mmcu=atmega8 -DCRUMB8 -Wl,-Map,ATmegaBOOT.map,--section-start=.text=0x1800 -o ATmegaBOOT.elf ATmegaBOOT.o
+avr-objdump -S -h ATmegaBOOT.elf > ATmegaBOOT.lst
+avr-objcopy -j .text -j .data -O ihex ATmegaBOOT.elf ATmegaBOOT.hex
+avr-objcopy -j .text -j .data -O binary ATmegaBOOT.elf ATmegaBOOT.bin
+avr-objcopy -j .text -j .data -O srec ATmegaBOOT.elf ATmegaBOOT.srec
diff --git a/bootloader/fixmybootloader.command b/bootloader/fixmybootloader.command
new file mode 100755
index 000000000..8f13da7df
--- /dev/null
+++ b/bootloader/fixmybootloader.command
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+# fixmybootloader.command 25.06.2005 mbanzi
+#
+# Arduino project http://arduino.berlios.de
+#
+# quick and dirty script to set the proper fuses and lock bits
+# while loading the bootloader onto a brand new arduino board
+#
+# very useful also when for some reasons the bootloader disappears
+#
+# TODO: cleanup and make it more user friendly
+#
+# expects an STK500 compatible programmer on the specified serial port
+# if you use the parallel port programmer you need to change the dprog
+# parametre
+#
+
+BINDIR=/usr/local/avr/bin
+#PORT=/dev/tty.usbserial0
+PORT=/dev/tty.USA19QW3b1P1.1
+
+$BINDIR/uisp -dpart=ATmega8 -dprog=stk500 -dserial=$PORT -dspeed=115200 --wr_lock=0xFF
+$BINDIR/uisp -dpart=ATmega8 -dprog=stk500 -dserial=$PORT -dspeed=115200 --wr_fuse_l=0xdf --wr_fuse_h=0xc8
+$BINDIR/uisp -dpart=ATmega8 -dprog=stk500 -dserial=$PORT -dspeed=115200 --erase --upload if=ATMegaBOOT.hex -v
+$BINDIR/uisp -dpart=ATmega8 -dprog=stk500 -dserial=$PORT -dspeed=115200 --wr_lock=0xCF
diff --git a/bootloader/program.bat b/bootloader/program.bat
new file mode 100755
index 000000000..b38c80da4
--- /dev/null
+++ b/bootloader/program.bat
@@ -0,0 +1,2 @@
+..\wiringlite\bin\uisp -dpart=ATmega8 -dprog=stk500 -dserial=com1 -dspeed=115200 --wr_fuse_l=0xdf --wr_fuse_h=0xc8
+..\wiringlite\bin\uisp -dpart=ATmega8 -dprog=stk500 -dserial=com1 -dspeed=115200 --erase --upload --verify if=ATMegaBOOT.hex
diff --git a/bootloader/program.command b/bootloader/program.command
new file mode 100755
index 000000000..8d91d60ca
--- /dev/null
+++ b/bootloader/program.command
@@ -0,0 +1 @@
+uisp -dpart=ATmega8 -dprog=avrisp -dserial=/dev/tty.usbserial0 -dspeed=115200 if=ATMegaBOOT.hex --erase --upload --verify