Merge branch 'master' of github.com:arduino/Arduino into LUFA_bootloader

Conflicts:
	.gitignore
This commit is contained in:
Zach Eveland 2012-03-03 13:28:39 -05:00
commit 8a35793794
14 changed files with 554 additions and 234 deletions

17
.gitignore vendored Normal file
View File

@ -0,0 +1,17 @@
app/bin/
app/pde.jar
build/macosx/work/
core/bin/
core/core.jar
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.o
hardware/arduino/bootloaders/caterina_LUFA/Descriptors.lst
hardware/arduino/bootloaders/caterina_LUFA/Caterina.sym
hardware/arduino/bootloaders/caterina_LUFA/Caterina.o
hardware/arduino/bootloaders/caterina_LUFA/Caterina.map
hardware/arduino/bootloaders/caterina_LUFA/Caterina.lst
hardware/arduino/bootloaders/caterina_LUFA/Caterina.lss
hardware/arduino/bootloaders/caterina_LUFA/Caterina.elf
hardware/arduino/bootloaders/caterina_LUFA/Caterina.eep
hardware/arduino/bootloaders/caterina_LUFA/.dep/
.gitignore
build/windows/work/

View File

@ -42,9 +42,9 @@ import static processing.app.I18n._;
* files and images, etc) that comes from that.
*/
public class Base {
public static final int REVISION = 100;
public static final int REVISION = 101;
/** This might be replaced by main() if there's a lib/version.txt file. */
static String VERSION_NAME = "0100";
static String VERSION_NAME = "0101";
/** Set true if this a proper release rather than a numbered revision. */
static public boolean RELEASE = false;

View File

@ -1120,7 +1120,11 @@ public class Editor extends JFrame implements RunnerListener {
undoItem.addActionListener(undoAction = new UndoAction());
menu.add(undoItem);
redoItem = newJMenuItem(_("Redo"), 'Y');
if (!Base.isMacOS()) {
redoItem = newJMenuItem(_("Redo"), 'Y');
} else {
redoItem = newJMenuItemShift(_("Redo"), 'Z');
}
redoItem.addActionListener(redoAction = new RedoAction());
menu.add(redoItem);
@ -1232,14 +1236,33 @@ public class Editor extends JFrame implements RunnerListener {
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (find != null) {
//find.find(true);
//FindReplace find = new FindReplace(Editor.this); //.show();
find.find(true);
find.findNext();
}
}
});
menu.add(item);
item = newJMenuItemShift(_("Find Previous"), 'G');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (find != null) {
find.findPrevious();
}
}
});
menu.add(item);
item = newJMenuItem(_("Use Selection For Find"), 'E');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (find == null) {
find = new FindReplace(Editor.this);
}
find.setFindText( getSelectedText() );
}
});
menu.add(item);
return menu;
}

View File

@ -46,8 +46,9 @@ import javax.swing.*;
*/
public class FindReplace extends JFrame implements ActionListener {
static final int BIG = 13;
static final int EDGE = Base.isMacOS() ? 20 : 13;
static final int SMALL = 6;
static final int BUTTONGAP = 12; // 12 is correct for Mac, other numbers may be required for other platofrms
Editor editor;
@ -59,14 +60,14 @@ public class FindReplace extends JFrame implements ActionListener {
JButton replaceButton;
JButton replaceAllButton;
JButton replaceFindButton;
JButton previousButton;
JButton findButton;
JCheckBox ignoreCaseBox;
static boolean ignoreCase = true;
/// true when there's something selected in the editor
boolean found;
JCheckBox wrapAroundBox;
static boolean wrapAround = true;
public FindReplace(Editor editor) {
super("Find");
@ -77,23 +78,66 @@ public class FindReplace extends JFrame implements ActionListener {
pain.setLayout(null);
JLabel findLabel = new JLabel(_("Find:"));
Dimension d0 = findLabel.getPreferredSize();
JLabel replaceLabel = new JLabel(_("Replace with:"));
Dimension d1 = replaceLabel.getPreferredSize();
Dimension labelDimension = replaceLabel.getPreferredSize();
pain.add(findLabel);
pain.add(replaceLabel);
pain.add(findField = new JTextField(20));
pain.add(replaceField = new JTextField(20));
Dimension d2 = findField.getPreferredSize();
int fieldHeight = findField.getPreferredSize().height;
if (findString != null) findField.setText(findString);
if (replaceString != null) replaceField.setText(replaceString);
//System.out.println("setting find str to " + findString);
//findField.requestFocusInWindow();
//pain.setDefault
ignoreCaseBox = new JCheckBox(_("Ignore Case"));
ignoreCaseBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ignoreCase = ignoreCaseBox.isSelected();
}
});
ignoreCaseBox.setSelected(ignoreCase);
pain.add(ignoreCaseBox);
wrapAroundBox = new JCheckBox(_("Wrap Around"));
wrapAroundBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
wrapAround = wrapAroundBox.isSelected();
}
});
wrapAroundBox.setSelected(wrapAround);
pain.add(wrapAroundBox);
JPanel buttons = new JPanel();
buttons.setLayout(new FlowLayout(FlowLayout.CENTER,BUTTONGAP,0));
// ordering is different on mac versus pc
if (Base.isMacOS()) {
buttons.add(replaceAllButton = new JButton(_("Replace All")));
buttons.add(replaceButton = new JButton(_("Replace")));
buttons.add(replaceFindButton = new JButton(_("Replace & Find")));
buttons.add(previousButton = new JButton(_("Previous")));
buttons.add(findButton = new JButton(_("Find")));
} else {
buttons.add(findButton = new JButton(_("Find")));
buttons.add(previousButton = new JButton(_("Previous"))); // is this the right position for non-Mac?
buttons.add(replaceFindButton = new JButton(_("Replace & Find")));
buttons.add(replaceButton = new JButton(_("Replace")));
buttons.add(replaceAllButton = new JButton(_("Replace All")));
}
pain.add(buttons);
// to fix ugliness.. normally macosx java 1.3 puts an
// ugly white border around this object, so turn it off.
if (Base.isMacOS()) {
buttons.setBorder(null);
}
/*
findField.addFocusListener(new FocusListener() {
public void focusGained(FocusEvent e) {
@ -109,92 +153,74 @@ public class FindReplace extends JFrame implements ActionListener {
});
*/
// +1 since it's better to tend downwards
int yoff = (1 + d2.height - d1.height) / 2;
Dimension buttonsDimension = buttons.getPreferredSize();
int visibleButtonWidth = buttonsDimension.width - 2 * BUTTONGAP;
int fieldWidth = visibleButtonWidth - (labelDimension.width + SMALL);
findLabel.setBounds(BIG + (d1.width-d0.width) + yoff, BIG,
d1.width, d1.height);
replaceLabel.setBounds(BIG, BIG + d2.height + SMALL + yoff,
d1.width, d1.height);
// +1 since it's better to tend downwards
int yoff = (1 + fieldHeight - labelDimension.height) / 2;
//ignoreCase = true;
ignoreCaseBox = new JCheckBox(_("Ignore Case"));
ignoreCaseBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ignoreCase = ignoreCaseBox.isSelected();
}
});
ignoreCaseBox.setSelected(ignoreCase);
pain.add(ignoreCaseBox);
int ypos = EDGE;
int labelWidth = findLabel.getPreferredSize().width;
findLabel.setBounds(EDGE + (labelDimension.width-labelWidth), ypos + yoff, // + yoff was added to the wrong field
labelWidth, labelDimension.height);
findField.setBounds(EDGE + labelDimension.width + SMALL, ypos,
fieldWidth, fieldHeight);
ypos += fieldHeight + SMALL;
labelWidth = replaceLabel.getPreferredSize().width;
replaceLabel.setBounds(EDGE + (labelDimension.width-labelWidth), ypos + yoff,
labelWidth, labelDimension.height);
replaceField.setBounds(EDGE + labelDimension.width + SMALL, ypos,
fieldWidth, fieldHeight);
//
ypos += fieldHeight + SMALL;
JPanel buttons = new JPanel();
buttons.setLayout(new FlowLayout());
ignoreCaseBox.setBounds(EDGE + labelDimension.width + SMALL,
ypos,
(fieldWidth-SMALL)/2, fieldHeight);
// ordering is different on mac versus pc
if (Base.isMacOS()) {
buttons.add(replaceAllButton = new JButton(_("Replace All")));
buttons.add(replaceButton = new JButton(_("Replace")));
buttons.add(replaceFindButton = new JButton(_("Replace & Find")));
buttons.add(findButton = new JButton(_("Find")));
wrapAroundBox.setBounds(EDGE + labelDimension.width + SMALL + (fieldWidth-SMALL)/2 + SMALL,
ypos,
(fieldWidth-SMALL)/2, fieldHeight);
} else {
buttons.add(findButton = new JButton(_("Find")));
buttons.add(replaceFindButton = new JButton(_("Replace & Find")));
buttons.add(replaceButton = new JButton(_("Replace")));
buttons.add(replaceAllButton = new JButton(_("Replace All")));
}
pain.add(buttons);
ypos += fieldHeight + SMALL;
// to fix ugliness.. normally macosx java 1.3 puts an
// ugly white border around this object, so turn it off.
if (Base.isMacOS()) {
buttons.setBorder(null);
}
buttons.setBounds(EDGE-BUTTONGAP, ypos,
buttonsDimension.width, buttonsDimension.height);
Dimension d3 = buttons.getPreferredSize();
//buttons.setBounds(BIG, BIG + d2.height*2 + SMALL + BIG,
buttons.setBounds(BIG, BIG + d2.height*3 + SMALL*2 + BIG,
d3.width, d3.height);
ypos += buttonsDimension.height + EDGE;
//
// Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
findField.setBounds(BIG + d1.width + SMALL, BIG,
d3.width - (d1.width + SMALL), d2.height);
replaceField.setBounds(BIG + d1.width + SMALL, BIG + d2.height + SMALL,
d3.width - (d1.width + SMALL), d2.height);
int wide = visibleButtonWidth + EDGE*2;
int high = ypos; // butt.y + butt.height + EDGE*2 + SMALL;
ignoreCaseBox.setBounds(BIG + d1.width + SMALL,
BIG + d2.height*2 + SMALL*2,
d3.width, d2.height);
pack();
Insets insets = getInsets();
//System.out.println("Insets = " + insets);
setSize(wide + insets.left + insets.right,high + insets.top + insets.bottom);
//
setLocationRelativeTo( null ); // center
// setBounds((screen.width - wide) / 2, (screen.height - high) / 2, wide, high);
replaceButton.addActionListener(this);
replaceAllButton.addActionListener(this);
replaceFindButton.addActionListener(this);
findButton.addActionListener(this);
previousButton.addActionListener(this);
// you mustn't replace what you haven't found, my son
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
// so that typing will go straight to this field
//findField.requestFocus();
// semantics of replace are "replace the current selection with the replace field"
// so whether we have found before or not is irrelevent
// replaceButton.setEnabled(false);
// replaceFindButton.setEnabled(false);
// make the find button the blinky default
getRootPane().setDefaultButton(findButton);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int wide = d3.width + BIG*2;
Rectangle butt = buttons.getBounds(); // how big is your butt?
int high = butt.y + butt.height + BIG*2 + SMALL;
setBounds((screen.width - wide) / 2,
(screen.height - high) / 2, wide, high);
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
@ -245,11 +271,13 @@ public class FindReplace extends JFrame implements ActionListener {
Object source = e.getSource();
if (source == findButton) {
find(true);
findNext();
} else if (source == previousButton) {
findPrevious();
} else if (source == replaceFindButton) {
replace();
find(true);
replaceAndFindNext();
} else if (source == replaceButton) {
replace();
@ -260,50 +288,54 @@ public class FindReplace extends JFrame implements ActionListener {
}
// look for the next instance of the find string
// to be found later than the current caret selection
// look for the next instance of the find string to be found
// once found, select it (and go to that line)
public void find(boolean wrap) {
// in case search len is zero,
// otherwise replace all will go into an infinite loop
found = false;
private boolean find(boolean wrap,boolean backwards ) {
String search = findField.getText();
//System.out.println("finding for " + search + " " + findString);
// this will catch "find next" being called when no search yet
if (search.length() == 0) return;
if (search.length() == 0) return false;
String text = editor.getText();
if (ignoreCase) {
search = search.toLowerCase();
search = search.toLowerCase();
text = text.toLowerCase();
}
//int selectionStart = editor.textarea.getSelectionStart();
int selectionEnd = editor.getSelectionStop();
int nextIndex;
if (!backwards) {
//int selectionStart = editor.textarea.getSelectionStart();
int selectionEnd = editor.getSelectionStop();
int nextIndex = text.indexOf(search, selectionEnd);
if (nextIndex == -1) {
if (wrap) {
nextIndex = text.indexOf(search, selectionEnd);
if (wrap && nextIndex == -1) {
// if wrapping, a second chance is ok, start from beginning
nextIndex = text.indexOf(search, 0);
}
} else {
//int selectionStart = editor.textarea.getSelectionStart();
int selectionStart = editor.getSelectionStart()-1;
if (nextIndex == -1) {
found = false;
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
//Toolkit.getDefaultToolkit().beep();
return;
if ( selectionStart >= 0 ) {
nextIndex = text.lastIndexOf(search, selectionStart);
} else {
nextIndex = -1;
}
if (wrap && nextIndex == -1) {
// if wrapping, a second chance is ok, start from the end
nextIndex = text.lastIndexOf(search);
}
}
found = true;
replaceButton.setEnabled(true);
replaceFindButton.setEnabled(true);
editor.setSelection(nextIndex, nextIndex + search.length());
if (nextIndex != -1) {
editor.setSelection(nextIndex, nextIndex + search.length());
} else {
//Toolkit.getDefaultToolkit().beep();
}
return nextIndex != -1;
}
@ -312,28 +344,18 @@ public class FindReplace extends JFrame implements ActionListener {
* replacement text field.
*/
public void replace() {
if (!found) return; // don't replace if nothing found
// check to see if the document has wrapped around
// otherwise this will cause an infinite loop
String sel = editor.getSelectedText();
if (sel.equals(replaceField.getText())) {
found = false;
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
return;
}
editor.setSelectedText(replaceField.getText());
//editor.setSketchModified(true);
//editor.sketch.setCurrentModified(true);
editor.getSketch().setModified(true); // TODO is this necessary?
// don't allow a double replace
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
}
/**
* Replace the current selection with whatever's in the
* replacement text field, and then find the next match
*/
public void replaceAndFindNext() {
replace();
findNext();
}
/**
* Replace everything that matches by doing find and replace
@ -343,9 +365,35 @@ public class FindReplace extends JFrame implements ActionListener {
// move to the beginning
editor.setSelection(0, 0);
do {
find(false);
replace();
} while (found);
boolean foundAtLeastOne = false;
while ( true ) {
if ( find(false,false) ) {
foundAtLeastOne = true;
replace();
} else {
break;
}
}
if ( !foundAtLeastOne ) {
Toolkit.getDefaultToolkit().beep();
}
}
public void setFindText( String t ) {
findField.setText( t );
findString = t;
}
public void findNext() {
if ( !find( wrapAround, false ) ) {
Toolkit.getDefaultToolkit().beep();
}
}
public void findPrevious() {
if ( !find( wrapAround, true ) ) {
Toolkit.getDefaultToolkit().beep();
}
}
}

View File

@ -834,6 +834,17 @@ public class JEditTextArea extends JComponent
return lineElement.getEndOffset();
}
/**
* Returns the end offset of the specified line, but not past the end of the text
* @param line The line
* @return The end offset of the specified line, safe to use for a selection, or -1 if the line is
* invalid.
*/
public int getSafeLineStopOffset(int line)
{
return Math.min(getLineStopOffset(line),getDocumentLength());
}
/**
* Returns the length of the specified line.
* @param line The line
@ -1144,7 +1155,7 @@ public class JEditTextArea extends JComponent
{
throw new IllegalArgumentException("Bounds out of"
+ " range: " + newStart + "," +
newEnd);
newEnd + " [" + getDocumentLength() + "]");
}
// If the new position is the same as the old, we don't
@ -1201,6 +1212,86 @@ public class JEditTextArea extends JComponent
// getLineOfOffset(end));
}
}
private boolean isWordCharacter( char ch, String noWordSep )
{
return Character.isLetterOrDigit(ch) || ch=='_' || noWordSep.indexOf(ch) != -1;
}
protected void setNewSelectionWord( int line, int offset )
{
if (getLineLength(line) == 0) {
newSelectionStart = getLineStartOffset(line);
newSelectionEnd = newSelectionStart;
return;
}
String noWordSep = (String)document.getProperty("noWordSep");
if(noWordSep == null)
noWordSep = "";
String lineText = getLineText(line);
int wordStart = 0;
int wordEnd = lineText.length();
char ch = lineText.charAt(Math.max(0,offset - 1));
// special case for whitespace (fry 0122, bug #348)
// this is really nasty.. turns out that double-clicking any non-letter
// or digit char gets lumped together.. sooo, this quickly gets messy,
// because really it needs to check whether the chars are of the same
// type.. so a double space or double - might be grouped together,
// but what about a +=1? do + and - get grouped but not the 1? blech,
// coming back to this later. it's not a difficult fix, just a
// time-consuming one to track down all the proper cases.
/*
if (ch == ' ') {
//System.out.println("yeehaa");
for(int i = offset - 1; i >= 0; i--) {
if (lineText.charAt(i) == ' ') {
wordStart = i;
} else {
break;
}
}
for(int i = offset; i < lineText.length(); i++) {
if (lineText.charAt(i) == ' ') {
wordEnd = i + 1;
} else {
break;
}
}
} else {
*/
// If the user clicked on a non-letter char,
// we select the surrounding non-letters
boolean selectNoLetter = !isWordCharacter(ch,noWordSep);
for(int i = offset - 1; i >= 0; i--) {
ch = lineText.charAt(i);
if (selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
wordStart = i + 1;
break;
}
}
for(int i = offset; i < lineText.length(); i++) {
ch = lineText.charAt(i);
if(selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
wordEnd = i;
break;
}
}
//}
int lineStart = getLineStartOffset(line);
newSelectionStart = lineStart + wordStart;
newSelectionEnd = lineStart + wordEnd;
}
/**
@ -1684,6 +1775,14 @@ public class JEditTextArea extends JComponent
protected int selectionEnd;
protected int selectionEndLine;
protected boolean biasLeft;
protected int newSelectionStart; // hack to get around lack of multiple returns in Java
protected int newSelectionEnd;
protected boolean selectWord;
protected boolean selectLine;
protected int selectionAncorStart;
protected int selectionAncorEnd;
protected int bracketPosition;
protected int bracketLine;
@ -2021,9 +2120,26 @@ public class JEditTextArea extends JComponent
{
if (popup != null && popup.isVisible()) return;
setSelectionRectangular((evt.getModifiers()
& InputEvent.CTRL_MASK) != 0);
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
if ( !selectWord && !selectLine ) {
setSelectionRectangular((evt.getModifiers()
& InputEvent.CTRL_MASK) != 0);
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
} else {
int line = yToLine(evt.getY());
if ( selectWord ) {
setNewSelectionWord( line, xToOffset(line,evt.getX()) );
} else {
newSelectionStart = getLineStartOffset(line);
newSelectionEnd = getSafeLineStopOffset(line);
}
if ( newSelectionStart < selectionAncorStart ) {
select(newSelectionStart,selectionAncorEnd);
} else if ( newSelectionEnd > selectionAncorEnd ) {
select(selectionAncorStart,newSelectionEnd);
} else {
select(newSelectionStart,newSelectionEnd);
}
}
}
final Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
@ -2094,6 +2210,9 @@ public class JEditTextArea extends JComponent
int offset = xToOffset(line,evt.getX());
int dot = getLineStartOffset(line) + offset;
selectLine = false;
selectWord = false;
switch(evt.getClickCount()) {
case 1:
@ -2159,74 +2278,11 @@ public class JEditTextArea extends JComponent
bl.printStackTrace();
}
String noWordSep = (String)document.getProperty("noWordSep");
if(noWordSep == null)
noWordSep = "";
// Ok, it's not a bracket... select the word
String lineText = getLineText(line);
int wordStart = 0;
int wordEnd = lineText.length();
char ch = lineText.charAt(Math.max(0,offset - 1));
// special case for whitespace (fry 0122, bug #348)
// this is really nasty.. turns out that double-clicking any non-letter
// or digit char gets lumped together.. sooo, this quickly gets messy,
// because really it needs to check whether the chars are of the same
// type.. so a double space or double - might be grouped together,
// but what about a +=1? do + and - get grouped but not the 1? blech,
// coming back to this later. it's not a difficult fix, just a
// time-consuming one to track down all the proper cases.
/*
if (ch == ' ') {
//System.out.println("yeehaa");
for(int i = offset - 1; i >= 0; i--) {
if (lineText.charAt(i) == ' ') {
wordStart = i;
} else {
break;
}
}
for(int i = offset; i < lineText.length(); i++) {
if (lineText.charAt(i) == ' ') {
wordEnd = i + 1;
} else {
break;
}
}
} else {
*/
// If the user clicked on a non-letter char,
// we select the surrounding non-letters
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
for(int i = offset - 1; i >= 0; i--) {
ch = lineText.charAt(i);
if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1)) {
wordStart = i + 1;
break;
}
}
for(int i = offset; i < lineText.length(); i++) {
ch = lineText.charAt(i);
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1)) {
wordEnd = i;
break;
}
}
//}
int lineStart = getLineStartOffset(line);
select(lineStart + wordStart,lineStart + wordEnd);
setNewSelectionWord( line, offset );
select(newSelectionStart,newSelectionEnd);
selectWord = true;
selectionAncorStart = selectionStart;
selectionAncorEnd = selectionEnd;
/*
String lineText = getLineText(line);
@ -2242,7 +2298,10 @@ public class JEditTextArea extends JComponent
private void doTripleClick(MouseEvent evt, int line,
int offset, int dot)
{
select(getLineStartOffset(line),getLineStopOffset(line)-1);
selectLine = true;
select(getLineStartOffset(line),getSafeLineStopOffset(line));
selectionAncorStart = selectionStart;
selectionAncorEnd = selectionEnd;
}
}

View File

@ -133,8 +133,6 @@ void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
#elif defined(MCUCR) && defined(ISC20) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
GIMSK |= (1 << INT2);
#else
#warning attachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif

View File

@ -45,6 +45,8 @@ int analogRead(uint8_t pin)
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__)
if (pin >= 24) pin -= 24; // allow for channel or pin numbers
#else
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

View File

@ -11,13 +11,33 @@
int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
{
uint8_t dhcp_state = STATE_DHCP_START;
uint8_t messageType = 0;
// zero out _dhcpMacAddr, _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
memset(_dhcpMacAddr, 0, 26);
_dhcpLeaseTime=0;
_dhcpT1=0;
_dhcpT2=0;
_lastCheck=0;
_timeout = timeout;
_responseTimeout = responseTimeout;
// zero out _dhcpMacAddr
memset(_dhcpMacAddr, 0, 6);
reset_DHCP_lease();
memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
_dhcp_state = STATE_DHCP_START;
return request_DHCP_lease();
}
void DhcpClass::reset_DHCP_lease(){
// zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
memset(_dhcpLocalIp, 0, 20);
}
//return:0 on error, 1 if request is sent and response is received
int DhcpClass::request_DHCP_lease(){
uint8_t messageType = 0;
// Pick an initial transaction ID
_dhcpTransactionId = random(1UL, 2000UL);
@ -35,55 +55,75 @@ int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long
unsigned long startTime = millis();
while(dhcp_state != STATE_DHCP_LEASED)
while(_dhcp_state != STATE_DHCP_LEASED)
{
if(dhcp_state == STATE_DHCP_START)
if(_dhcp_state == STATE_DHCP_START)
{
_dhcpTransactionId++;
send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
dhcp_state = STATE_DHCP_DISCOVER;
_dhcp_state = STATE_DHCP_DISCOVER;
}
else if(dhcp_state == STATE_DHCP_DISCOVER)
else if(_dhcp_state == STATE_DHCP_REREQUEST){
_dhcpTransactionId++;
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
_dhcp_state = STATE_DHCP_REQUEST;
}
else if(_dhcp_state == STATE_DHCP_DISCOVER)
{
uint32_t respId;
messageType = parseDHCPResponse(responseTimeout, respId);
messageType = parseDHCPResponse(_responseTimeout, respId);
if(messageType == DHCP_OFFER)
{
// We'll use the transaction ID that the offer came with,
// rather than the one we were up to
_dhcpTransactionId = respId;
send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
dhcp_state = STATE_DHCP_REQUEST;
_dhcp_state = STATE_DHCP_REQUEST;
}
}
else if(dhcp_state == STATE_DHCP_REQUEST)
else if(_dhcp_state == STATE_DHCP_REQUEST)
{
uint32_t respId;
messageType = parseDHCPResponse(responseTimeout, respId);
messageType = parseDHCPResponse(_responseTimeout, respId);
if(messageType == DHCP_ACK)
{
dhcp_state = STATE_DHCP_LEASED;
_dhcp_state = STATE_DHCP_LEASED;
result = 1;
//use default lease time if we didn't get it
if(_dhcpLeaseTime == 0){
_dhcpLeaseTime = DEFAULT_LEASE;
}
//calculate T1 & T2 if we didn't get it
if(_dhcpT1 == 0){
//T1 should be 50% of _dhcpLeaseTime
_dhcpT1 = _dhcpLeaseTime >> 1;
}
if(_dhcpT2 == 0){
//T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
_dhcpT2 = _dhcpT1 << 1;
}
_renewInSec = _dhcpT1;
_rebindInSec = _dhcpT2;
}
else if(messageType == DHCP_NAK)
dhcp_state = STATE_DHCP_START;
_dhcp_state = STATE_DHCP_START;
}
if(messageType == 255)
{
messageType = 0;
dhcp_state = STATE_DHCP_START;
_dhcp_state = STATE_DHCP_START;
}
if(result != 1 && ((millis() - startTime) > timeout))
if(result != 1 && ((millis() - startTime) > _timeout))
break;
}
// We're done with the socket now
_dhcpUdpSocket.stop();
_dhcpTransactionId++;
return result;
}
@ -302,8 +342,26 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
}
}
break;
case dhcpT1value :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
_dhcpT1 = ntohl(_dhcpT1);
break;
case dhcpT2value :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
_dhcpT2 = ntohl(_dhcpT2);
break;
case dhcpIPaddrLeaseTime :
opt_len = _dhcpUdpSocket.read();
_dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
_dhcpLeaseTime = ntohl(_dhcpLeaseTime);
_renewInSec = _dhcpLeaseTime;
break;
default :
opt_len = _dhcpUdpSocket.read();
// Skip over the rest of this option
@ -322,6 +380,68 @@ uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& tr
return type;
}
/*
returns:
0/DHCP_CHECK_NONE: nothing happened
1/DHCP_CHECK_RENEW_FAIL: renew failed
2/DHCP_CHECK_RENEW_OK: renew success
3/DHCP_CHECK_REBIND_FAIL: rebind fail
4/DHCP_CHECK_REBIND_OK: rebind success
*/
int DhcpClass::checkLease(){
//this uses a signed / unsigned trick to deal with millis overflow
unsigned long now = millis();
signed long snow = (long)now;
int rc=DHCP_CHECK_NONE;
if (_lastCheck != 0){
signed long factor;
//calc how many ms past the timeout we are
factor = snow - (long)_secTimeout;
//if on or passed the timeout, reduce the counters
if ( factor >= 0 ){
//next timeout should be now plus 1000 ms minus parts of second in factor
_secTimeout = snow + 1000 - factor % 1000;
//how many seconds late are we, minimum 1
factor = factor / 1000 +1;
//reduce the counters by that mouch
//if we can assume that the cycle time (factor) is fairly constant
//and if the remainder is less than cycle time * 2
//do it early instead of late
if(_renewInSec < factor*2 )
_renewInSec = 0;
else
_renewInSec -= factor;
if(_rebindInSec < factor*2 )
_rebindInSec = 0;
else
_rebindInSec -= factor;
}
//if we have a lease but should renew, do it
if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
_dhcp_state = STATE_DHCP_REREQUEST;
rc = 1 + request_DHCP_lease();
}
//if we have a lease or is renewing but should bind, do it
if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
//this should basically restart completely
_dhcp_state = STATE_DHCP_START;
reset_DHCP_lease();
rc = 3 + request_DHCP_lease();
}
}
else{
_secTimeout = snow + 1000;
}
_lastCheck = now;
return rc;
}
IPAddress DhcpClass::getLocalIp()
{
return IPAddress(_dhcpLocalIp);

View File

@ -45,6 +45,13 @@
#define MAX_DHCP_OPT 16
#define HOST_NAME "WIZnet"
#define DEFAULT_LEASE (900) //default lease time in seconds
#define DHCP_CHECK_NONE (0)
#define DHCP_CHECK_RENEW_FAIL (1)
#define DHCP_CHECK_RENEW_OK (2)
#define DHCP_CHECK_REBIND_FAIL (3)
#define DHCP_CHECK_REBIND_OK (4)
enum
{
@ -139,8 +146,19 @@ private:
uint8_t _dhcpGatewayIp[4];
uint8_t _dhcpDhcpServerIp[4];
uint8_t _dhcpDnsServerIp[4];
uint32_t _dhcpLeaseTime;
uint32_t _dhcpT1, _dhcpT2;
signed long _renewInSec;
signed long _rebindInSec;
signed long _lastCheck;
unsigned long _timeout;
unsigned long _responseTimeout;
unsigned long _secTimeout;
uint8_t _dhcp_state;
EthernetUDP _dhcpUdpSocket;
int request_DHCP_lease();
void reset_DHCP_lease();
void presend_DHCP();
void send_DHCP_MESSAGE(uint8_t, uint16_t);
void printByte(char *, uint8_t);
@ -154,6 +172,7 @@ public:
IPAddress getDnsServerIp();
int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
int checkLease();
};
#endif

View File

@ -10,7 +10,8 @@ uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
int EthernetClass::begin(uint8_t *mac_address)
{
DhcpClass dhcp;
_dhcp = new DhcpClass();
// Initialise the basic info
W5100.init();
@ -18,15 +19,15 @@ int EthernetClass::begin(uint8_t *mac_address)
W5100.setIPAddress(IPAddress(0,0,0,0).raw_address());
// Now try to get our config info from a DHCP server
int ret = dhcp.beginWithDHCP(mac_address);
int ret = _dhcp->beginWithDHCP(mac_address);
if(ret == 1)
{
// We've successfully found a DHCP server and got our configuration info, so set things
// accordingly
W5100.setIPAddress(dhcp.getLocalIp().raw_address());
W5100.setGatewayIp(dhcp.getGatewayIp().raw_address());
W5100.setSubnetMask(dhcp.getSubnetMask().raw_address());
_dnsServerAddress = dhcp.getDnsServerIp();
W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
_dnsServerAddress = _dhcp->getDnsServerIp();
}
return ret;
@ -66,6 +67,31 @@ void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server
_dnsServerAddress = dns_server;
}
int EthernetClass::maintain(){
int rc = DHCP_CHECK_NONE;
if(_dhcp != NULL){
//we have a pointer to dhcp, use it
rc = _dhcp->checkLease();
switch ( rc ){
case DHCP_CHECK_NONE:
//nothing done
break;
case DHCP_CHECK_RENEW_OK:
case DHCP_CHECK_REBIND_OK:
//we might have got a new IP.
W5100.setIPAddress(_dhcp->getLocalIp().raw_address());
W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address());
W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address());
_dnsServerAddress = _dhcp->getDnsServerIp();
break;
default:
//this is actually a error, it will retry though
break;
}
}
return rc;
}
IPAddress EthernetClass::localIP()
{
IPAddress ret;

View File

@ -6,12 +6,14 @@
#include "IPAddress.h"
#include "EthernetClient.h"
#include "EthernetServer.h"
#include "Dhcp.h"
#define MAX_SOCK_NUM 4
class EthernetClass {
private:
IPAddress _dnsServerAddress;
DhcpClass* _dhcp;
public:
static uint8_t _state[MAX_SOCK_NUM];
static uint16_t _server_port[MAX_SOCK_NUM];
@ -23,6 +25,7 @@ public:
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server);
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway);
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
int maintain();
IPAddress localIP();
IPAddress subnetMask();

View File

@ -45,9 +45,9 @@ IPAddress ip(10,0,0,20);
// initialize the library instance:
EthernetClient client;
long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
unsigned long lastConnectionTime = 0; // last time you connected to the server, in milliseconds
boolean lastConnected = false; // state of the connection last time through the main loop
const int postingInterval = 10000; //delay between updates to Pachube.com
const unsigned long postingInterval = 10000; //delay between updates to Pachube.com
void setup() {
// start serial port:

View File

@ -14,7 +14,7 @@
version 0019.
Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13
* Ethernet shield attached to pins 10, 11, 12, 13
created 21 May 2011
by Tom Igoe
@ -35,12 +35,12 @@ IPAddress ip(192,168,1,20);
// initialize the library instance:
EthernetClient client;
const int requestInterval = 60000; // delay between requests
const unsigned long requestInterval = 60000; // delay between requests
char serverName[] = "api.twitter.com"; // twitter URL
boolean requested; // whether you've made a request since connecting
long lastAttemptTime = 0; // last time you connected to the server, in milliseconds
unsigned long lastAttemptTime = 0; // last time you connected to the server, in milliseconds
String currentLine = ""; // string to hold the text from server
String tweet = ""; // string to hold the tweet
@ -51,13 +51,17 @@ void setup() {
currentLine.reserve(256);
tweet.reserve(150);
// initialize serial:
// initialize serial:
Serial.begin(9600);
// attempt a DHCP connection:
Serial.println("Attempting to get an IP address using DHCP:");
if (!Ethernet.begin(mac)) {
// if DHCP fails, start with a hard-coded address:
Serial.println("failed to get an IP address using DHCP, trying manually");
Ethernet.begin(mac, ip);
}
Serial.print("My address:");
Serial.println(Ethernet.localIP());
// connect to Twitter:
connectToServer();
}
@ -114,7 +118,7 @@ void connectToServer() {
Serial.println("connecting to server...");
if (client.connect(serverName, 80)) {
Serial.println("making HTTP request...");
// make HTTP GET request to twitter:
// make HTTP GET request to twitter:
client.println("GET /1/statuses/user_timeline.xml?screen_name=arduino&count=1 HTTP/1.1");
client.println("HOST: api.twitter.com");
client.println();
@ -122,3 +126,4 @@ void connectToServer() {
// note the time of this connect attempt:
lastAttemptTime = millis();
}

View File

@ -1,4 +1,4 @@
0100 arduino
0101 arduino
Fix Linux make.sh, etc. scripts
Test on Linux.