diff --git a/.classpath b/.classpath index 71e8cc144..5f528e603 100644 --- a/.classpath +++ b/.classpath @@ -2,9 +2,11 @@ - - - - + + + + + + diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs index ef277e5a2..a4e4441e5 100644 --- a/.settings/org.eclipse.jdt.core.prefs +++ b/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,15 @@ -#Thu Jan 10 10:50:38 PST 2008 +#Tue Aug 16 19:08:40 CEST 2011 eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 -org.eclipse.jdt.core.compiler.compliance=1.4 -org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning -org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning -org.eclipse.jdt.core.compiler.source=1.3 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.6 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 diff --git a/app/src/processing/app/Base.java b/app/src/processing/app/Base.java index 036cb4f5a..2e3d7b346 100644 --- a/app/src/processing/app/Base.java +++ b/app/src/processing/app/Base.java @@ -993,6 +993,13 @@ public class Base { } + public void onBoardOrPortChange() { + for (Editor editor : editors) { + editor.onBoardOrPortChange(); + } + } + + public void rebuildBoardsMenu(JMenu menu) { //System.out.println("rebuilding boards menu"); menu.removeAll(); @@ -1005,6 +1012,7 @@ public class Base { //System.out.println("Switching to " + target + ":" + board); Preferences.set("target", (String) getValue("target")); Preferences.set("board", (String) getValue("board")); + onBoardOrPortChange(); } }; action.putValue("target", target.getName()); diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index 33f1fc855..dd6ad5614 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -46,6 +46,7 @@ import gnu.io.*; /** * Main editor panel for the Processing Development Environment. */ +@SuppressWarnings("serial") public class Editor extends JFrame implements RunnerListener { Base base; @@ -113,7 +114,7 @@ public class Editor extends JFrame implements RunnerListener { EditorLineStatus lineStatus; - JEditorPane editorPane; + //JEditorPane editorPane; JEditTextArea textarea; EditorListener listener; @@ -195,8 +196,10 @@ public class Editor extends JFrame implements RunnerListener { //PdeKeywords keywords = new PdeKeywords(); //sketchbook = new Sketchbook(this); - if (serialMonitor == null) + if (serialMonitor == null) { serialMonitor = new SerialMonitor(Preferences.get("serial.port")); + serialMonitor.setIconImage(getIconImage()); + } buildMenuBar(); @@ -907,6 +910,7 @@ public class Editor extends JFrame implements RunnerListener { public void actionPerformed(ActionEvent e) { selectSerialPort(((JCheckBoxMenuItem)e.getSource()).getText()); + base.onBoardOrPortChange(); } /* @@ -1818,7 +1822,7 @@ public class Editor extends JFrame implements RunnerListener { internalCloseRunner(); running = true; toolbar.activate(EditorToolbar.RUN); - statusNotice("Compiling..."); + status.progress("Compiling sketch..."); // do this to advance/clear the terminal window / dos prompt / etc for (int i = 0; i < 10; i++) System.out.println(); @@ -1838,12 +1842,14 @@ public class Editor extends JFrame implements RunnerListener { public void run() { try { sketch.prepare(); - String appletClassName = sketch.build(false); + sketch.build(false); statusNotice("Done compiling."); } catch (Exception e) { + status.unprogress(); statusError(e); } + status.unprogress(); toolbar.deactivate(EditorToolbar.RUN); } } @@ -1853,12 +1859,14 @@ public class Editor extends JFrame implements RunnerListener { public void run() { try { sketch.prepare(); - String appletClassName = sketch.build(true); + sketch.build(true); statusNotice("Done compiling."); } catch (Exception e) { + status.unprogress(); statusError(e); } + status.unprogress(); toolbar.deactivate(EditorToolbar.RUN); } } @@ -2311,6 +2319,7 @@ public class Editor extends JFrame implements RunnerListener { 0); if (result == null) return false; selectSerialPort(result); + base.onBoardOrPortChange(); return true; } @@ -2334,7 +2343,7 @@ public class Editor extends JFrame implements RunnerListener { //if (!handleExportCheckModified()) return; toolbar.activate(EditorToolbar.EXPORT); console.clear(); - statusNotice("Uploading to I/O Board..."); + status.progress("Uploading to I/O Board..."); new Thread(usingProgrammer ? exportAppHandler : exportHandler).start(); } @@ -2363,10 +2372,12 @@ public class Editor extends JFrame implements RunnerListener { } catch (RunnerException e) { //statusError("Error during upload."); //e.printStackTrace(); + status.unprogress(); statusError(e); } catch (Exception e) { e.printStackTrace(); } + status.unprogress(); uploading = false; //toolbar.clear(); toolbar.deactivate(EditorToolbar.EXPORT); @@ -2397,10 +2408,12 @@ public class Editor extends JFrame implements RunnerListener { } catch (RunnerException e) { //statusError("Error during upload."); //e.printStackTrace(); + status.unprogress(); statusError(e); } catch (Exception e) { e.printStackTrace(); } + status.unprogress(); uploading = false; //toolbar.clear(); toolbar.deactivate(EditorToolbar.EXPORT); @@ -2615,30 +2628,49 @@ public class Editor extends JFrame implements RunnerListener { // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + protected void onBoardOrPortChange() { + Map boardPreferences = Base.getBoardPreferences(); + lineStatus.setBoardName(boardPreferences.get("name")); + lineStatus.setSerialPort(Preferences.get("serial.port")); + lineStatus.repaint(); + } + /** * Returns the edit popup menu. */ class TextAreaPopup extends JPopupMenu { - //String currentDir = System.getProperty("user.dir"); - String referenceFile = null; + //private String currentDir = System.getProperty("user.dir"); + private String referenceFile = null; - JMenuItem cutItem; - JMenuItem copyItem; - JMenuItem discourseItem; - JMenuItem referenceItem; + private JMenuItem cutItem; + private JMenuItem copyItem; + private JMenuItem discourseItem; + private JMenuItem referenceItem; + private JMenuItem openURLItem; + private JSeparator openURLItemSeparator; + private String clickedURL; public TextAreaPopup() { - JMenuItem item; - + openURLItem = new JMenuItem("Open URL"); + openURLItem.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + Base.openURL(clickedURL); + } + }); + add(openURLItem); + + openURLItemSeparator = new JSeparator(); + add(openURLItemSeparator); + cutItem = new JMenuItem("Cut"); cutItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleCut(); } }); - this.add(cutItem); + add(cutItem); copyItem = new JMenuItem("Copy"); copyItem.addActionListener(new ActionListener() { @@ -2646,7 +2678,7 @@ public class Editor extends JFrame implements RunnerListener { handleCopy(); } }); - this.add(copyItem); + add(copyItem); discourseItem = new JMenuItem("Copy for Forum"); discourseItem.addActionListener(new ActionListener() { @@ -2654,7 +2686,7 @@ public class Editor extends JFrame implements RunnerListener { handleDiscourseCopy(); } }); - this.add(discourseItem); + add(discourseItem); discourseItem = new JMenuItem("Copy as HTML"); discourseItem.addActionListener(new ActionListener() { @@ -2662,15 +2694,15 @@ public class Editor extends JFrame implements RunnerListener { handleHTMLCopy(); } }); - this.add(discourseItem); + add(discourseItem); - item = new JMenuItem("Paste"); + JMenuItem item = new JMenuItem("Paste"); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handlePaste(); } }); - this.add(item); + add(item); item = new JMenuItem("Select All"); item.addActionListener(new ActionListener() { @@ -2678,9 +2710,9 @@ public class Editor extends JFrame implements RunnerListener { handleSelectAll(); } }); - this.add(item); + add(item); - this.addSeparator(); + addSeparator(); item = new JMenuItem("Comment/Uncomment"); item.addActionListener(new ActionListener() { @@ -2688,7 +2720,7 @@ public class Editor extends JFrame implements RunnerListener { handleCommentUncomment(); } }); - this.add(item); + add(item); item = new JMenuItem("Increase Indent"); item.addActionListener(new ActionListener() { @@ -2696,7 +2728,7 @@ public class Editor extends JFrame implements RunnerListener { handleIndentOutdent(true); } }); - this.add(item); + add(item); item = new JMenuItem("Decrease Indent"); item.addActionListener(new ActionListener() { @@ -2704,9 +2736,9 @@ public class Editor extends JFrame implements RunnerListener { handleIndentOutdent(false); } }); - this.add(item); + add(item); - this.addSeparator(); + addSeparator(); referenceItem = new JMenuItem("Find in Reference"); referenceItem.addActionListener(new ActionListener() { @@ -2714,11 +2746,23 @@ public class Editor extends JFrame implements RunnerListener { handleFindReference(); } }); - this.add(referenceItem); + add(referenceItem); } // if no text is selected, disable copy and cut menu items public void show(Component component, int x, int y) { + int lineNo = textarea.getLineOfOffset(textarea.xyToOffset(x, y)); + int offset = textarea.xToOffset(lineNo, x); + String line = textarea.getLineText(lineNo); + clickedURL = textarea.checkClickedURL(line, offset); + if (clickedURL != null) { + openURLItem.setVisible(true); + openURLItemSeparator.setVisible(true); + } else { + openURLItem.setVisible(false); + openURLItemSeparator.setVisible(false); + } + if (textarea.isSelectionActive()) { cutItem.setEnabled(true); copyItem.setEnabled(true); diff --git a/app/src/processing/app/EditorLineStatus.java b/app/src/processing/app/EditorLineStatus.java index f28175ff0..2fcb8c917 100644 --- a/app/src/processing/app/EditorLineStatus.java +++ b/app/src/processing/app/EditorLineStatus.java @@ -25,6 +25,9 @@ package processing.app; import processing.app.syntax.*; import java.awt.*; +import java.awt.geom.Rectangle2D; +import java.util.Map; + import javax.swing.*; @@ -39,10 +42,14 @@ public class EditorLineStatus extends JComponent { Color foreground; Color background; + Color messageForeground; + Font font; int high; String text = ""; + String name = ""; + String serialport = ""; public EditorLineStatus(JEditTextArea textarea) { @@ -87,6 +94,11 @@ public class EditorLineStatus extends JComponent { public void paintComponent(Graphics g) { + if (name=="" && serialport=="") { + Map boardPreferences = Base.getBoardPreferences(); + setBoardName(boardPreferences.get("name")); + setSerialPort(Preferences.get("serial.port")); + } g.setColor(background); Dimension size = getSize(); g.fillRect(0, 0, size.width, size.height); @@ -96,11 +108,20 @@ public class EditorLineStatus extends JComponent { int baseline = (high + g.getFontMetrics().getAscent()) / 2; g.drawString(text, 6, baseline); + g.setColor(messageForeground); + String tmp = name + " on " + serialport; + + Rectangle2D bounds = g.getFontMetrics().getStringBounds(tmp, null); + + g.drawString(tmp, size.width - (int) bounds.getWidth() -20 , baseline); + if (Base.isMacOS()) { g.drawImage(resize, size.width - 20, 0, this); } } + public void setBoardName(String name) { this.name = name; } + public void setSerialPort(String serialport) { this.serialport = serialport; } public Dimension getPreferredSize() { return new Dimension(300, high); diff --git a/app/src/processing/app/EditorStatus.java b/app/src/processing/app/EditorStatus.java index a7035ab7c..a335b9230 100644 --- a/app/src/processing/app/EditorStatus.java +++ b/app/src/processing/app/EditorStatus.java @@ -40,6 +40,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { //static final int PROMPT = 2; //static final int EDIT = 3; static final int EDIT = 2; + static final int PROGRESS = 5; static final int YES = 1; static final int NO = 2; @@ -66,6 +67,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { JButton cancelButton; JButton okButton; JTextField editField; + JProgressBar progressBar; //Thread promptThread; int response; @@ -76,16 +78,22 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { empty(); if (bgcolor == null) { - bgcolor = new Color[3]; //4]; + bgcolor = new Color[6]; bgcolor[0] = Theme.getColor("status.notice.bgcolor"); bgcolor[1] = Theme.getColor("status.error.bgcolor"); bgcolor[2] = Theme.getColor("status.edit.bgcolor"); + bgcolor[3] = null; + bgcolor[4] = null; + bgcolor[5] = Theme.getColor("status.notice.bgcolor"); - fgcolor = new Color[3]; //4]; + fgcolor = new Color[6]; fgcolor[0] = Theme.getColor("status.notice.fgcolor"); fgcolor[1] = Theme.getColor("status.error.fgcolor"); fgcolor[2] = Theme.getColor("status.edit.fgcolor"); - } + fgcolor[3] = null; + fgcolor[4] = null; + fgcolor[5] = Theme.getColor("status.notice.fgcolor"); +} } @@ -163,6 +171,54 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { empty(); } + public void progress(String message) + { + mode = PROGRESS; + this.message = message; + progressBar.setIndeterminate(false); + progressBar.setVisible(true); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + repaint(); + } + + + public void progressIndeterminate(String message) + { + mode = PROGRESS; + this.message = message; + progressBar.setIndeterminate(true); + progressBar.setValue(50); + progressBar.setVisible(true); + setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + repaint(); + } + + + public void progressNotice(String message) { + //mode = NOTICE; + this.message = message; + //update(); + repaint(); + } + + + public void unprogress() + { + if (Preferences.getBoolean("editor.beep.compile")) { + Toolkit.getDefaultToolkit().beep(); + } + progressBar.setVisible(false); + progressBar.setValue(0); + setCursor(null); + //empty(); + } + + + public void progressUpdate(int value) + { + progressBar.setValue(value); + repaint(); + } /* public void update() { @@ -369,6 +425,19 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { }); add(editField); editField.setVisible(false); + + progressBar = new JProgressBar(JScrollBar.HORIZONTAL); + progressBar.setIndeterminate(false); + if (Base.isMacOS()) { + //progressBar.setBackground(bgcolor[PROGRESS]); + //progressBar.putClientProperty("JProgressBar.style", "circular"); + } + progressBar.setValue(0); + progressBar.setBorderPainted(true); + //progressBar.setStringPainted(true); + add(progressBar); + progressBar.setVisible(false); + } } @@ -385,11 +454,13 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { //noButton.setLocation(noLeft, top); cancelButton.setLocation(cancelLeft, top); okButton.setLocation(noLeft, top); + progressBar.setLocation(noLeft, top); //yesButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT); //noButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT); cancelButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT); okButton.setSize(Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT); + progressBar.setSize(2*Preferences.BUTTON_WIDTH, Preferences.BUTTON_HEIGHT); // edit field height is awkward, and very different between mac and pc, // so use at least the preferred height for now. @@ -398,6 +469,7 @@ public class EditorStatus extends JPanel /*implements ActionListener*/ { int editTop = (1 + sizeH - editHeight) / 2; // add 1 for ceil editField.setBounds(yesLeft - Preferences.BUTTON_WIDTH, editTop, editWidth, editHeight); + progressBar.setBounds(noLeft, editTop, editWidth, editHeight); } diff --git a/app/src/processing/app/EditorToolbar.java b/app/src/processing/app/EditorToolbar.java index 9d7a5fc13..6b04aa2d9 100644 --- a/app/src/processing/app/EditorToolbar.java +++ b/app/src/processing/app/EditorToolbar.java @@ -170,6 +170,10 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key x2[i] = x1[i] + BUTTON_WIDTH; offsetX = x2[i]; } + + // Serial button must be on the right + x1[SERIAL] = width - BUTTON_WIDTH - 14; + x2[SERIAL] = width - 14; } Graphics g = offscreen.getGraphics(); g.setColor(bgcolor); //getBackground()); @@ -194,9 +198,15 @@ public class EditorToolbar extends JComponent implements MouseInputListener, Key g2.drawString(status, statusX, statusY); */ if (currentRollover != -1) { - int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2; + int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2; String status = shiftPressed ? titleShift[currentRollover] : title[currentRollover]; - g.drawString(status, buttonCount * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY); + if (currentRollover != SERIAL) + g.drawString(status, (buttonCount-1) * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY); + else { + int statusX = x1[SERIAL] - BUTTON_GAP; + statusX -= g.getFontMetrics().stringWidth(status); + g.drawString(status, statusX, statusY); + } } screen.drawImage(offscreen, 0, 0, null); diff --git a/app/src/processing/app/Preferences.java b/app/src/processing/app/Preferences.java index 4dd15c041..315620033 100644 --- a/app/src/processing/app/Preferences.java +++ b/app/src/processing/app/Preferences.java @@ -772,8 +772,9 @@ public class Preferences { s = st.nextToken(); boolean bold = (s.indexOf("bold") != -1); boolean italic = (s.indexOf("italic") != -1); + boolean underlined = (s.indexOf("underlined") != -1); //System.out.println(what + " = " + str + " " + bold + " " + italic); - return new SyntaxStyle(color, italic, bold); + return new SyntaxStyle(color, italic, bold, underlined); } } diff --git a/app/src/processing/app/Sketch.java b/app/src/processing/app/Sketch.java index 22e2aa591..93b8e40dc 100644 --- a/app/src/processing/app/Sketch.java +++ b/app/src/processing/app/Sketch.java @@ -1507,6 +1507,7 @@ public class Sketch { throws RunnerException { // run the preprocessor + editor.status.progressUpdate(20); String primaryClassName = preprocess(buildPath); // compile the program. errors will happen as a RunnerException @@ -1552,6 +1553,7 @@ public class Sketch { appletFolder.mkdirs(); // build the sketch + editor.status.progressNotice("Compiling sketch..."); String foundName = build(appletFolder.getPath(), false); // (already reported) error during export, exit this function if (foundName == null) return false; @@ -1565,12 +1567,18 @@ public class Sketch { // return false; // } + editor.status.progressNotice("Uploading..."); upload(appletFolder.getPath(), foundName, usingProgrammer); - + editor.status.progressUpdate(100); return true; } + + public void setCompilingProgress(int percent) { + editor.status.progressUpdate(percent); + } + protected void size(String buildPath, String suggestedClassName) throws RunnerException { long size = 0; diff --git a/app/src/processing/app/Theme.java b/app/src/processing/app/Theme.java index 8b68f4f45..373b56835 100644 --- a/app/src/processing/app/Theme.java +++ b/app/src/processing/app/Theme.java @@ -196,7 +196,8 @@ public class Theme { s = st.nextToken(); boolean bold = (s.indexOf("bold") != -1); boolean italic = (s.indexOf("italic") != -1); + boolean underlined = (s.indexOf("underlined") != -1); - return new SyntaxStyle(color, italic, bold); + return new SyntaxStyle(color, italic, bold, underlined); } } \ No newline at end of file diff --git a/app/src/processing/app/debug/Compiler.java b/app/src/processing/app/debug/Compiler.java index bf972b8ea..559df3a61 100644 --- a/app/src/processing/app/debug/Compiler.java +++ b/app/src/processing/app/debug/Compiler.java @@ -91,19 +91,19 @@ public class Compiler implements MessageConsumer { corePath = coreFolder.getAbsolutePath(); } - String pins = boardPreferences.get("build.pins"); - String pinsPath = null; + String variant = boardPreferences.get("build.variant"); + String variantPath = null; - if (pins != null) { - if (pins.indexOf(':') == -1) { + if (variant != null) { + if (variant.indexOf(':') == -1) { Target t = Base.getTarget(); - File pinsFolder = new File(new File(t.getFolder(), "pins"), pins); - pinsPath = pinsFolder.getAbsolutePath(); + File variantFolder = new File(new File(t.getFolder(), "variants"), variant); + variantPath = variantFolder.getAbsolutePath(); } else { - Target t = Base.targetsTable.get(pins.substring(0, pins.indexOf(':'))); - File pinsFolder = new File(t.getFolder(), "pins"); - pinsFolder = new File(pinsFolder, pins.substring(pins.indexOf(':') + 1)); - pinsPath = pinsFolder.getAbsolutePath(); + Target t = Base.targetsTable.get(variant.substring(0, variant.indexOf(':'))); + File variantFolder = new File(t.getFolder(), "variants"); + variantFolder = new File(variantFolder, variant.substring(variant.indexOf(':') + 1)); + variantPath = variantFolder.getAbsolutePath(); } } @@ -111,15 +111,17 @@ public class Compiler implements MessageConsumer { // 0. include paths for core + all libraries + sketch.setCompilingProgress(20); List includePaths = new ArrayList(); includePaths.add(corePath); - if (pinsPath != null) includePaths.add(pinsPath); + if (variantPath != null) includePaths.add(variantPath); for (File file : sketch.getImportedLibraries()) { includePaths.add(file.getPath()); } // 1. compile the sketch (already in the buildPath) + sketch.setCompilingProgress(30); objectFiles.addAll( compileFiles(avrBasePath, buildPath, includePaths, findFilesInPath(buildPath, "S", false), @@ -129,6 +131,7 @@ public class Compiler implements MessageConsumer { // 2. compile the libraries, outputting .o files to: // + sketch.setCompilingProgress(40); for (File libraryFolder : sketch.getImportedLibraries()) { File outputFolder = new File(buildPath, libraryFolder.getName()); File utilityFolder = new File(libraryFolder, "utility"); @@ -156,9 +159,10 @@ public class Compiler implements MessageConsumer { // 3. compile the core, outputting .o files to and then // collecting them into the core.a library file. + sketch.setCompilingProgress(50); includePaths.clear(); includePaths.add(corePath); // include path for core only - if (pinsPath != null) includePaths.add(pinsPath); + if (variantPath != null) includePaths.add(variantPath); List coreObjectFiles = compileFiles(avrBasePath, buildPath, includePaths, findFilesInPath(corePath, "S", true), @@ -180,6 +184,7 @@ public class Compiler implements MessageConsumer { // 4. link it all together into the .elf file + sketch.setCompilingProgress(60); List baseCommandLinker = new ArrayList(Arrays.asList(new String[] { avrBasePath + "avr-gcc", "-Os", @@ -208,6 +213,7 @@ public class Compiler implements MessageConsumer { List commandObjcopy; // 5. extract EEPROM data (from EEMEM directive) to .eep file. + sketch.setCompilingProgress(70); commandObjcopy = new ArrayList(baseCommandObjcopy); commandObjcopy.add(2, "ihex"); commandObjcopy.set(3, "-j"); @@ -221,6 +227,7 @@ public class Compiler implements MessageConsumer { execAsynchronously(commandObjcopy); // 6. build the .hex file + sketch.setCompilingProgress(80); commandObjcopy = new ArrayList(baseCommandObjcopy); commandObjcopy.add(2, "ihex"); commandObjcopy.add(".eeprom"); // remove eeprom data @@ -228,6 +235,8 @@ public class Compiler implements MessageConsumer { commandObjcopy.add(buildPath + File.separator + primaryClassName + ".hex"); execAsynchronously(commandObjcopy); + sketch.setCompilingProgress(90); + return true; } diff --git a/app/src/processing/app/syntax/JEditTextArea.java b/app/src/processing/app/syntax/JEditTextArea.java index d5c01c48a..3c1548fbd 100644 --- a/app/src/processing/app/syntax/JEditTextArea.java +++ b/app/src/processing/app/syntax/JEditTextArea.java @@ -2045,6 +2045,17 @@ public class JEditTextArea extends JComponent } } + public String checkClickedURL(String line, int offset) { + String[] parse = SyntaxUtilities.parseCommentUrls(line); + if (parse==null) + return null; + int start = parse[0].length(); + int stop = start + parse[1].length(); + if (offsetstop) + return null; + return parse[1]; + } + class MouseHandler extends MouseAdapter { public void mousePressed(MouseEvent evt) @@ -2095,6 +2106,13 @@ public class JEditTextArea extends JComponent private void doSingleClick(MouseEvent evt, int line, int offset, int dot) { + // Check for click on urls + String clickedURL = checkClickedURL(getLineText(line), offset); + if (clickedURL != null) { + Base.openURL(clickedURL); + return; + } + if ((evt.getModifiers() & InputEvent.SHIFT_MASK) != 0) { rectSelect = (evt.getModifiers() & InputEvent.CTRL_MASK) != 0; select(getMarkPosition(),dot); diff --git a/app/src/processing/app/syntax/PdeTextAreaDefaults.java b/app/src/processing/app/syntax/PdeTextAreaDefaults.java index b715255be..382c69aaf 100644 --- a/app/src/processing/app/syntax/PdeTextAreaDefaults.java +++ b/app/src/processing/app/syntax/PdeTextAreaDefaults.java @@ -169,6 +169,9 @@ public class PdeTextAreaDefaults extends TextAreaDefaults { // ?? styles[Token.LABEL] = Theme.getStyle("label"); + // http://arduino.cc/ + styles[Token.URL] = Theme.getStyle("url"); + // + - = / styles[Token.OPERATOR] = Theme.getStyle("operator"); diff --git a/app/src/processing/app/syntax/SyntaxStyle.java b/app/src/processing/app/syntax/SyntaxStyle.java index 56323c3cc..ac3dd797d 100644 --- a/app/src/processing/app/syntax/SyntaxStyle.java +++ b/app/src/processing/app/syntax/SyntaxStyle.java @@ -10,6 +10,10 @@ package processing.app.syntax; import java.awt.*; +import java.awt.font.TextAttribute; +import java.util.Hashtable; +import java.util.Map; + import javax.swing.JComponent; @@ -27,11 +31,12 @@ public class SyntaxStyle * @param italic True if the text should be italics * @param bold True if the text should be bold */ - public SyntaxStyle(Color color, boolean italic, boolean bold) + public SyntaxStyle(Color color, boolean italic, boolean bold, boolean underlined) { this.color = color; this.italic = italic; this.bold = bold; + this.underlined = underlined; } /** @@ -47,7 +52,7 @@ public class SyntaxStyle */ public boolean isPlain() { - return !(bold || italic); + return !(bold || italic || underlined); } /** @@ -67,7 +72,14 @@ public class SyntaxStyle } /** - * Returns the specified font, but with the style's bold and + * @return true if underline is enabled for this style. + */ + public boolean isUnderlined() { + return underlined; + } + + /** + * Returns the specified font, but with the style's bold, underline and * italic flags applied. */ public Font getStyledFont(Font font) @@ -78,10 +90,16 @@ public class SyntaxStyle if(font.equals(lastFont)) return lastStyledFont; lastFont = font; + lastStyledFont = new Font(font.getFamily(), (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0), font.getSize()); + if (underlined) { + Map attr = new Hashtable(); + attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + lastStyledFont = lastStyledFont.deriveFont(attr); + } return lastStyledFont; } @@ -100,6 +118,11 @@ public class SyntaxStyle (bold ? Font.BOLD : 0) | (italic ? Font.ITALIC : 0), font.getSize()); + if (underlined) { + Map attr = new Hashtable(); + attr.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + lastStyledFont = lastStyledFont.deriveFont(attr); + } //fontMetrics = Toolkit.getDefaultToolkit().getFontMetrics(lastStyledFont); fontMetrics = comp.getFontMetrics(lastStyledFont); return fontMetrics; @@ -125,13 +148,16 @@ public class SyntaxStyle { return getClass().getName() + "[color=" + color + (italic ? ",italic" : "") + - (bold ? ",bold" : "") + "]"; + (bold ? ",bold" : "") + + (underlined ? ",underlined" : "") + + "]"; } // private members private Color color; private boolean italic; private boolean bold; + private boolean underlined; private Font lastFont; private Font lastStyledFont; private FontMetrics fontMetrics; diff --git a/app/src/processing/app/syntax/SyntaxUtilities.java b/app/src/processing/app/syntax/SyntaxUtilities.java index 5225d0b73..1e3c6c900 100644 --- a/app/src/processing/app/syntax/SyntaxUtilities.java +++ b/app/src/processing/app/syntax/SyntaxUtilities.java @@ -11,6 +11,8 @@ package processing.app.syntax; import javax.swing.text.*; import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** @@ -93,16 +95,17 @@ public class SyntaxUtilities { SyntaxStyle[] styles = new SyntaxStyle[Token.ID_COUNT]; - styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false); - styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false); - styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true); - styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false); - styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false); - styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false); - styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true); - styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true); - styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true); - styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true); + styles[Token.COMMENT1] = new SyntaxStyle(Color.black,true,false,false); + styles[Token.COMMENT2] = new SyntaxStyle(new Color(0x990033),true,false,false); + styles[Token.KEYWORD1] = new SyntaxStyle(Color.black,false,true,false); + styles[Token.KEYWORD2] = new SyntaxStyle(Color.magenta,false,false,false); + styles[Token.KEYWORD3] = new SyntaxStyle(new Color(0x009600),false,false,false); + styles[Token.LITERAL1] = new SyntaxStyle(new Color(0x650099),false,false,false); + styles[Token.LITERAL2] = new SyntaxStyle(new Color(0x650099),false,true,false); + styles[Token.LABEL] = new SyntaxStyle(new Color(0x990033),false,true,false); + styles[Token.OPERATOR] = new SyntaxStyle(Color.black,false,true,false); + styles[Token.URL] = new SyntaxStyle(Color.blue,true,false,false); + styles[Token.INVALID] = new SyntaxStyle(Color.red,false,true,false); return styles; } @@ -148,7 +151,10 @@ public class SyntaxUtilities styles[id].setGraphicsFlags(gfx,defaultFont); line.count = length; - x = Utilities.drawTabbedText(line,x,y,gfx,expander,0); + if (id == Token.COMMENT1 || id == Token.COMMENT2) + x = drawTabbedCommentsText(line, x, y, gfx, expander, styles, styles[id]); + else + x = Utilities.drawTabbedText(line, x, y, gfx, expander, 0); line.offset += length; offset += length; @@ -158,6 +164,66 @@ public class SyntaxUtilities return x; } + /** + * Parse comments and identify "@schematics <something>" pattern. + * + * @param line + * A string to parse + * @return null if the pattern is not found, otherwise an array of + * String is returned: the elements with index 0, 1 and 2 are + * respectively the preamble, the <something> stuff, and + * the remaining part of the string. + */ + public static String[] parseCommentUrls(String line) { + Matcher m = urlPattern.matcher(line.toString()); + if (!m.find()) + return null; + + String res[] = new String[3]; + res[0] = line.substring(0, m.start(1)); + res[1] = line.substring(m.start(1), m.end(1)); + res[2] = line.substring(m.end(1)); + // System.out.println("0 =>"+res[0]+"<\n1 =>"+res[1]+"< \n2 =>"+res[2]+"<"); + return res; + } + + static private Pattern urlPattern = Pattern.compile( + "((?:https?|ftp)://" + // ( Protocol + "(?:(?:[\\w_\\-]+:)?[\\w_\\-]+@)?" + // Username and password + "(?:[\\w_\\-]+\\.)+[\\w_\\-]+" + // Domain name + "(?::[0-9]{1,5})?" + // Port + "(?:/[\\w_\\-./?%&=+]*)?)" + // Path ) + "(?:\\s|$)"); // whitespace or EOL + + public static Segment stringToSegment(String v) { + return new Segment(v.toCharArray(), 0, v.length()); + } + + private static int drawTabbedCommentsText(Segment line, int x, int y, + Graphics gfx, TabExpander expander, SyntaxStyle[] styles, + SyntaxStyle commentStyle) { + + String parse[] = parseCommentUrls(line.toString()); + if (parse == null) + // Revert to plain writing. + return Utilities.drawTabbedText(line, x, y, gfx, expander, 0); + Segment pre = stringToSegment(parse[0]); + Segment tag = stringToSegment(parse[1]); + Segment post = stringToSegment(parse[2]); + + if (pre.count>0) + x = Utilities.drawTabbedText(pre, x, y, gfx, expander, 0); + + Font f = gfx.getFont(); + styles[Token.URL].setGraphicsFlags(gfx, f); + x = Utilities.drawTabbedText(tag, x, y, gfx, expander, 0); + + commentStyle.setGraphicsFlags(gfx, f); + if (post.count>0) + x = Utilities.drawTabbedText(post, x, y, gfx, expander, 0); + return x; + } + // private members private SyntaxUtilities() {} } diff --git a/app/src/processing/app/syntax/Token.java b/app/src/processing/app/syntax/Token.java index a0f73bebf..06dc26323 100644 --- a/app/src/processing/app/syntax/Token.java +++ b/app/src/processing/app/syntax/Token.java @@ -83,17 +83,22 @@ public class Token */ public static final byte OPERATOR = 9; + /** + * URL token id. + */ + public static final byte URL = 10; + /** * Invalid token id. This can be used to mark invalid * or incomplete tokens, so the user can easily spot * syntax errors. */ - public static final byte INVALID = 10; + public static final byte INVALID = 11; /** * The total number of defined token ids. */ - public static final byte ID_COUNT = 11; + public static final byte ID_COUNT = 12; /** * The first id that can be used for internal state diff --git a/build/macosx/template.app/Contents/Info.plist b/build/macosx/template.app/Contents/Info.plist index 45809f544..2233d7278 100755 --- a/build/macosx/template.app/Contents/Info.plist +++ b/build/macosx/template.app/Contents/Info.plist @@ -7,11 +7,11 @@ CFBundleGetInfoString - 1.0-beta1 + 1.0-beta2 CFBundleVersion 0100 CFBundleShortVersionString - 1.0-beta1 + 1.0-beta2 CFBundleAllowMixedLocalizations diff --git a/build/shared/lib/keywords.txt b/build/shared/lib/keywords.txt index 8859d3b84..730de4e75 100644 --- a/build/shared/lib/keywords.txt +++ b/build/shared/lib/keywords.txt @@ -172,6 +172,13 @@ print KEYWORD2 Serial_Print println KEYWORD2 Serial_Println available KEYWORD2 Serial_Available flush KEYWORD2 Serial_Flush +setTimeout KEYWORD2 +find KEYWORD2 +findUntil KEYWORD2 +parseInt KEYWORD2 +parseFloat KEYWORD2 +readBytes KEYWORD2 +readBytesUntil KEYWORD2 setup KEYWORD3 Setup loop KEYWORD3 Loop diff --git a/build/shared/lib/theme/theme.txt b/build/shared/lib/theme/theme.txt index a0889e64a..d8f5b7aa4 100644 --- a/build/shared/lib/theme/theme.txt +++ b/build/shared/lib/theme/theme.txt @@ -83,6 +83,9 @@ editor.literal1.style = #006699,plain # p5 built in variables: e.g. mouseX, width, pixels editor.literal2.style = #006699,plain +# http://arduino.cc/ +editor.url.style = #0000ff,underlined + # e.g. + - = / editor.operator.style = #000000,plain diff --git a/hardware/arduino/boards.txt b/hardware/arduino/boards.txt index 88a71433d..7adac6233 100644 --- a/hardware/arduino/boards.txt +++ b/hardware/arduino/boards.txt @@ -14,11 +14,11 @@ uno.bootloader.lock_bits=0x0F uno.build.mcu=atmega328p uno.build.f_cpu=16000000L uno.build.core=arduino -uno.build.pins=standard +uno.build.variant=standard ############################################################## -atmega328.name=Arduino Duemilanove or Nano w/ ATmega328 +atmega328.name=Arduino Duemilanove w/ ATmega328 atmega328.upload.protocol=stk500 atmega328.upload.maximum_size=30720 @@ -35,11 +35,11 @@ atmega328.bootloader.lock_bits=0x0F atmega328.build.mcu=atmega328p atmega328.build.f_cpu=16000000L atmega328.build.core=arduino -atmega328.build.pins=standard +atmega328.build.variant=standard ############################################################## -diecimila.name=Arduino Diecimila, Duemilanove, or Nano w/ ATmega168 +diecimila.name=Arduino Diecimila or Duemilanove w/ ATmega168 diecimila.upload.protocol=stk500 diecimila.upload.maximum_size=14336 @@ -56,7 +56,49 @@ diecimila.bootloader.lock_bits=0x0F diecimila.build.mcu=atmega168 diecimila.build.f_cpu=16000000L diecimila.build.core=arduino -diecimila.build.pins=standard +diecimila.build.variant=standard + +############################################################## + +nano328.name=Arduino Nano w/ ATmega328 + +nano328.upload.protocol=stk500 +nano328.upload.maximum_size=30720 +nano328.upload.speed=57600 + +nano328.bootloader.low_fuses=0xFF +nano328.bootloader.high_fuses=0xDA +nano328.bootloader.extended_fuses=0x05 +nano328.bootloader.path=atmega +nano328.bootloader.file=ATmegaBOOT_168_atmega328.hex +nano328.bootloader.unlock_bits=0x3F +nano328.bootloader.lock_bits=0x0F + +nano328.build.mcu=atmega328p +nano328.build.f_cpu=16000000L +nano328.build.core=arduino +nano328.build.variant=eightanaloginputs + +############################################################## + +nano.name=Arduino Nano w/ ATmega168 + +nano.upload.protocol=stk500 +nano.upload.maximum_size=14336 +nano.upload.speed=19200 + +nano.bootloader.low_fuses=0xff +nano.bootloader.high_fuses=0xdd +nano.bootloader.extended_fuses=0x00 +nano.bootloader.path=atmega +nano.bootloader.file=ATmegaBOOT_168_diecimila.hex +nano.bootloader.unlock_bits=0x3F +nano.bootloader.lock_bits=0x0F + +nano.build.mcu=atmega168 +nano.build.f_cpu=16000000L +nano.build.core=arduino +nano.build.variant=eightanaloginputs ############################################################## @@ -77,7 +119,7 @@ mega2560.bootloader.lock_bits=0x0F mega2560.build.mcu=atmega2560 mega2560.build.f_cpu=16000000L mega2560.build.core=arduino -mega2560.build.pins=mega +mega2560.build.variant=mega ############################################################## @@ -98,7 +140,7 @@ mega.bootloader.lock_bits=0x0F mega.build.mcu=atmega1280 mega.build.f_cpu=16000000L mega.build.core=arduino -mega.build.pins=mega +mega.build.variant=mega ############################################################## @@ -119,7 +161,7 @@ mini.bootloader.lock_bits=0x0F mini.build.mcu=atmega168 mini.build.f_cpu=16000000L mini.build.core=arduino -mini.build.pins=standard +mini.build.variant=eightanaloginputs ############################################################## @@ -140,7 +182,7 @@ fio.bootloader.lock_bits=0x0F fio.build.mcu=atmega328p fio.build.f_cpu=8000000L fio.build.core=arduino -fio.build.pins=standard +fio.build.variant=eightanaloginputs ############################################################## @@ -162,7 +204,7 @@ bt328.bootloader.lock_bits=0x0F bt328.build.mcu=atmega328p bt328.build.f_cpu=16000000L bt328.build.core=arduino -bt328.build.pins=standard +bt328.build.variant=eightanaloginputs ############################################################## @@ -184,7 +226,7 @@ bt.bootloader.lock_bits=0x0F bt.build.mcu=atmega168 bt.build.f_cpu=16000000L bt.build.core=arduino -bt.build.pins=standard +bt.build.variant=eightanaloginputs ############################################################## @@ -205,7 +247,7 @@ lilypad328.bootloader.lock_bits=0x0F lilypad328.build.mcu=atmega328p lilypad328.build.f_cpu=8000000L lilypad328.build.core=arduino -lilypad328.build.pins=standard +lilypad328.build.variant=standard ############################################################## @@ -226,7 +268,7 @@ lilypad.bootloader.lock_bits=0x0F lilypad.build.mcu=atmega168 lilypad.build.f_cpu=8000000L lilypad.build.core=arduino -lilypad.build.pins=standard +lilypad.build.variant=standard ############################################################## @@ -247,7 +289,7 @@ pro5v328.bootloader.lock_bits=0x0F pro5v328.build.mcu=atmega328p pro5v328.build.f_cpu=16000000L pro5v328.build.core=arduino -pro5v328.build.pins=standard +pro5v328.build.variant=standard ############################################################## @@ -268,7 +310,7 @@ pro5v.bootloader.lock_bits=0x0F pro5v.build.mcu=atmega168 pro5v.build.f_cpu=16000000L pro5v.build.core=arduino -pro5v.build.pins=standard +pro5v.build.variant=standard ############################################################## @@ -289,7 +331,7 @@ pro328.bootloader.lock_bits=0x0F pro328.build.mcu=atmega328p pro328.build.f_cpu=8000000L pro328.build.core=arduino -pro328.build.pins=standard +pro328.build.variant=standard ############################################################## @@ -310,7 +352,7 @@ pro.bootloader.lock_bits=0x0F pro.build.mcu=atmega168 pro.build.f_cpu=8000000L pro.build.core=arduino -pro.build.pins=standard +pro.build.variant=standard ############################################################## @@ -331,7 +373,7 @@ atmega168.bootloader.lock_bits=0x0F atmega168.build.mcu=atmega168 atmega168.build.f_cpu=16000000L atmega168.build.core=arduino -atmega168.build.pins=standard +atmega168.build.variant=standard ############################################################## @@ -351,4 +393,4 @@ atmega8.bootloader.lock_bits=0x0F atmega8.build.mcu=atmega8 atmega8.build.f_cpu=16000000L atmega8.build.core=arduino -atmega8.build.pins=standard +atmega8.build.variant=standard diff --git a/hardware/arduino/cores/arduino/HardwareSerial.cpp b/hardware/arduino/cores/arduino/HardwareSerial.cpp index db6b1490b..d6be2181c 100644 --- a/hardware/arduino/cores/arduino/HardwareSerial.cpp +++ b/hardware/arduino/cores/arduino/HardwareSerial.cpp @@ -352,12 +352,13 @@ void HardwareSerial::flush() ; } -void HardwareSerial::write(uint8_t c) +size_t HardwareSerial::write(uint8_t c) { int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit + // ???: return 0 here instead? while (i == _tx_buffer->tail) ; @@ -365,6 +366,8 @@ void HardwareSerial::write(uint8_t c) _tx_buffer->head = i; sbi(*_ucsrb, _udrie); + + return 1; } // Preinstantiate Objects ////////////////////////////////////////////////////// diff --git a/hardware/arduino/cores/arduino/HardwareSerial.h b/hardware/arduino/cores/arduino/HardwareSerial.h index eefdcbe16..1895f08f6 100644 --- a/hardware/arduino/cores/arduino/HardwareSerial.h +++ b/hardware/arduino/cores/arduino/HardwareSerial.h @@ -55,7 +55,7 @@ class HardwareSerial : public Stream virtual int peek(void); virtual int read(void); virtual void flush(void); - virtual void write(uint8_t); + virtual size_t write(uint8_t); using Print::write; // pull in write(str) and write(buf, size) from Print }; diff --git a/hardware/arduino/cores/arduino/Print.cpp b/hardware/arduino/cores/arduino/Print.cpp index 06ac52a5e..8190d4fb4 100755 --- a/hardware/arduino/cores/arduino/Print.cpp +++ b/hardware/arduino/cores/arduino/Print.cpp @@ -30,167 +30,190 @@ // Public Methods ////////////////////////////////////////////////////////////// /* default implementation: may be overridden */ -void Print::write(const char *str) +size_t Print::write(const char *str) { - while (*str) - write(*str++); + size_t n = 0; + while (*str) { + n += write(*str++); + } + return n; } /* default implementation: may be overridden */ -void Print::write(const uint8_t *buffer, size_t size) +size_t Print::write(const uint8_t *buffer, size_t size) { - while (size--) - write(*buffer++); + size_t n = 0; + while (size--) { + n += write(*buffer++); + } + return n; } -void Print::print(const __FlashStringHelper *ifsh) +size_t Print::print(const __FlashStringHelper *ifsh) { const prog_char *p = (const prog_char *)ifsh; + size_t n = 0; while (1) { unsigned char c = pgm_read_byte(p++); - if (c == 0) return; - write(c); + if (c == 0) break; + n += write(c); } + return n; } -void Print::print(const String &s) +size_t Print::print(const String &s) { + size_t n = 0; for (int i = 0; i < s.length(); i++) { - write(s[i]); + n += write(s[i]); } + return n; } -void Print::print(const char str[]) +size_t Print::print(const char str[]) { - write(str); + return write(str); } -void Print::print(char c) +size_t Print::print(char c) { - write(c); + return write(c); } -void Print::print(unsigned char b, int base) +size_t Print::print(unsigned char b, int base) { - print((unsigned long) b, base); + return print((unsigned long) b, base); } -void Print::print(int n, int base) +size_t Print::print(int n, int base) { - print((long) n, base); + return print((long) n, base); } -void Print::print(unsigned int n, int base) +size_t Print::print(unsigned int n, int base) { - print((unsigned long) n, base); + return print((unsigned long) n, base); } -void Print::print(long n, int base) +size_t Print::print(long n, int base) { if (base == 0) { - write(n); + return write(n); } else if (base == 10) { if (n < 0) { - print('-'); + int t = print('-'); n = -n; + return printNumber(n, 10) + t; } - printNumber(n, 10); + return printNumber(n, 10); } else { - printNumber(n, base); + return printNumber(n, base); } } -void Print::print(unsigned long n, int base) +size_t Print::print(unsigned long n, int base) { - if (base == 0) write(n); - else printNumber(n, base); + if (base == 0) return write(n); + else return printNumber(n, base); } -void Print::print(double n, int digits) +size_t Print::print(double n, int digits) { - printFloat(n, digits); + return printFloat(n, digits); } -void Print::println(const __FlashStringHelper *ifsh) +size_t Print::println(const __FlashStringHelper *ifsh) { - print(ifsh); - println(); + size_t n = print(ifsh); + n += println(); + return n; } -void Print::print(const Printable& x) +size_t Print::print(const Printable& x) { - x.printTo(*this); + return x.printTo(*this); } -void Print::println(void) +size_t Print::println(void) { - print('\r'); - print('\n'); + size_t n = print('\r'); + n += print('\n'); + return n; } -void Print::println(const String &s) +size_t Print::println(const String &s) { - print(s); - println(); + size_t n = print(s); + n += println(); + return n; } -void Print::println(const char c[]) +size_t Print::println(const char c[]) { - print(c); - println(); + size_t n = print(c); + n += println(); + return n; } -void Print::println(char c) +size_t Print::println(char c) { - print(c); - println(); + size_t n = print(c); + n += println(); + return n; } -void Print::println(unsigned char b, int base) +size_t Print::println(unsigned char b, int base) { - print(b, base); - println(); + size_t n = print(b, base); + n += println(); + return n; } -void Print::println(int n, int base) +size_t Print::println(int num, int base) { - print(n, base); - println(); + size_t n = print(num, base); + n += println(); + return n; } -void Print::println(unsigned int n, int base) +size_t Print::println(unsigned int num, int base) { - print(n, base); - println(); + size_t n = print(num, base); + n += println(); + return n; } -void Print::println(long n, int base) +size_t Print::println(long num, int base) { - print(n, base); - println(); + size_t n = print(num, base); + n += println(); + return n; } -void Print::println(unsigned long n, int base) +size_t Print::println(unsigned long num, int base) { - print(n, base); - println(); + size_t n = print(num, base); + n += println(); + return n; } -void Print::println(double n, int digits) +size_t Print::println(double num, int digits) { - print(n, digits); - println(); + size_t n = print(num, digits); + n += println(); + return n; } -void Print::println(const Printable& x) +size_t Print::println(const Printable& x) { - print(x); - println(); + size_t n = print(x); + n += println(); + return n; } // Private Methods ///////////////////////////////////////////////////////////// -void Print::printNumber(unsigned long n, uint8_t base) { +size_t Print::printNumber(unsigned long n, uint8_t base) { char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. char *str = &buf[sizeof(buf) - 1]; @@ -206,15 +229,17 @@ void Print::printNumber(unsigned long n, uint8_t base) { *--str = c < 10 ? c + '0' : c + 'A' - 10; } while(n); - write(str); + return write(str); } -void Print::printFloat(double number, uint8_t digits) +size_t Print::printFloat(double number, uint8_t digits) { + size_t n = 0; + // Handle negative numbers if (number < 0.0) { - print('-'); + n += print('-'); number = -number; } @@ -228,18 +253,21 @@ void Print::printFloat(double number, uint8_t digits) // Extract the integer part of the number and print it unsigned long int_part = (unsigned long)number; double remainder = number - (double)int_part; - print(int_part); + n += print(int_part); // Print the decimal point, but only if there are digits beyond - if (digits > 0) - print("."); + if (digits > 0) { + n += print("."); + } // Extract digits from the remainder one at a time while (digits-- > 0) { remainder *= 10.0; int toPrint = int(remainder); - print(toPrint); + n += print(toPrint); remainder -= toPrint; } + + return n; } diff --git a/hardware/arduino/cores/arduino/Print.h b/hardware/arduino/cores/arduino/Print.h index bf10b1477..fce302e72 100755 --- a/hardware/arduino/cores/arduino/Print.h +++ b/hardware/arduino/cores/arduino/Print.h @@ -34,37 +34,45 @@ class Print { private: - void printNumber(unsigned long, uint8_t); - void printFloat(double, uint8_t); + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } public: - virtual void write(uint8_t) = 0; - virtual void write(const char *str); - virtual void write(const uint8_t *buffer, size_t size); + Print() : write_error(0) {} + + int writeError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + virtual size_t write(const char *str); + virtual size_t write(const uint8_t *buffer, size_t size); - void print(const __FlashStringHelper *); - void print(const String &); - void print(const char[]); - void print(char); - void print(unsigned char, int = DEC); - void print(int, int = DEC); - void print(unsigned int, int = DEC); - void print(long, int = DEC); - void print(unsigned long, int = DEC); - void print(double, int = 2); - void print(const Printable&); + size_t print(const __FlashStringHelper *); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); - void println(const __FlashStringHelper *); - void println(const String &s); - void println(const char[]); - void println(char); - void println(unsigned char, int = DEC); - void println(int, int = DEC); - void println(unsigned int, int = DEC); - void println(long, int = DEC); - void println(unsigned long, int = DEC); - void println(double, int = 2); - void println(const Printable&); - void println(void); + size_t println(const __FlashStringHelper *); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(void); }; #endif diff --git a/hardware/arduino/cores/arduino/Printable.h b/hardware/arduino/cores/arduino/Printable.h index 5ff607767..d03c9af62 100644 --- a/hardware/arduino/cores/arduino/Printable.h +++ b/hardware/arduino/cores/arduino/Printable.h @@ -33,8 +33,7 @@ class Print; class Printable { public: - virtual ~Printable() {}; - virtual void printTo(Print& p) const =0; + virtual size_t printTo(Print& p) const = 0; }; #endif diff --git a/hardware/arduino/cores/arduino/Stream.cpp b/hardware/arduino/cores/arduino/Stream.cpp new file mode 100644 index 000000000..d267bf0cb --- /dev/null +++ b/hardware/arduino/cores/arduino/Stream.cpp @@ -0,0 +1,233 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() +{ + //Serial.println(_timeout); + this->_startMillis = millis(); + while(millis() - this->_startMillis < this->_timeout) + { + if (this->available() > 0) { + return this->read(); + } + } + return -1; // -1 indicates timeout +} + +// returns the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::getNextDigit() +{ + int c; + do{ + c = timedRead(); + if( c < 0) + return c; // timeout + } + while( c != '-' && (c < '0' || c > '9') ) ; + +return c; +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout( long timeout) // sets the maximum number of milliseconds to wait +{ + this->_timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, NULL); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if( *target == 0) + return true; // return true if target is a null string + while( (c = timedRead()) > 0){ + if( c == target[index]){ + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen){ // return true if all chars in the target match + return true; + } + } + else{ + index = 0; // reset index if any char does not match + } + if(termLen > 0 && c == terminator[termIndex]){ + if(++termIndex >= termLen) + return false; // return false if terminate string found before target string + } + else + termIndex = 0; + } + return false; +} + + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() +{ + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) +{ + boolean isNegative = false; + long value = 0; + int c; + + c = getNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore this charactor + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + c = timedRead(); + } + while( (c >= '0' && c <= '9') || c == skipChar ); + + if(isNegative) + value = -value; + return value; +} + + +// as parseInt but returns a floating point value +float Stream::parseFloat() +{ + parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar){ + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + float fValue; + char c; + float fraction = 1.0; + + c = getNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + c = timedRead(); + } + while( (c >= '0' && c <= '9') || c == '.' || c == skipChar ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, null is detected or timeout (see setTimeout) +// returns the number of characters placed in the buffer (0 means no valid data found) +int Stream::readBytes( char *buffer, size_t length) +{ + return readBytesUntil( 0, buffer, length); +} + + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +int Stream::readBytesUntil( char terminator, char *buffer, size_t length) +{ + int index = 0; + *buffer = 0; + while(index < length-1 ){ + int c = timedRead(); + if( c <= 0 ){ + return 0; // timeout returns 0 ! + } + else if( c == terminator){ + buffer[index] = 0; // terminate the string + return index; // data got successfully + } + else{ + buffer[index++] = (char)c; + } + } + buffer[index] = 0; + return index; // here if buffer is full before detecting the terminator +} + diff --git a/hardware/arduino/cores/arduino/Stream.h b/hardware/arduino/cores/arduino/Stream.h index 93d8275dc..1633f15d5 100644 --- a/hardware/arduino/cores/arduino/Stream.h +++ b/hardware/arduino/cores/arduino/Stream.h @@ -15,6 +15,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis */ #ifndef Stream_h @@ -23,13 +25,69 @@ #include #include "Print.h" +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(skipChar) parseInt(skipchar) +#define getFloat() parseFloat() +#define getFloat(skipChar) parseFloat(skipChar) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + class Stream : public Print { + private: + long _timeout; // number of milliseconds to wait for the next char before aborting timed read + long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int getNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + public: virtual int available() = 0; virtual int read() = 0; virtual int peek() = 0; virtual void flush() = 0; + + Stream() {_timeout=1000;} + +// parsing methods + + void setTimeout(long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + + bool find(char *target); // reads data from the stream until the target string is found + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + // returns true if target string is found, false if timed out + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(); // float version of parseInt + + float parseFloat(char skipChar); // as above but the given skipChar is ignored + + int readBytes( char *buffer, size_t length); // read chars from stream into buffer + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + int readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + }; #endif diff --git a/hardware/arduino/variants/eightanaloginputs/pins_arduino.h b/hardware/arduino/variants/eightanaloginputs/pins_arduino.h new file mode 100644 index 000000000..52b37efc4 --- /dev/null +++ b/hardware/arduino/variants/eightanaloginputs/pins_arduino.h @@ -0,0 +1,27 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#include "../standard/pins_arduino.h" +#undef NUM_ANALOG_INPUTS +#define NUM_ANALOG_INPUTS 8 diff --git a/hardware/arduino/pins/mega/pins_arduino.h b/hardware/arduino/variants/mega/pins_arduino.h similarity index 84% rename from hardware/arduino/pins/mega/pins_arduino.h rename to hardware/arduino/variants/mega/pins_arduino.h index e3785e42f..237173adc 100644 --- a/hardware/arduino/pins/mega/pins_arduino.h +++ b/hardware/arduino/variants/mega/pins_arduino.h @@ -27,11 +27,20 @@ #include +#define NUM_DIGITAL_PINS 70 +#define NUM_ANALOG_INPUTS 16 +#define analogInputToDigitalPin(p) ((p < 16) ? (p) + 54 : -1) +#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 13) || ((p) >= 44 && (p)<= 46)) + const static uint8_t SS = 53; const static uint8_t MOSI = 51; const static uint8_t MISO = 50; const static uint8_t SCK = 52; +const static uint8_t SDA = 20; +const static uint8_t SCL = 21; +const static uint8_t LED = 13; + const static uint8_t A0 = 54; const static uint8_t A1 = 55; const static uint8_t A2 = 56; @@ -49,6 +58,31 @@ const static uint8_t A13 = 67; const static uint8_t A14 = 68; const static uint8_t A15 = 69; +// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins) +// Only pins available for RECEIVE (TRANSMIT can be on any pin): +// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me) +// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + +#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \ + (((p) >= 50) && ((p) <= 53)) || \ + (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) ) + +#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? 2 : \ + 0 ) ) + +#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \ + ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \ + ((uint8_t *)0) ) ) + +#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \ + ( ((p) == 50) ? 3 : \ + ( ((p) == 51) ? 2 : \ + ( ((p) == 52) ? 1 : \ + ( ((p) == 53) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ + 0 ) ) ) ) ) ) + #ifdef ARDUINO_MAIN const uint16_t PROGMEM port_to_mode_PGM[] = { diff --git a/hardware/arduino/pins/standard/pins_arduino.h b/hardware/arduino/variants/standard/pins_arduino.h similarity index 83% rename from hardware/arduino/pins/standard/pins_arduino.h rename to hardware/arduino/variants/standard/pins_arduino.h index 8fabb1781..3999d1fcd 100644 --- a/hardware/arduino/pins/standard/pins_arduino.h +++ b/hardware/arduino/variants/standard/pins_arduino.h @@ -27,11 +27,25 @@ #include +#define NUM_DIGITAL_PINS 20 +#define NUM_ANALOG_INPUTS 6 +#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1) + +#if defined(__AVR_ATmega8__) +#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11) +#else +#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11) +#endif + const static uint8_t SS = 10; const static uint8_t MOSI = 11; const static uint8_t MISO = 12; const static uint8_t SCK = 13; +const static uint8_t SDA = 18; +const static uint8_t SCL = 19; +const static uint8_t LED = 13; + const static uint8_t A0 = 14; const static uint8_t A1 = 15; const static uint8_t A2 = 16; @@ -41,6 +55,11 @@ const static uint8_t A5 = 19; const static uint8_t A6 = 20; const static uint8_t A7 = 21; +#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) +#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) +#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) +#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) + #ifdef ARDUINO_MAIN // On the Arduino board, digital pins are also used diff --git a/libraries/ArduinoTestSuite/examples/ATS_Write_Print/ATS_Write_Print.ino b/libraries/ArduinoTestSuite/examples/ATS_Write_Print/ATS_Write_Print.ino new file mode 100644 index 000000000..d7e47f179 --- /dev/null +++ b/libraries/ArduinoTestSuite/examples/ATS_Write_Print/ATS_Write_Print.ino @@ -0,0 +1,61 @@ +#include + +void Test_Equal(long actual, long expected) +{ + char buf[100]; + boolean b = expected == actual; + ATS_PrintTestStatus("", b); + if (!b) { + Serial.print("expected '"); + Serial.print(expected); + Serial.print("', actual '"); + Serial.print(actual); + Serial.println("'"); + } +} + +void setup() +{ + byte buf[5] = { 65, 66, 67, 0, 69 }; + ATS_begin("Arduino", "Write & Print Return Values Test"); + + Test_Equal(Serial.write('a'), 1); + Test_Equal(Serial.write(byte(0)), 1); + Test_Equal(Serial.write("abc"), 3); + Test_Equal(Serial.write(""), 0); + Test_Equal(Serial.write(buf, 5), 5); + Test_Equal(Serial.print(0), 1); + Test_Equal(Serial.print(""), 0); + Test_Equal(Serial.print("abc"), 3); + Test_Equal(Serial.print(0), 1); + Test_Equal(Serial.print(1), 1); + Test_Equal(Serial.print(11), 2); + Test_Equal(Serial.print(12345), 5); + Test_Equal(Serial.print(-1), 2); + Test_Equal(Serial.print(-123), 4); + Test_Equal(Serial.println(), 2); + Test_Equal(Serial.println(""), 2); + Test_Equal(Serial.println("abc"), 5); + Test_Equal(Serial.println(0), 3); + Test_Equal(Serial.println(1), 3); + Test_Equal(Serial.println(11), 4); + Test_Equal(Serial.println(12345), 7); + Test_Equal(Serial.println(-1), 4); + Test_Equal(Serial.println(-123), 6); + + ATS_end(); +} + +void loop() {} + + + + + + + + + + + + diff --git a/libraries/Ethernet/Client.cpp b/libraries/Ethernet/Client.cpp index f146ac5ed..3c1c2503b 100644 --- a/libraries/Ethernet/Client.cpp +++ b/libraries/Ethernet/Client.cpp @@ -70,19 +70,24 @@ int Client::connect(IPAddress ip, uint16_t port) { return 1; } -void Client::write(uint8_t b) { - if (_sock != MAX_SOCK_NUM) - send(_sock, &b, 1); +size_t Client::write(uint8_t b) { + return write(&b, 1); } -void Client::write(const char *str) { - if (_sock != MAX_SOCK_NUM) - send(_sock, (const uint8_t *)str, strlen(str)); +size_t Client::write(const char *str) { + return write((const uint8_t *) str, strlen(str)); } -void Client::write(const uint8_t *buf, size_t size) { - if (_sock != MAX_SOCK_NUM) - send(_sock, buf, size); +size_t Client::write(const uint8_t *buf, size_t size) { + if (_sock == MAX_SOCK_NUM) { + setWriteError(); + return 0; + } + if (!send(_sock, buf, size)) { + setWriteError(); + return 0; + } + return size; } int Client::available() { diff --git a/libraries/Ethernet/Client.h b/libraries/Ethernet/Client.h index 582f4938a..a8dd6fa42 100644 --- a/libraries/Ethernet/Client.h +++ b/libraries/Ethernet/Client.h @@ -12,9 +12,9 @@ public: uint8_t status(); int connect(IPAddress ip, uint16_t port); int connect(const char *host, uint16_t port); - virtual void write(uint8_t); - virtual void write(const char *str); - virtual void write(const uint8_t *buf, size_t size); + virtual size_t write(uint8_t); + virtual size_t write(const char *str); + virtual size_t write(const uint8_t *buf, size_t size); virtual int available(); virtual int read(); virtual int read(uint8_t *buf, size_t size); diff --git a/libraries/Ethernet/IPAddress.cpp b/libraries/Ethernet/IPAddress.cpp index 77928b5cb..fe3deb77a 100644 --- a/libraries/Ethernet/IPAddress.cpp +++ b/libraries/Ethernet/IPAddress.cpp @@ -42,13 +42,15 @@ bool IPAddress::operator==(const uint8_t* addr) return memcmp(addr, _address, sizeof(_address)) == 0; } -void IPAddress::printTo(Print& p) const +size_t IPAddress::printTo(Print& p) const { + size_t n = 0; for (int i =0; i < 3; i++) { - p.print(_address[i], DEC); - p.print('.'); + n += p.print(_address[i], DEC); + n += p.print('.'); } - p.print(_address[3], DEC); + n += p.print(_address[3], DEC); + return n; } diff --git a/libraries/Ethernet/IPAddress.h b/libraries/Ethernet/IPAddress.h index 7dd520351..2585aec0e 100644 --- a/libraries/Ethernet/IPAddress.h +++ b/libraries/Ethernet/IPAddress.h @@ -60,7 +60,7 @@ public: IPAddress& operator=(const uint8_t *address); IPAddress& operator=(uint32_t address); - virtual void printTo(Print& p) const; + virtual size_t printTo(Print& p) const; friend class EthernetClass; friend class UDP; diff --git a/libraries/Ethernet/Server.cpp b/libraries/Ethernet/Server.cpp index 4271741b9..1ac75d507 100644 --- a/libraries/Ethernet/Server.cpp +++ b/libraries/Ethernet/Server.cpp @@ -67,18 +67,20 @@ Client Server::available() return Client(MAX_SOCK_NUM); } -void Server::write(uint8_t b) +size_t Server::write(uint8_t b) { write(&b, 1); } -void Server::write(const char *str) +size_t Server::write(const char *str) { write((const uint8_t *)str, strlen(str)); } -void Server::write(const uint8_t *buffer, size_t size) +size_t Server::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + accept(); for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { @@ -86,7 +88,9 @@ void Server::write(const uint8_t *buffer, size_t size) if (EthernetClass::_server_port[sock] == _port && client.status() == SnSR::ESTABLISHED) { - client.write(buffer, size); + n += client.write(buffer, size); } } + + return n; } diff --git a/libraries/Ethernet/Server.h b/libraries/Ethernet/Server.h index 6aa5d3aaf..fa4a56d88 100644 --- a/libraries/Ethernet/Server.h +++ b/libraries/Ethernet/Server.h @@ -14,9 +14,9 @@ public: Server(uint16_t); Client available(); void begin(); - virtual void write(uint8_t); - virtual void write(const char *str); - virtual void write(const uint8_t *buf, size_t size); + virtual size_t write(uint8_t); + virtual size_t write(const char *str); + virtual size_t write(const uint8_t *buf, size_t size); }; #endif diff --git a/libraries/Ethernet/Udp.cpp b/libraries/Ethernet/Udp.cpp index aed5d983b..a1244ffb9 100644 --- a/libraries/Ethernet/Udp.cpp +++ b/libraries/Ethernet/Udp.cpp @@ -102,21 +102,22 @@ int UDP::endPacket() return sendUDP(_sock); } -void UDP::write(uint8_t byte) +size_t UDP::write(uint8_t byte) { - write(&byte, 1); + return write(&byte, 1); } -void UDP::write(const char *str) +size_t UDP::write(const char *str) { size_t len = strlen(str); - write((const uint8_t *)str, len); + return write((const uint8_t *)str, len); } -void UDP::write(const uint8_t *buffer, size_t size) +size_t UDP::write(const uint8_t *buffer, size_t size) { uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); _offset += bytes_written; + return bytes_written; } int UDP::parsePacket() diff --git a/libraries/Ethernet/Udp.h b/libraries/Ethernet/Udp.h index 99df53f15..59238c1ae 100644 --- a/libraries/Ethernet/Udp.h +++ b/libraries/Ethernet/Udp.h @@ -67,11 +67,11 @@ public: // Returns 1 if the packet was sent successfully, 0 if there was an error int endPacket(); // Write a single byte into the packet - virtual void write(uint8_t); + virtual size_t write(uint8_t); // Write a string of characters into the packet - virtual void write(const char *str); + virtual size_t write(const char *str); // Write size bytes from buffer into the packet - virtual void write(const uint8_t *buffer, size_t size); + virtual size_t write(const uint8_t *buffer, size_t size); // Start processing the next available incoming packet // Returns the size of the packet in bytes, or 0 if no packets are available diff --git a/libraries/LiquidCrystal/LiquidCrystal.cpp b/libraries/LiquidCrystal/LiquidCrystal.cpp index 04d0f50e7..81a3b7f64 100644 --- a/libraries/LiquidCrystal/LiquidCrystal.cpp +++ b/libraries/LiquidCrystal/LiquidCrystal.cpp @@ -258,8 +258,9 @@ inline void LiquidCrystal::command(uint8_t value) { send(value, LOW); } -inline void LiquidCrystal::write(uint8_t value) { +inline size_t LiquidCrystal::write(uint8_t value) { send(value, HIGH); + return 1; // assume sucess } /************ low level data pushing commands **********/ diff --git a/libraries/LiquidCrystal/LiquidCrystal.h b/libraries/LiquidCrystal/LiquidCrystal.h index f66ec1b4c..f4352f341 100755 --- a/libraries/LiquidCrystal/LiquidCrystal.h +++ b/libraries/LiquidCrystal/LiquidCrystal.h @@ -79,7 +79,7 @@ public: void createChar(uint8_t, uint8_t[]); void setCursor(uint8_t, uint8_t); - virtual void write(uint8_t); + virtual size_t write(uint8_t); void command(uint8_t); private: void send(uint8_t, uint8_t); diff --git a/libraries/SD/File.cpp b/libraries/SD/File.cpp index 9ef819667..ffd09471f 100644 --- a/libraries/SD/File.cpp +++ b/libraries/SD/File.cpp @@ -58,19 +58,27 @@ boolean File::isDirectory(void) { } -void File::write(uint8_t val) { - if (_file) - _file->write(val); +size_t File::write(uint8_t val) { + return write(&val, 1); } -void File::write(const char *str) { - if (_file) - _file->write(str); +size_t File::write(const char *str) { + return write((const uint8_t *) str, strlen(str)); } -void File::write(const uint8_t *buf, size_t size) { - if (_file) - _file->write(buf, size); +size_t File::write(const uint8_t *buf, size_t size) { + size_t t; + if (!_file) { + setWriteError(); + return 0; + } + _file->clearWriteError(); + t = _file->write(buf, size); + if (_file->writeError()) { + setWriteError(); + return 0; + } + return t; } int File::peek() { diff --git a/libraries/SD/SD.h b/libraries/SD/SD.h index 584e2ae9e..cd123edc6 100644 --- a/libraries/SD/SD.h +++ b/libraries/SD/SD.h @@ -32,9 +32,9 @@ public: File(SdFile f, char *name); // wraps an underlying SdFile File(void); // 'empty' constructor ~File(void); // destructor - virtual void write(uint8_t); - virtual void write(const char *str); - virtual void write(const uint8_t *buf, size_t size); + virtual size_t write(uint8_t); + virtual size_t write(const char *str); + virtual size_t write(const uint8_t *buf, size_t size); virtual int read(); virtual int peek(); virtual int available(); diff --git a/libraries/SD/utility/SdFat.h b/libraries/SD/utility/SdFat.h index 048fa711e..344326f98 100644 --- a/libraries/SD/utility/SdFat.h +++ b/libraries/SD/utility/SdFat.h @@ -141,7 +141,7 @@ class SdFile : public Print { * Set writeError to false before calling print() and/or write() and check * for true after calls to print() and/or write(). */ - bool writeError; + //bool writeError; /** * Cancel unbuffered reads for this file. * See setUnbufferedRead() @@ -283,9 +283,9 @@ class SdFile : public Print { } /** \return SdVolume that contains this file. */ SdVolume* volume(void) const {return vol_;} - void write(uint8_t b); - int16_t write(const void* buf, uint16_t nbyte); - void write(const char* str); + size_t write(uint8_t b); + size_t write(const void* buf, uint16_t nbyte); + size_t write(const char* str); void write_P(PGM_P str); void writeln_P(PGM_P str); //------------------------------------------------------------------------------ diff --git a/libraries/SD/utility/SdFile.cpp b/libraries/SD/utility/SdFile.cpp index 40444a721..47974e206 100644 --- a/libraries/SD/utility/SdFile.cpp +++ b/libraries/SD/utility/SdFile.cpp @@ -1121,7 +1121,7 @@ uint8_t SdFile::truncate(uint32_t length) { * for a read-only file, device is full, a corrupt file system or an I/O error. * */ -int16_t SdFile::write(const void* buf, uint16_t nbyte) { +size_t SdFile::write(const void* buf, uint16_t nbyte) { // convert void* to uint8_t* - must be before goto statements const uint8_t* src = reinterpret_cast(buf); @@ -1210,8 +1210,9 @@ int16_t SdFile::write(const void* buf, uint16_t nbyte) { writeErrorReturn: // return for write error - writeError = true; - return -1; + //writeError = true; + setWriteError(); + return 0; } //------------------------------------------------------------------------------ /** @@ -1219,8 +1220,8 @@ int16_t SdFile::write(const void* buf, uint16_t nbyte) { * * Use SdFile::writeError to check for errors. */ -void SdFile::write(uint8_t b) { - write(&b, 1); +size_t SdFile::write(uint8_t b) { + return write(&b, 1); } //------------------------------------------------------------------------------ /** @@ -1228,8 +1229,8 @@ void SdFile::write(uint8_t b) { * * Use SdFile::writeError to check for errors. */ -void SdFile::write(const char* str) { - write(str, strlen(str)); +size_t SdFile::write(const char* str) { + return write(str, strlen(str)); } //------------------------------------------------------------------------------ /** diff --git a/libraries/SoftwareSerial/SoftwareSerial.cpp b/libraries/SoftwareSerial/SoftwareSerial.cpp index b8a1fc46b..c15bdda0d 100755 --- a/libraries/SoftwareSerial/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -42,7 +42,6 @@ http://arduiniana.org. #include #include "Arduino.h" #include "SoftwareSerial.h" -#include "icrmacros.h" // // Lookup table // @@ -441,10 +440,12 @@ int SoftwareSerial::available() return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF; } -void SoftwareSerial::write(uint8_t b) +size_t SoftwareSerial::write(uint8_t b) { - if (_tx_delay == 0) - return; + if (_tx_delay == 0) { + setWriteError(); + return 0; + } uint8_t oldSREG = SREG; cli(); // turn off interrupts for a clean txmit @@ -485,6 +486,8 @@ void SoftwareSerial::write(uint8_t b) SREG = oldSREG; // turn interrupts back on tunedDelay(_tx_delay); + + return 1; } void SoftwareSerial::flush() diff --git a/libraries/SoftwareSerial/SoftwareSerial.h b/libraries/SoftwareSerial/SoftwareSerial.h index 2fc998c23..67f76cfdc 100755 --- a/libraries/SoftwareSerial/SoftwareSerial.h +++ b/libraries/SoftwareSerial/SoftwareSerial.h @@ -89,7 +89,7 @@ public: bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; } int peek(); - virtual void write(uint8_t byte); + virtual size_t write(uint8_t byte); virtual int read(); virtual int available(); virtual void flush(); diff --git a/libraries/SoftwareSerial/icrmacros.h b/libraries/SoftwareSerial/icrmacros.h deleted file mode 100755 index 936eae848..000000000 --- a/libraries/SoftwareSerial/icrmacros.h +++ /dev/null @@ -1,69 +0,0 @@ -/* -icrmacros.h - -A place to put useful ICR (interrupt change register) macros - -If you want to support non-Arduino processors you can extend or replace -this file. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; either -version 2.1 of the License, or (at your option) any later version. - -This library 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 -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -The latest version of this library can always be found at -http://arduiniana.org. -*/ - -// Abstractions for maximum portability between processors -// These are macros to associate pins to pin change interrupts -#if !defined(digitalPinToPCICR) // Courtesy Paul Stoffregen - -#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) - -#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) -#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) -#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) -#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) - -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -// Specifically for the Arduino Mega 2560 (or 1280 on the original Arduino Mega) -// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins) -// Only pins available for RECEIVE (TRANSMIT can be on any pin): -// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me) -// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 - -#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \ - (((p) >= 50) && ((p) <= 53)) || \ - (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) ) - -#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \ - ( (((p) >= 62) && ((p) <= 69)) ? 2 : \ - 0 ) ) - -#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \ - ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \ - ((uint8_t *)0) ) ) - -#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \ - ( ((p) == 50) ? 3 : \ - ( ((p) == 51) ? 2 : \ - ( ((p) == 52) ? 1 : \ - ( ((p) == 53) ? 0 : \ - ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ - 0 ) ) ) ) ) ) - -#else -#error This processor is not supported by SoftwareSerial -#endif -#endif - diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index 5818beef1..211d9c7ef 100755 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -124,13 +124,14 @@ uint8_t TwoWire::endTransmission(void) // must be called in: // slave tx event callback // or after beginTransmission(address) -void TwoWire::write(uint8_t data) +size_t TwoWire::write(uint8_t data) { if(transmitting){ // in master transmitter mode // don't bother if buffer is full if(txBufferLength >= BUFFER_LENGTH){ - return; + setWriteError(); + return 0; } // put byte in tx buffer txBuffer[txBufferIndex] = data; @@ -142,12 +143,13 @@ void TwoWire::write(uint8_t data) // reply to master twi_transmit(&data, 1); } + return 1; } // must be called in: // slave tx event callback // or after beginTransmission(address) -void TwoWire::write(const uint8_t *data, size_t quantity) +size_t TwoWire::write(const uint8_t *data, size_t quantity) { if(transmitting){ // in master transmitter mode @@ -159,14 +161,15 @@ void TwoWire::write(const uint8_t *data, size_t quantity) // reply to master twi_transmit(data, quantity); } + return quantity; } // must be called in: // slave tx event callback // or after beginTransmission(address) -void TwoWire::write(const char *data) +size_t TwoWire::write(const char *data) { - write((uint8_t*)data, strlen(data)); + return write((uint8_t*)data, strlen(data)); } // must be called in: diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h index 51df04e97..7f6ea67ad 100755 --- a/libraries/Wire/Wire.h +++ b/libraries/Wire/Wire.h @@ -52,9 +52,9 @@ class TwoWire : public Stream uint8_t endTransmission(void); uint8_t requestFrom(uint8_t, uint8_t); uint8_t requestFrom(int, int); - virtual void write(uint8_t); - virtual void write(const char *); - virtual void write(const uint8_t *, size_t); + virtual size_t write(uint8_t); + virtual size_t write(const char *); + virtual size_t write(const uint8_t *, size_t); virtual int available(void); virtual int read(void); virtual int peek(void);