arduino-0022
This commit is contained in:
parent
4f99742f03
commit
a9ad0e80a0
803 changed files with 69785 additions and 33024 deletions
|
@ -0,0 +1,715 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test Suite
|
||||
//* (C) 2010 by Mark Sproul
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//* 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.
|
||||
//************************************************************************
|
||||
//* Aug 31, 2010 <MLS> Started on TestArduino
|
||||
//* Oct 18, 2010 <MLS> Added memory testing
|
||||
//************************************************************************
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/eeprom.h>
|
||||
|
||||
|
||||
|
||||
#include "ArduinoTestSuite.h"
|
||||
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include "pins_arduino.h"
|
||||
|
||||
|
||||
#include "avr_cpunames.h"
|
||||
|
||||
#if defined(USART3_RX_vect)
|
||||
#define SERIAL_PORT_COUNT 4
|
||||
#elif defined(USART1_RX_vect)
|
||||
#define SERIAL_PORT_COUNT 2
|
||||
#else
|
||||
#define SERIAL_PORT_COUNT 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
enum
|
||||
{
|
||||
ATS_Manufacturer = 1,
|
||||
ATS_CPU,
|
||||
ATS_GCC_version,
|
||||
ATS_LIBC_version,
|
||||
ATS_CompiledDate,
|
||||
ATS_TestSuiteName,
|
||||
ATS_FreeMemory,
|
||||
|
||||
|
||||
};
|
||||
unsigned long gTestStartTime;
|
||||
short gTagIndent;
|
||||
int gYotalErrors;
|
||||
int gTestCount;
|
||||
|
||||
|
||||
|
||||
prog_char gTextMsg_Manufacturer[] PROGMEM = "MANUFACTURER";
|
||||
prog_char gTextMsg_CPUname[] PROGMEM = "CPU-NAME";
|
||||
prog_char gTextMsg_GCC_VERSION[] PROGMEM = "GCC-Version";
|
||||
prog_char gTextMsg_AVR_LIBC[] PROGMEM = "AVR-LibC-Ver";
|
||||
prog_char gTextMsg_COMPILED_DATE[] PROGMEM = "Compiled-date";
|
||||
prog_char gTextMsg_TEST_SUITE_NAME[] PROGMEM = "Test-Suite-Name";
|
||||
prog_char gTextMsg_memoryUsage[] PROGMEM = "Free-memory";
|
||||
prog_char gTextMsg_dotdotdot[] PROGMEM = "... ";
|
||||
prog_char gTextMsg_ok[] PROGMEM = "ok";
|
||||
prog_char gTextMsg_FAIL[] PROGMEM = "FAIL";
|
||||
prog_char gTextMsg_spaceEqual[] PROGMEM = " = ";
|
||||
prog_char gTextMsg_info[] PROGMEM = "info.";
|
||||
prog_char gTextMsg_dashLine[] PROGMEM = "--------------------------";
|
||||
prog_char gTextMsg_DigitalRW[] PROGMEM = "DigitalReadWrite_";
|
||||
prog_char gTextMsg_PWMoutput[] PROGMEM = "PWMoutput_";
|
||||
prog_char gTextMsg_AnalogInput[] PROGMEM = "AnalogInput_";
|
||||
|
||||
//************************************************************************
|
||||
void Serial_print_P(prog_char *flashMemStr)
|
||||
{
|
||||
char theChar;
|
||||
int ii;
|
||||
|
||||
ii = 0;
|
||||
#if (FLASHEND > 0x10000)
|
||||
while (theChar = pgm_read_byte_far(flashMemStr + ii++))
|
||||
#else
|
||||
while (theChar = pgm_read_byte_near(flashMemStr + ii++))
|
||||
#endif
|
||||
{
|
||||
Serial.print(theChar);
|
||||
}
|
||||
}
|
||||
|
||||
//************************************************************************
|
||||
void Serial_println_P(prog_char *flashMemStr)
|
||||
{
|
||||
Serial_print_P(flashMemStr);
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
//************************************************************************
|
||||
//* this is for internal use only, not made pubic to the API
|
||||
static void ATS_PrintProperty( int propertyTagNum,
|
||||
char *propertyName,
|
||||
char *propertyValue)
|
||||
{
|
||||
char lineBuffer[64];
|
||||
|
||||
strcpy_P(lineBuffer, gTextMsg_info);
|
||||
switch(propertyTagNum)
|
||||
{
|
||||
case 0:
|
||||
strcat(lineBuffer, propertyName);
|
||||
break;
|
||||
|
||||
case ATS_Manufacturer:
|
||||
strcat_P(lineBuffer, gTextMsg_Manufacturer);
|
||||
break;
|
||||
|
||||
case ATS_CPU:
|
||||
strcat_P(lineBuffer, gTextMsg_CPUname);
|
||||
break;
|
||||
|
||||
case ATS_GCC_version:
|
||||
strcat_P(lineBuffer, gTextMsg_GCC_VERSION);
|
||||
break;
|
||||
|
||||
case ATS_LIBC_version:
|
||||
strcat_P(lineBuffer, gTextMsg_AVR_LIBC);
|
||||
break;
|
||||
|
||||
case ATS_CompiledDate:
|
||||
strcat_P(lineBuffer, gTextMsg_COMPILED_DATE);
|
||||
break;
|
||||
|
||||
case ATS_TestSuiteName:
|
||||
strcat_P(lineBuffer, gTextMsg_TEST_SUITE_NAME);
|
||||
break;
|
||||
|
||||
case ATS_FreeMemory:
|
||||
strcat_P(lineBuffer, gTextMsg_memoryUsage);
|
||||
break;
|
||||
}
|
||||
|
||||
while (strlen(lineBuffer) < 20)
|
||||
{
|
||||
strcat(lineBuffer, " ");
|
||||
}
|
||||
|
||||
strcat_P(lineBuffer, gTextMsg_spaceEqual);
|
||||
if (propertyValue != 0)
|
||||
{
|
||||
strcat(lineBuffer, propertyValue);
|
||||
}
|
||||
Serial.println(lineBuffer);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void ATS_begin(char *manufName, char *testSuiteName)
|
||||
{
|
||||
int freeMemory;
|
||||
char memoryMsg[48];
|
||||
|
||||
gYotalErrors = 0;
|
||||
gTestCount = 0;
|
||||
|
||||
Serial.begin(9600);
|
||||
delay(1000);
|
||||
|
||||
gTestStartTime = millis();
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
ATS_PrintProperty(ATS_Manufacturer, 0, manufName);
|
||||
ATS_PrintProperty(ATS_CPU, 0, _AVR_CPU_NAME_);
|
||||
ATS_PrintProperty(ATS_GCC_version, 0, __VERSION__);
|
||||
ATS_PrintProperty(ATS_LIBC_version, 0, __AVR_LIBC_VERSION_STRING__);
|
||||
ATS_PrintProperty(ATS_CompiledDate, 0, __DATE__);
|
||||
ATS_PrintProperty(ATS_TestSuiteName, 0, testSuiteName);
|
||||
|
||||
freeMemory = ATS_GetFreeMemory();
|
||||
sprintf(memoryMsg, "%d bytes", freeMemory);
|
||||
ATS_PrintProperty(ATS_FreeMemory, 0, memoryMsg);
|
||||
|
||||
randomSeed(analogRead(0));
|
||||
|
||||
}
|
||||
|
||||
//************************************************************************
|
||||
void ATS_end()
|
||||
{
|
||||
long seconds;
|
||||
long milliSecs;
|
||||
|
||||
|
||||
Serial_println_P(gTextMsg_dashLine);
|
||||
|
||||
// Ran 4 tests in 0.000s
|
||||
Serial.print("Ran ");
|
||||
Serial.print(gTestCount);
|
||||
Serial.print(" tests in ");
|
||||
|
||||
seconds = millis() / 1000;
|
||||
milliSecs = millis() % 1000;
|
||||
Serial.print(seconds);
|
||||
Serial.print('.');
|
||||
Serial.print(milliSecs);
|
||||
Serial.print('s');
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
|
||||
if (gYotalErrors == 0)
|
||||
{
|
||||
Serial.print("OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print("FAILED (failures=");
|
||||
Serial.print(gYotalErrors);
|
||||
Serial.print(")");
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
//* send control D to terminate (End Of File)
|
||||
Serial.write(0x04);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void ATS_PrintTestStatus(char *testString, boolean passed)
|
||||
{
|
||||
int sLen;
|
||||
|
||||
Serial.print(testString);
|
||||
sLen = strlen(testString);
|
||||
while (sLen < 60)
|
||||
{
|
||||
Serial.print(' ');
|
||||
sLen++;
|
||||
}
|
||||
Serial_print_P(gTextMsg_dotdotdot);
|
||||
if (passed)
|
||||
{
|
||||
Serial_print_P(gTextMsg_ok);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial_print_P(gTextMsg_FAIL);
|
||||
gYotalErrors++;
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
gTestCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
//* returns true if no errors, false if there is an error
|
||||
int ATS_Test_DigitalPinWithHelper(uint8_t digitalPinToTest, uint8_t helperpin)
|
||||
{
|
||||
boolean passedOK;
|
||||
int pinValue;
|
||||
char testName[64];
|
||||
char numString[32];
|
||||
|
||||
strcpy_P(testName, gTextMsg_DigitalRW);
|
||||
sprintf(numString, "%02d", digitalPinToTest);
|
||||
strcat(testName, numString);
|
||||
|
||||
passedOK = true;
|
||||
|
||||
//* test senario 1
|
||||
pinMode(digitalPinToTest, OUTPUT);
|
||||
pinMode(helperpin, INPUT);
|
||||
|
||||
digitalWrite(digitalPinToTest, HIGH);
|
||||
pinValue = digitalRead(helperpin);
|
||||
if (pinValue != HIGH)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
digitalWrite(digitalPinToTest, LOW);
|
||||
pinValue = digitalRead(helperpin);
|
||||
if (pinValue != LOW)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
//* now reverse the input/output
|
||||
pinMode(digitalPinToTest, INPUT);
|
||||
pinMode(helperpin, OUTPUT);
|
||||
|
||||
digitalWrite(helperpin, HIGH);
|
||||
pinValue = digitalRead(digitalPinToTest);
|
||||
if (pinValue != HIGH)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
digitalWrite(helperpin, LOW);
|
||||
pinValue = digitalRead(digitalPinToTest);
|
||||
if (pinValue != LOW)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
if (! passedOK)
|
||||
{
|
||||
sprintf(numString, " (helper pin=%02d)", helperpin);
|
||||
strcat(testName, numString);
|
||||
}
|
||||
ATS_PrintTestStatus(testName, passedOK);
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
//************************************************************************
|
||||
boolean ATS_Test_DigitalPin(uint8_t digitalPinToTest)
|
||||
{
|
||||
boolean passedOK;
|
||||
uint8_t helperpin;
|
||||
|
||||
if ((digitalPinToTest % 2) == 0)
|
||||
{
|
||||
//* if its EVEN, add 1
|
||||
helperpin = digitalPinToTest + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//* if its ODD
|
||||
helperpin = digitalPinToTest - 1;
|
||||
}
|
||||
passedOK = ATS_Test_DigitalPinWithHelper(digitalPinToTest, helperpin);
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
//* returns true if no errors, false if there is an error
|
||||
int ATS_TestTimer( uint8_t timerPinNumber,
|
||||
uint8_t inputPin,
|
||||
char *statusString,
|
||||
char *errorString)
|
||||
{
|
||||
boolean passedOK;
|
||||
unsigned long loopCounter;
|
||||
unsigned long lowCount;
|
||||
unsigned long highCount;
|
||||
unsigned long startTime;
|
||||
int percentLow;
|
||||
int percentHigh;
|
||||
int pinValue;
|
||||
char numString[48];
|
||||
int pwmValue;
|
||||
|
||||
pwmValue = 128;
|
||||
loopCounter = 0;
|
||||
lowCount = 0;
|
||||
highCount = 0;
|
||||
passedOK = true;
|
||||
|
||||
startTime = millis();
|
||||
pinMode(inputPin, INPUT);
|
||||
analogWrite(timerPinNumber, pwmValue);
|
||||
while ((millis() - startTime) < 500)
|
||||
{
|
||||
pinValue = digitalRead(inputPin);
|
||||
if (pinValue == HIGH)
|
||||
{
|
||||
highCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowCount++;
|
||||
}
|
||||
}
|
||||
analogWrite(timerPinNumber, 0);
|
||||
|
||||
//* the difference should be about 50%
|
||||
percentLow = lowCount / ((lowCount + highCount) / 100);
|
||||
percentHigh = highCount / ((lowCount + highCount) / 100);
|
||||
if ((percentLow > 45) && (percentLow < 55))
|
||||
{
|
||||
passedOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
passedOK = false;
|
||||
strcat(errorString, " PWM ERROR");
|
||||
}
|
||||
sprintf(numString, " (PWM=%02d %d%% LOW %d%% HIGH)", pwmValue, percentLow, percentHigh);
|
||||
strcat(statusString, numString);
|
||||
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
//* returns true if no errors, false if there is an error
|
||||
boolean ATS_Test_PWMPinWithHelper(uint8_t pwmPinToTest, uint8_t helperpin)
|
||||
{
|
||||
boolean passedOK;
|
||||
char testName[64];
|
||||
char errorString[48];
|
||||
char numString[8];
|
||||
uint8_t timerNumber;
|
||||
|
||||
|
||||
|
||||
strcpy_P(testName, gTextMsg_PWMoutput);
|
||||
sprintf(numString, "%02d", pwmPinToTest);
|
||||
strcat(testName, numString);
|
||||
|
||||
passedOK = true;
|
||||
errorString[0] = 0;
|
||||
|
||||
|
||||
//* is pin1 a timer?
|
||||
timerNumber = digitalPinToTimer(pwmPinToTest);
|
||||
if (timerNumber != NOT_ON_TIMER)
|
||||
{
|
||||
passedOK = ATS_TestTimer(pwmPinToTest, helperpin, testName, errorString);
|
||||
}
|
||||
else
|
||||
{
|
||||
//* we should not get here
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
ATS_PrintTestStatus(testName, passedOK);
|
||||
|
||||
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
//************************************************************************
|
||||
boolean ATS_Test_PWM_Pin(uint8_t pwmPinToTest)
|
||||
{
|
||||
boolean passedOK;
|
||||
uint8_t helperpin;
|
||||
|
||||
if ((pwmPinToTest % 2) == 0)
|
||||
{
|
||||
//* if its EVEN, add 1
|
||||
helperpin = pwmPinToTest + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//* if its ODD
|
||||
helperpin = pwmPinToTest - 1;
|
||||
}
|
||||
passedOK = ATS_Test_PWMPinWithHelper(pwmPinToTest, helperpin);
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define kAnalogPinOffset 54
|
||||
#else
|
||||
#define kAnalogPinOffset 14
|
||||
#endif
|
||||
|
||||
|
||||
//************************************************************************
|
||||
boolean ATS_Test_AnalogInputWithHelper(uint8_t analogPintoTest, uint8_t helperPin)
|
||||
{
|
||||
boolean passedOK;
|
||||
char testName[64];
|
||||
char infoString[48];
|
||||
int analogValueHigh;
|
||||
int analogValueLow;
|
||||
|
||||
|
||||
//* first we have to set the ANALOG pin to INPUT
|
||||
pinMode(analogPintoTest + kAnalogPinOffset, INPUT);
|
||||
|
||||
passedOK = true;
|
||||
|
||||
strcpy_P(testName, gTextMsg_AnalogInput);
|
||||
sprintf(infoString, "%02d", analogPintoTest);
|
||||
strcat(testName, infoString);
|
||||
|
||||
|
||||
pinMode(helperPin, OUTPUT);
|
||||
|
||||
digitalWrite(helperPin, LOW);
|
||||
analogValueLow = analogRead(analogPintoTest);
|
||||
if (analogValueLow > 100)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
digitalWrite(helperPin, HIGH);
|
||||
analogValueHigh = analogRead(analogPintoTest);
|
||||
if (analogValueHigh < 1000)
|
||||
{
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
sprintf(infoString, " (Low=%4d High=%4d helper pin=%d)", analogValueLow, analogValueHigh, helperPin);
|
||||
strcat(testName, infoString);
|
||||
|
||||
ATS_PrintTestStatus(testName, passedOK);
|
||||
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
boolean ATS_Test_AnalogInput(uint8_t analogPinToTest)
|
||||
{
|
||||
boolean passedOK;
|
||||
uint8_t helperpin;
|
||||
|
||||
if ((analogPinToTest % 2) == 0)
|
||||
{
|
||||
//* if its EVEN, add 1
|
||||
helperpin = kAnalogPinOffset + analogPinToTest + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//* if its ODD
|
||||
helperpin = kAnalogPinOffset + analogPinToTest - 1;
|
||||
}
|
||||
passedOK = ATS_Test_AnalogInputWithHelper(analogPinToTest, helperpin);
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
#define kSerialTestBaudRate 9600
|
||||
#define kSerialTestDelay 3
|
||||
|
||||
|
||||
#if (SERIAL_PORT_COUNT > 1) && !defined(__AVR_ATmega32U4__)
|
||||
//************************************************************************
|
||||
//* retunrs 0 if no errors, 1 if an error occured
|
||||
short ATS_TestSerialLoopback(HardwareSerial *theSerialPort, char *serialPortName)
|
||||
{
|
||||
char xmitChar;
|
||||
char rcvChar;
|
||||
short ii;
|
||||
short serialErrCt;
|
||||
short timeOutLoopCtr;
|
||||
|
||||
|
||||
serialErrCt = 1;
|
||||
if (theSerialPort != 0)
|
||||
{
|
||||
serialErrCt = 0;
|
||||
theSerialPort->begin(kSerialTestBaudRate);
|
||||
|
||||
for (ii=0; ii<150; ii++)
|
||||
{
|
||||
xmitChar = ii;
|
||||
theSerialPort->print(xmitChar);
|
||||
|
||||
timeOutLoopCtr = 0;
|
||||
//* wait for data to come back or timeout
|
||||
while (!theSerialPort->available() && (timeOutLoopCtr < kSerialTestDelay))
|
||||
{
|
||||
delay(1);
|
||||
timeOutLoopCtr++;
|
||||
}
|
||||
|
||||
if (theSerialPort->available())
|
||||
{
|
||||
//* get the char
|
||||
rcvChar = theSerialPort->read();
|
||||
if (rcvChar != xmitChar)
|
||||
{
|
||||
serialErrCt = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
serialErrCt = 1;
|
||||
}
|
||||
}
|
||||
theSerialPort->end();
|
||||
|
||||
if (serialErrCt == 0)
|
||||
{
|
||||
ATS_PrintTestStatus(serialPortName, PASSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATS_PrintTestStatus(serialPortName, FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
return(serialErrCt);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//************************************************************************
|
||||
boolean ATS_Test_EEPROM(void)
|
||||
{
|
||||
boolean passedOK;
|
||||
uint8_t dataByte;
|
||||
uint8_t dataByteRead;
|
||||
uint16_t dataWord;
|
||||
uint16_t dataWordRead;
|
||||
uint32_t dataLongWord;
|
||||
uint32_t dataLongWordRead;
|
||||
int addressPtr;
|
||||
char reportString[48];
|
||||
|
||||
passedOK = true;
|
||||
//* test BYTE read/write
|
||||
addressPtr = random(E2END);
|
||||
dataByte = 0x5A;
|
||||
eeprom_write_byte((uint8_t *)addressPtr, dataByte);
|
||||
dataByteRead = eeprom_read_byte((uint8_t *)addressPtr);
|
||||
|
||||
sprintf(reportString, "EEPROM_byte_rw (addr= 0x%04X)", addressPtr);
|
||||
if (dataByteRead == dataByte)
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, PASSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, FAILED);
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
//* test WORD read/write
|
||||
addressPtr = random(E2END);
|
||||
dataWord = 0xA55A;
|
||||
eeprom_write_word((uint16_t *)addressPtr, dataWord);
|
||||
dataWordRead = eeprom_read_word((uint16_t *)addressPtr);
|
||||
|
||||
sprintf(reportString, "EEPROM_word_rw (addr= 0x%04X)", addressPtr);
|
||||
if (dataWordRead == dataWord)
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, PASSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, FAILED);
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
//* test Long WORD read/write
|
||||
addressPtr = random(E2END);
|
||||
dataLongWord = 0x5AA5A55A;
|
||||
eeprom_write_dword((uint32_t *)addressPtr, dataLongWord);
|
||||
dataLongWordRead = eeprom_read_dword((uint32_t *)addressPtr);
|
||||
|
||||
sprintf(reportString, "EEPROM_dword_rw (addr= 0x%04X)", addressPtr);
|
||||
if (dataLongWordRead == dataLongWord)
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, PASSED);
|
||||
}
|
||||
else
|
||||
{
|
||||
ATS_PrintTestStatus(reportString, FAILED);
|
||||
passedOK = false;
|
||||
}
|
||||
|
||||
|
||||
return(passedOK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
extern unsigned int __data_start;
|
||||
extern unsigned int __data_end;
|
||||
extern unsigned int __bss_start;
|
||||
extern unsigned int __bss_end;
|
||||
extern unsigned int __heap_start;
|
||||
extern void *__brkval;
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
int ATS_GetFreeMemory()
|
||||
{
|
||||
int free_memory;
|
||||
|
||||
if((int)__brkval == 0)
|
||||
{
|
||||
free_memory = ((int)&free_memory) - ((int)&__bss_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
free_memory = ((int)&free_memory) - ((int)__brkval);
|
||||
}
|
||||
return free_memory;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
//************************************************************************
|
||||
//************************************************************************
|
||||
//* Aug 31, 2010 <MLS> Started on TestArduino
|
||||
//************************************************************************
|
||||
|
||||
#ifndef _AVR_IO_H_
|
||||
#include <avr/io.h>
|
||||
#endif
|
||||
|
||||
#ifndef WProgram_h
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#ifndef HardwareSerial_h
|
||||
#include "HardwareSerial.h"
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(USART3_RX_vect)
|
||||
#define SERIAL_PORT_COUNT 4
|
||||
#elif defined(USART1_RX_vect)
|
||||
#define SERIAL_PORT_COUNT 2
|
||||
#else
|
||||
#define SERIAL_PORT_COUNT 1
|
||||
#endif
|
||||
|
||||
|
||||
void ATS_begin(char *manufName, char *testSuiteName);
|
||||
void ATS_end();
|
||||
|
||||
void ATS_PrintTestStatus(char *testString, boolean passed);
|
||||
boolean ATS_Test_DigitalPin(uint8_t digitalPinToTest);
|
||||
boolean ATS_Test_PWM_Pin(uint8_t digitalPinToTest);
|
||||
boolean ATS_Test_AnalogInput(uint8_t analogPintoTest);
|
||||
boolean ATS_Test_EEPROM(void);
|
||||
|
||||
short ATS_TestSerialLoopback(HardwareSerial *theSerialPort, char *serialPortName);
|
||||
|
||||
|
||||
int ATS_GetFreeMemory();
|
||||
|
||||
//************************************************************************
|
||||
//* this has to be an inline function because calling subroutines affects free memory
|
||||
inline void ATS_ReportMemoryUsage(int _memoryUsageAtStart)
|
||||
{
|
||||
int freeMemoryAtEnd;
|
||||
int lostMemory;
|
||||
boolean memoryOK;
|
||||
char memoryUsage[48];
|
||||
|
||||
freeMemoryAtEnd = ATS_GetFreeMemory();
|
||||
lostMemory = _memoryUsageAtStart - freeMemoryAtEnd;
|
||||
if (lostMemory == 0)
|
||||
{
|
||||
strcpy(memoryUsage, "Memory Usage");
|
||||
memoryOK = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(memoryUsage, "Memory Usage (lost %d bytes)", lostMemory);
|
||||
memoryOK = false;
|
||||
}
|
||||
ATS_PrintTestStatus(memoryUsage, memoryOK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern unsigned long gTestStartTime;
|
||||
extern int gYotalErrors;
|
||||
extern int gTestCount;
|
||||
|
||||
|
||||
#define PASSED true
|
||||
#define FAILED false
|
||||
|
186
arduino-0022-linux-x64/libraries/ArduinoTestSuite/avr_cpunames.h
Normal file
186
arduino-0022-linux-x64/libraries/ArduinoTestSuite/avr_cpunames.h
Normal file
|
@ -0,0 +1,186 @@
|
|||
//**************************************************************************************************
|
||||
//*
|
||||
//* Atmel AVR CPU name strings
|
||||
//*
|
||||
//**************************************************************************************************
|
||||
//* Sep 19, 2010 <MLS> Started on avr_cpunames.h
|
||||
//**************************************************************************************************
|
||||
|
||||
//#include "avr_cpunames.h"
|
||||
|
||||
//**************************************************************************************************
|
||||
|
||||
|
||||
#if defined (__AVR_AT94K__)
|
||||
#define _AVR_CPU_NAME_ "AT94k"
|
||||
#elif defined (__AVR_AT43USB320__)
|
||||
#elif defined (__AVR_AT43USB355__)
|
||||
#elif defined (__AVR_AT76C711__)
|
||||
#elif defined (__AVR_AT86RF401__)
|
||||
#elif defined (__AVR_AT90PWM1__)
|
||||
#elif defined (__AVR_AT90PWM2__)
|
||||
#elif defined (__AVR_AT90PWM2B__)
|
||||
#elif defined (__AVR_AT90PWM3__)
|
||||
#elif defined (__AVR_AT90PWM3B__)
|
||||
#elif defined (__AVR_AT90PWM216__)
|
||||
#elif defined (__AVR_AT90PWM316__)
|
||||
#elif defined (__AVR_ATmega32C1__)
|
||||
#elif defined (__AVR_ATmega32M1__)
|
||||
#elif defined (__AVR_ATmega32U4__)
|
||||
#define _AVR_CPU_NAME_ "ATmega32U4"
|
||||
#elif defined (__AVR_ATmega32U6__)
|
||||
#define _AVR_CPU_NAME_ "ATmega32U6"
|
||||
#elif defined (__AVR_ATmega128__)
|
||||
#define _AVR_CPU_NAME_ "Atmega128"
|
||||
#elif defined (__AVR_ATmega1280__)
|
||||
#define _AVR_CPU_NAME_ "ATmega1280"
|
||||
#elif defined (__AVR_ATmega1281__)
|
||||
#define _AVR_CPU_NAME_ "ATmega1281"
|
||||
#elif defined (__AVR_ATmega1284P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega1284"
|
||||
#elif defined (__AVR_ATmega2560__)
|
||||
#define _AVR_CPU_NAME_ "ATmega2560"
|
||||
#elif defined (__AVR_ATmega2561__)
|
||||
#define _AVR_CPU_NAME_ "ATmega2561"
|
||||
#elif defined (__AVR_AT90CAN32__)
|
||||
#define _AVR_CPU_NAME_ "AT90CAN32"
|
||||
#elif defined (__AVR_AT90CAN64__)
|
||||
#define _AVR_CPU_NAME_ "AT90CAN64"
|
||||
#elif defined (__AVR_AT90CAN128__)
|
||||
#define _AVR_CPU_NAME_ "AT90CAN128"
|
||||
#elif defined (__AVR_AT90USB82__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB82"
|
||||
#elif defined (__AVR_AT90USB162__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB162"
|
||||
#elif defined (__AVR_AT90USB646__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB646"
|
||||
#elif defined (__AVR_AT90USB647__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB647"
|
||||
#elif defined (__AVR_AT90USB1286__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB1286"
|
||||
#elif defined (__AVR_AT90USB1287__)
|
||||
#define _AVR_CPU_NAME_ "AT90USB1287"
|
||||
#elif defined (__AVR_ATmega64__)
|
||||
#define _AVR_CPU_NAME_ "ATmega64"
|
||||
#elif defined (__AVR_ATmega640__)
|
||||
#define _AVR_CPU_NAME_ "ATmega640"
|
||||
#elif defined (__AVR_ATmega644__)
|
||||
#define _AVR_CPU_NAME_ "ATmega644"
|
||||
#elif defined (__AVR_ATmega644P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega644P"
|
||||
#elif defined (__AVR_ATmega645__)
|
||||
#define _AVR_CPU_NAME_ "ATmega645"
|
||||
#elif defined (__AVR_ATmega6450__)
|
||||
#define _AVR_CPU_NAME_ "ATmega6450"
|
||||
#elif defined (__AVR_ATmega649__)
|
||||
#define _AVR_CPU_NAME_ "ATmega649"
|
||||
#elif defined (__AVR_ATmega6490__)
|
||||
#define _AVR_CPU_NAME_ "ATmega6490"
|
||||
#elif defined (__AVR_ATmega103__)
|
||||
#define _AVR_CPU_NAME_ "ATmega103"
|
||||
#elif defined (__AVR_ATmega32__)
|
||||
#define _AVR_CPU_NAME_ "Atmega32"
|
||||
#elif defined (__AVR_ATmega323__)
|
||||
#define _AVR_CPU_NAME_ "ATmega323"
|
||||
#elif defined (__AVR_ATmega324P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega324P"
|
||||
#elif defined (__AVR_ATmega325__)
|
||||
#define _AVR_CPU_NAME_ "ATmega325"
|
||||
#elif defined (__AVR_ATmega325P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega325P"
|
||||
#elif defined (__AVR_ATmega3250__)
|
||||
#define _AVR_CPU_NAME_ "ATmega3250"
|
||||
#elif defined (__AVR_ATmega3250P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega3250P"
|
||||
#elif defined (__AVR_ATmega328P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega328P"
|
||||
#elif defined (__AVR_ATmega329__)
|
||||
#define _AVR_CPU_NAME_ "ATmega329"
|
||||
#elif defined (__AVR_ATmega329P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega329P"
|
||||
#elif defined (__AVR_ATmega3290__)
|
||||
#define _AVR_CPU_NAME_ "ATmega3290"
|
||||
#elif defined (__AVR_ATmega3290P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega3290P"
|
||||
#elif defined (__AVR_ATmega32HVB__)
|
||||
#define _AVR_CPU_NAME_ "ATmega32HVB"
|
||||
#elif defined (__AVR_ATmega406__)
|
||||
#define _AVR_CPU_NAME_ "ATmega406"
|
||||
#elif defined (__AVR_ATmega16__)
|
||||
#define _AVR_CPU_NAME_ "Atmega16"
|
||||
#elif defined (__AVR_ATmega161__)
|
||||
#define _AVR_CPU_NAME_ "ATmega161"
|
||||
#elif defined (__AVR_ATmega162__)
|
||||
#define _AVR_CPU_NAME_ "ATmega162"
|
||||
#elif defined (__AVR_ATmega163__)
|
||||
#define _AVR_CPU_NAME_ "ATmega163"
|
||||
#elif defined (__AVR_ATmega164P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega164P"
|
||||
#elif defined (__AVR_ATmega165__)
|
||||
#define _AVR_CPU_NAME_ "ATmega165"
|
||||
#elif defined (__AVR_ATmega165P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega165P"
|
||||
#elif defined (__AVR_ATmega168__)
|
||||
#define _AVR_CPU_NAME_ "ATmega168"
|
||||
#elif defined (__AVR_ATmega168P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega168P"
|
||||
#elif defined (__AVR_ATmega169__)
|
||||
#define _AVR_CPU_NAME_ "Atmega169"
|
||||
#elif defined (__AVR_ATmega169P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega169P"
|
||||
#elif defined (__AVR_ATmega8HVA__)
|
||||
#define _AVR_CPU_NAME_ "ATmega8HVA"
|
||||
#elif defined (__AVR_ATmega16HVA__)
|
||||
#define _AVR_CPU_NAME_ "ATmega16HVA"
|
||||
#elif defined (__AVR_ATmega8__)
|
||||
#define _AVR_CPU_NAME_ "ATmega8"
|
||||
#elif defined (__AVR_ATmega48__)
|
||||
#define _AVR_CPU_NAME_ "ATmega48"
|
||||
#elif defined (__AVR_ATmega48P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega48P"
|
||||
#elif defined (__AVR_ATmega88__)
|
||||
#define _AVR_CPU_NAME_ "ATmega88"
|
||||
#elif defined (__AVR_ATmega88P__)
|
||||
#define _AVR_CPU_NAME_ "ATmega88P"
|
||||
#elif defined (__AVR_ATmega8515__)
|
||||
#define _AVR_CPU_NAME_ "ATmega8515"
|
||||
#elif defined (__AVR_ATmega8535__)
|
||||
#define _AVR_CPU_NAME_ "ATmega8535"
|
||||
#elif defined (__AVR_AT90S8535__)
|
||||
#elif defined (__AVR_AT90C8534__)
|
||||
#elif defined (__AVR_AT90S8515__)
|
||||
#elif defined (__AVR_AT90S4434__)
|
||||
#elif defined (__AVR_AT90S4433__)
|
||||
#elif defined (__AVR_AT90S4414__)
|
||||
#elif defined (__AVR_ATtiny22__)
|
||||
#elif defined (__AVR_ATtiny26__)
|
||||
#elif defined (__AVR_AT90S2343__)
|
||||
#elif defined (__AVR_AT90S2333__)
|
||||
#elif defined (__AVR_AT90S2323__)
|
||||
#elif defined (__AVR_AT90S2313__)
|
||||
#elif defined (__AVR_ATtiny2313__)
|
||||
#define _AVR_CPU_NAME_ "ATtiny2313"
|
||||
#elif defined (__AVR_ATtiny13__)
|
||||
#elif defined (__AVR_ATtiny13A__)
|
||||
#elif defined (__AVR_ATtiny25__)
|
||||
#elif defined (__AVR_ATtiny45__)
|
||||
#elif defined (__AVR_ATtiny85__)
|
||||
#elif defined (__AVR_ATtiny24__)
|
||||
#elif defined (__AVR_ATtiny44__)
|
||||
#elif defined (__AVR_ATtiny84__)
|
||||
#elif defined (__AVR_ATtiny261__)
|
||||
#elif defined (__AVR_ATtiny461__)
|
||||
#elif defined (__AVR_ATtiny861__)
|
||||
#elif defined (__AVR_ATtiny43U__)
|
||||
#elif defined (__AVR_ATtiny48__)
|
||||
#elif defined (__AVR_ATtiny88__)
|
||||
#elif defined (__AVR_ATtiny167__)
|
||||
|
||||
#else
|
||||
#error cpu not defined
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined (_AVR_CPU_NAME_)
|
||||
// #define _AVR_CPU_NAME_ "UNKNOWN"
|
||||
#endif
|
|
@ -0,0 +1,76 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test of Arduino Constants
|
||||
//* (C) 2010 by Rick Anderson
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//************************************************************************
|
||||
//* Oct 16, 2010 <ROA> Test of Arduino Constants
|
||||
//************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
int startMemoryUsage;
|
||||
|
||||
//Start memory usage must be site prior to ATS_begin
|
||||
startMemoryUsage = ATS_GetFreeMemory();
|
||||
ATS_begin("Arduino", "Test of Arduino Constants");
|
||||
/*
|
||||
* Test Run Start
|
||||
*/
|
||||
|
||||
|
||||
//test true constant
|
||||
ATS_PrintTestStatus("1. Test of true constant", true == 1);
|
||||
|
||||
//test false consts
|
||||
ATS_PrintTestStatus( "2. Test of false constant", false == 0);
|
||||
|
||||
//Test of HIGH == 1
|
||||
ATS_PrintTestStatus( "3. Test of HIGH == 1", HIGH == 1);
|
||||
|
||||
//Test of LOW == 0
|
||||
ATS_PrintTestStatus( "4. Test of LOW == 0", LOW == 0);
|
||||
|
||||
//Test of INPUT == 1
|
||||
ATS_PrintTestStatus( "5. Test of INPUT == 1", HIGH == 1);
|
||||
|
||||
//Test of OUTPUT == 0
|
||||
ATS_PrintTestStatus( "6. Test of OUTPUT == 0", LOW == 0);
|
||||
|
||||
//test decimal
|
||||
ATS_PrintTestStatus( "7. Test of decimal constant", 101 == ((1 * pow(10,2)) + (0 * pow(10,1)) + 1));
|
||||
|
||||
//test binary
|
||||
ATS_PrintTestStatus( "8. Test of binary constant", B101 == 5);
|
||||
|
||||
//test octal
|
||||
ATS_PrintTestStatus( "9. Test of octal constant", 0101 == 65);
|
||||
|
||||
//test hexadecimal
|
||||
ATS_PrintTestStatus( "7. Test of hexadecimal constant", (0x101 == 257));
|
||||
|
||||
/*
|
||||
* Test Run End
|
||||
*/
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
//************************************************************************
//* Arduino Test Suite
//* ATS_ToneTest
//*
//* Copyright (c) 2010 Mark Sproul 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
//************************************************************************
//* Aug 31, 2010 <MLS> Started on TestArduino
//* Oct 28, 2010 <MLS> Started on Delay
//************************************************************************
#include "WProgram.h"
#include "HardwareSerial.h"
#include <ArduinoTestSuite.h>
//************************************************************************
void setup()
{
short ii;
short testNum;
int startMemoryUsage;
unsigned long startMillis;
unsigned long endMillis;
unsigned long deltaMillis;
unsigned long errMillis;
boolean passed;
char testNameString[80];
startMemoryUsage = ATS_GetFreeMemory();
ATS_begin("Arduino", "DelayTest");
testNum = 1;
//* we start at 2 because 0/1 are RXD/TXD
for (ii=0; ii<1000; ii+= 15)
{
startMillis = millis();
delay(ii);
endMillis = millis();
deltaMillis = endMillis - startMillis;
if (deltaMillis >= ii)
{
errMillis = deltaMillis - ii;
}
else
{
errMillis = ii - deltaMillis;
}
if (errMillis <= 1)
{
passed = true;
}
else
{
passed = false;
}
sprintf(testNameString, "DelayTest.%02d (delay= %4d actual delay=%ld err=%ld)", testNum, ii, deltaMillis, errMillis);
ATS_PrintTestStatus(testNameString, passed);
testNum++;
}
ATS_ReportMemoryUsage(startMemoryUsage);
ATS_end();
}
//************************************************************************
void loop()
{
}
|
|
@ -0,0 +1,94 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test Suite
|
||||
//* (C) 2010 by Mark Sproul
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//************************************************************************
|
||||
//* Aug 31, 2010 <MLS> Started on TestArduino
|
||||
//* Oct 18, 2010 <MLS> Added memory testing
|
||||
//************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include "pins_arduino.h"
|
||||
#include <ArduinoTestSuite.h>
|
||||
#include "avr_cpunames.h"
|
||||
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
#define kBoard_PinCount 20
|
||||
#define kBoard_AnalogCount 6
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define kBoard_PinCount 70
|
||||
#define kBoard_AnalogCount 16
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
short ii;
|
||||
uint8_t timerNumber;
|
||||
int startMemoryUsage;
|
||||
|
||||
startMemoryUsage = ATS_GetFreeMemory();
|
||||
|
||||
ATS_begin("Arduino", "general");
|
||||
|
||||
//* test digital pins
|
||||
//* we start at 2 because 0/1 are RXD/TXD
|
||||
for (ii=2; ii<kBoard_PinCount; ii++)
|
||||
{
|
||||
ATS_Test_DigitalPin(ii);
|
||||
}
|
||||
|
||||
|
||||
//* test PWM pins
|
||||
//* we start at 2 because 0/1 are RXD/TXD
|
||||
for (ii=2; ii<kBoard_PinCount; ii++)
|
||||
{
|
||||
timerNumber = digitalPinToTimer(ii);
|
||||
if (timerNumber != NOT_ON_TIMER)
|
||||
{
|
||||
ATS_Test_PWM_Pin(ii);
|
||||
}
|
||||
}
|
||||
|
||||
for (ii=0; ii<kBoard_AnalogCount; ii++)
|
||||
{
|
||||
ATS_Test_AnalogInput(ii);
|
||||
}
|
||||
|
||||
#if (SERIAL_PORT_COUNT > 1)
|
||||
ATS_TestSerialLoopback(&Serial1, "Serial1");
|
||||
#endif
|
||||
#if (SERIAL_PORT_COUNT > 2)
|
||||
ATS_TestSerialLoopback(&Serial2, "Serial2");
|
||||
#endif
|
||||
#if (SERIAL_PORT_COUNT > 3)
|
||||
ATS_TestSerialLoopback(&Serial3, "Serial3");
|
||||
#endif
|
||||
|
||||
ATS_Test_EEPROM();
|
||||
|
||||
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Tests writing to and reading from a file, in particular the
|
||||
// the Stream implementation (e.g. read() and peek()).
|
||||
|
||||
#include <SD.h>
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
int startMemoryUsage = ATS_GetFreeMemory();
|
||||
boolean b;
|
||||
File f;
|
||||
|
||||
ATS_begin("Arduino", "SD Test");
|
||||
|
||||
ATS_PrintTestStatus("SD.begin()", b = SD.begin(4));
|
||||
if (!b) goto done;
|
||||
|
||||
SD.remove("test.txt");
|
||||
|
||||
f = SD.open("test.txt", FILE_WRITE);
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
f.print("abc");
|
||||
f.print("de");
|
||||
f.close();
|
||||
|
||||
f = SD.open("test.txt", FILE_WRITE);
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
f.print("fgh");
|
||||
f.close();
|
||||
|
||||
f = SD.open("test.txt");
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
ATS_PrintTestStatus("read()", f.read() == 'a');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'b');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'b');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'c');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'd');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'd');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'd');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'd');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'd');
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("read()", f.read() == 'e');
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'f');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'f');
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'g');
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'g');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'g');
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("available()", f.available() != 0);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'h');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'h');
|
||||
ATS_PrintTestStatus("available()", f.available() == 0);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == -1);
|
||||
ATS_PrintTestStatus("read()", f.read() == -1);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == -1);
|
||||
ATS_PrintTestStatus("read()", f.read() == -1);
|
||||
|
||||
f.close();
|
||||
|
||||
SD.remove("test2.txt");
|
||||
|
||||
f = SD.open("test2.txt", FILE_WRITE);
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
f.print("ABC");
|
||||
f.close();
|
||||
|
||||
f = SD.open("test.txt");
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'a');
|
||||
|
||||
f.close();
|
||||
|
||||
f = SD.open("test2.txt");
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'A');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'A');
|
||||
|
||||
f.close();
|
||||
|
||||
done:
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
#include <SD.h>
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
int startMemoryUsage = ATS_GetFreeMemory();
|
||||
boolean b;
|
||||
File f;
|
||||
|
||||
ATS_begin("Arduino", "SD Files Test");
|
||||
|
||||
ATS_PrintTestStatus("SD.begin()", b = SD.begin(4));
|
||||
if (!b) goto done;
|
||||
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.open()", f = SD.open("asdf.txt", FILE_WRITE)); f.close();
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("/asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.remove()", SD.remove("asdf.txt"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
|
||||
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("/asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/"));
|
||||
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("asdf"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
|
||||
|
||||
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("x/y/z"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/z"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y/z/"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("/x/y/z/"));
|
||||
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("x/y/z"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x/y"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
|
||||
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("x/y/"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("x"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
|
||||
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("/x"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("x/y/z"));
|
||||
|
||||
ATS_PrintTestStatus("!SD.open()", !(f = SD.open("asdf/asdf.txt", FILE_WRITE))); f.close();
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf.txt"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf/asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.mkdir()", SD.mkdir("asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("SD.open()", f = SD.open("asdf/asdf.txt", FILE_WRITE)); f.close();
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/asdf.txt"));
|
||||
ATS_PrintTestStatus("!SD.rmdir()", !SD.rmdir("asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf/asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.remove()", SD.remove("asdf/asdf.txt"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf/asdf.txt"));
|
||||
ATS_PrintTestStatus("SD.exists()", SD.exists("asdf"));
|
||||
ATS_PrintTestStatus("SD.rmdir()", SD.rmdir("asdf"));
|
||||
ATS_PrintTestStatus("!SD.exists()", !SD.exists("asdf"));
|
||||
|
||||
done:
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
void loop() {}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// Tests writing to and reading from a file, in particular the
|
||||
// the Stream implementation (e.g. read() and peek()).
|
||||
|
||||
#include <SD.h>
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
int startMemoryUsage = ATS_GetFreeMemory();
|
||||
boolean b;
|
||||
File f;
|
||||
|
||||
ATS_begin("Arduino", "SD Test");
|
||||
|
||||
ATS_PrintTestStatus("SD.begin()", b = SD.begin(4));
|
||||
if (!b) goto done;
|
||||
|
||||
SD.remove("test.txt");
|
||||
|
||||
f = SD.open("test.txt", FILE_WRITE);
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
ATS_PrintTestStatus("initial position", f.position() == 0);
|
||||
ATS_PrintTestStatus("initial size", f.size() == 0);
|
||||
|
||||
f.print("0123456789");
|
||||
|
||||
ATS_PrintTestStatus("position after writing", f.position() == 10);
|
||||
ATS_PrintTestStatus("size after writing", f.size() == 10);
|
||||
|
||||
f.seek(0);
|
||||
|
||||
ATS_PrintTestStatus("size after seek", f.size() == 10);
|
||||
ATS_PrintTestStatus("position after seek", f.position() == 0);
|
||||
|
||||
f.seek(7);
|
||||
|
||||
ATS_PrintTestStatus("position after seek", f.position() == 7);
|
||||
ATS_PrintTestStatus("reading after seek", f.read() == '7');
|
||||
ATS_PrintTestStatus("position after reading after seeking", f.position() == 8);
|
||||
ATS_PrintTestStatus("reading after reading after seeking", f.read() == '8');
|
||||
|
||||
f.seek(3);
|
||||
|
||||
ATS_PrintTestStatus("position after seeking", f.position() == 3);
|
||||
ATS_PrintTestStatus("peeking after seeking", f.peek() == '3');
|
||||
ATS_PrintTestStatus("position after peeking after seeking", f.position() == 3);
|
||||
ATS_PrintTestStatus("peeking after peeking after seeking", f.peek() == '3');
|
||||
ATS_PrintTestStatus("position after peeking after seeking", f.position() == 3);
|
||||
ATS_PrintTestStatus("peeking after peeking after seeking", f.read() == '3');
|
||||
ATS_PrintTestStatus("position after peeking after seeking", f.position() == 4);
|
||||
|
||||
f.seek(1);
|
||||
|
||||
ATS_PrintTestStatus("position after seeking", f.position() == 1);
|
||||
ATS_PrintTestStatus("peeking after seeking", f.peek() == '1');
|
||||
|
||||
f.seek(4);
|
||||
|
||||
ATS_PrintTestStatus("position after seeking", f.position() == 4);
|
||||
ATS_PrintTestStatus("peeking after seeking", f.peek() == '4');
|
||||
|
||||
f.seek(7);
|
||||
|
||||
ATS_PrintTestStatus("position()", f.position() == 7);
|
||||
ATS_PrintTestStatus("read()", f.read() == '7');
|
||||
|
||||
f.seek(0);
|
||||
f.peek();
|
||||
f.print("AB");
|
||||
|
||||
ATS_PrintTestStatus("position()", f.position() == 2);
|
||||
ATS_PrintTestStatus("size()", f.size() == 10);
|
||||
ATS_PrintTestStatus("read()", f.read() == '2');
|
||||
|
||||
f.seek(0);
|
||||
|
||||
ATS_PrintTestStatus("read()", f.read() == 'A');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'B');
|
||||
ATS_PrintTestStatus("read()", f.read() == '2');
|
||||
|
||||
f.close();
|
||||
|
||||
f = SD.open("test.txt");
|
||||
ATS_PrintTestStatus("SD.open()", f);
|
||||
if (!f) goto done;
|
||||
|
||||
ATS_PrintTestStatus("position()", f.position() == 0);
|
||||
ATS_PrintTestStatus("size()", f.size() == 10);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == 'A');
|
||||
ATS_PrintTestStatus("read()", f.read() == 'A');
|
||||
|
||||
f.seek(4);
|
||||
|
||||
ATS_PrintTestStatus("position()", f.position() == 4);
|
||||
ATS_PrintTestStatus("size()", f.size() == 10);
|
||||
ATS_PrintTestStatus("peek()", f.peek() == '4');
|
||||
ATS_PrintTestStatus("read()", f.read() == '4');
|
||||
|
||||
f.close();
|
||||
|
||||
done:
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
void loop() {}
|
|
@ -0,0 +1,52 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test Example Skeleton
|
||||
//* (C) 2010 by Rick Anderson
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//************************************************************************
|
||||
//* Oct 16, 2010 <ROA> Started on String Test
|
||||
//************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
int startMemoryUsage;
|
||||
|
||||
//startMemoryUsage must be set directly before ATS_begin
|
||||
startMemoryUsage = ATS_GetFreeMemory();
|
||||
ATS_begin("Arduino", "Skeleton Test");
|
||||
/*
|
||||
* Test Run Start
|
||||
* Test one passes because result is set to true
|
||||
* Test two fails becuase result is set to false
|
||||
* You can test memory for any set of tests by using the ATS_ReportMemoryUsage test
|
||||
* There is also a way to print current memeory for debugging
|
||||
*/
|
||||
ATS_PrintTestStatus("1. Test of true test status", true);
|
||||
|
||||
ATS_PrintTestStatus("2. Test of false test status, this will fail.", false);
|
||||
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
/*
|
||||
* Test Run End
|
||||
*/
|
||||
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test Example Skeleton
|
||||
//* (C) 2010 by Rick Anderson
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//************************************************************************
|
||||
//* Oct 16, 2010 <ROA> Started on String Test
|
||||
//************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
char testName[64];
|
||||
int startMemoryUsage;
|
||||
/*
|
||||
* Create variable for the tests.
|
||||
*/
|
||||
|
||||
|
||||
String stringOne;
|
||||
int firstClosingBracket;
|
||||
int firstOpeningBracket;
|
||||
int secondOpeningBracket;
|
||||
int secondClosingBracket;
|
||||
int bodyTag;
|
||||
int firstListItem;
|
||||
int secondListItem;
|
||||
int lastOpeningBracket;
|
||||
int lastListItem;
|
||||
int lastParagraph;
|
||||
int secondLastGraf;
|
||||
|
||||
/*;
|
||||
* initiate the test run
|
||||
*/
|
||||
startMemoryUsage = ATS_GetFreeMemory();
|
||||
ATS_begin("Arduino", "String Memory Test");
|
||||
// indexOf() returns the position (i.e. index) of a particular character
|
||||
// in a string. For example, if you were parsing HTML tags, you could use it:
|
||||
stringOne = "<HTML><HEAD><BODY>";
|
||||
firstClosingBracket = stringOne.indexOf('>');
|
||||
Serial.println("The index of > in the string " + stringOne + " is " + firstClosingBracket);
|
||||
|
||||
stringOne = "<HTML><HEAD><BODY>";
|
||||
secondOpeningBracket = firstClosingBracket + 1;
|
||||
secondClosingBracket = stringOne.indexOf('>', secondOpeningBracket );
|
||||
Serial.println("The index of the second > in the string " + stringOne + " is " + secondClosingBracket);
|
||||
|
||||
// you can also use indexOf() to search for Strings:
|
||||
stringOne = "<HTML><HEAD><BODY>";
|
||||
bodyTag = stringOne.indexOf("<BODY>");
|
||||
Serial.println("The index of the body tag in the string " + stringOne + " is " + bodyTag);
|
||||
|
||||
stringOne = "<UL><LI>item<LI>item<LI>item</UL>";
|
||||
firstListItem = stringOne.indexOf("<LI>");
|
||||
secondListItem = stringOne.indexOf("item", firstListItem + 1 );
|
||||
Serial.println("The index of the second list item in the string " + stringOne + " is " + secondClosingBracket);
|
||||
|
||||
// lastIndexOf() gives you the last occurrence of a character or string:
|
||||
lastOpeningBracket = stringOne.lastIndexOf('<');
|
||||
Serial.println("The index of the last < in the string " + stringOne + " is " + lastOpeningBracket);
|
||||
|
||||
lastListItem = stringOne.lastIndexOf("<LI>");
|
||||
Serial.println("The index of the last list item in the string " + stringOne + " is " + lastListItem);
|
||||
|
||||
|
||||
// lastIndexOf() can also search for a string:
|
||||
stringOne = "<p>Lorem ipsum dolor sit amet</p><p>Ipsem</p><p>Quod</p>";
|
||||
lastParagraph = stringOne.lastIndexOf("<p");
|
||||
secondLastGraf = stringOne.lastIndexOf("<p", lastParagraph - 1);
|
||||
Serial.println("The index of the second last paragraph tag " + stringOne + " is " + secondLastGraf);
|
||||
|
||||
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Test complete
|
||||
*/
|
||||
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
//************************************************************************
|
||||
//* Arduino String Test
|
||||
//* (C) 2010 by Rick Anderson
|
||||
//* Open source as per standard Arduino code
|
||||
//*
|
||||
//************************************************************************
|
||||
//* Oct 16, 2010 <ROA> Started on String Test
|
||||
//************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
|
||||
int startMemoryUsage;
|
||||
|
||||
ATS_begin("Arduino", "Test of String Library");
|
||||
|
||||
/*
|
||||
* Test Variable Setup
|
||||
* Best practive set all your test variables prior to teseting.
|
||||
* This is required for Memory tests.
|
||||
*/
|
||||
|
||||
String stringOne = String("stringThree = ");
|
||||
String stringTwo = String("this string");
|
||||
String stringThree = String ();
|
||||
char charResult[100];
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Run the tests
|
||||
*/
|
||||
|
||||
// adding a constant integer to a string:
|
||||
stringThree = stringOne + 123;
|
||||
//strcpy(charResult, "\0");
|
||||
stringThree.toCharArray(charResult, sizeof(charResult));
|
||||
|
||||
ATS_PrintTestStatus("1. Adding a constant integer to a string:", strcmp(charResult,"stringThree = 123" ) == 0);
|
||||
|
||||
// adding a constant long interger to a string:
|
||||
stringThree = stringOne + 123456789;
|
||||
stringThree.toCharArray(charResult, sizeof(charResult));
|
||||
|
||||
ATS_PrintTestStatus("2. Adding a constant long interger to a string", strcmp(charResult,"stringThree = 123456789" ) == 0);
|
||||
|
||||
|
||||
// adding a constant character to a string:
|
||||
stringThree = stringOne + 'A';
|
||||
stringThree.toCharArray(charResult, sizeof(charResult));
|
||||
|
||||
ATS_PrintTestStatus("3. Adding a constant character to a string", strcmp(charResult,"stringThree = A" ) == 0);
|
||||
|
||||
|
||||
// adding a constant string to a string:
|
||||
stringThree = stringOne + "abc";
|
||||
stringThree.toCharArray(charResult, sizeof(charResult));
|
||||
|
||||
ATS_PrintTestStatus("4. Adding a constant string variable to a string", strcmp(charResult,"stringThree = abc" ) == 0);
|
||||
|
||||
//"5. Adding a constant long interger to a string"
|
||||
stringThree = stringOne + stringTwo;
|
||||
stringThree.toCharArray(charResult, sizeof(charResult));
|
||||
|
||||
ATS_PrintTestStatus("5. Adding a constant long interger to a string", strcmp(charResult,"stringThree = this string" ) == 0);
|
||||
|
||||
|
||||
/*
|
||||
* setup up String Comparison Operater Tests
|
||||
*/
|
||||
|
||||
stringOne = String("this");
|
||||
stringTwo = String("that");
|
||||
|
||||
// two strings equal:
|
||||
ATS_PrintTestStatus("6. Two strings equal",stringOne == "this");
|
||||
|
||||
// two strings not equal:
|
||||
ATS_PrintTestStatus("7. Two strings not equal",stringOne != stringTwo);
|
||||
|
||||
// two strings not equal (case sensitivity matters):
|
||||
stringOne = "This";
|
||||
stringTwo = "this";
|
||||
ATS_PrintTestStatus("8. Two strings not equal [case sensitivity matters]", stringOne != stringTwo);
|
||||
|
||||
// you can also use equals() to see if two strings are the same:
|
||||
stringOne = "this";
|
||||
stringTwo = "this";
|
||||
ATS_PrintTestStatus("9. Equals() method equals", stringOne.equals(stringTwo));
|
||||
|
||||
|
||||
// you can also use not equals() to see if two strings are not the same:
|
||||
stringOne = String("This");
|
||||
stringTwo = String("this");
|
||||
ATS_PrintTestStatus("10. Not equals() method equals", !stringOne.equals(stringTwo));
|
||||
|
||||
// or perhaps you want to ignore case:
|
||||
ATS_PrintTestStatus("11. EqualsIgnoreCase() method equals", stringOne.equalsIgnoreCase(stringTwo));
|
||||
|
||||
// a numeric string compared to the number it represents:
|
||||
stringOne = "1";
|
||||
int numberOne = 1;
|
||||
ATS_PrintTestStatus("12. A numeric string compared to the number it represents", stringOne == numberOne);
|
||||
|
||||
// two numeric strings compared:
|
||||
stringOne = "2";
|
||||
stringTwo = "1";
|
||||
ATS_PrintTestStatus("13. Two numeric strings compared",stringOne >= stringTwo);
|
||||
|
||||
|
||||
// comparison operators can be used to compare strings for alphabetic sorting too:
|
||||
|
||||
/*
|
||||
stringOne = String("Brown");
|
||||
ATS_PrintTestStatus("14. comparison operator < can be used to compare strings for alphabetic sorting ",stringOne < "Charles");
|
||||
ATS_PrintTestStatus("15. comparison operator > can be used to compare strings for alphabetic sorting ",stringOne > "Adams");
|
||||
ATS_PrintTestStatus("16. comparison operator <= can be used to compare strings for alphabetic sorting ",stringOne <= "Browne");
|
||||
ATS_PrintTestStatus("17. comparison operator >= can be used to compare strings for alphabetic sorting ",stringOne >= "Brow");
|
||||
*/
|
||||
|
||||
|
||||
// the compareTo() operator also allows you to compare strings
|
||||
stringOne = "Cucumber";
|
||||
stringTwo = "Cucuracha";
|
||||
|
||||
ATS_PrintTestStatus("18. The compareTo() operator also allows you to compare strings", stringOne.compareTo(stringTwo) < 0);
|
||||
|
||||
// compareTo() String with numnber > String with number:
|
||||
stringOne = "Sensor: 50";
|
||||
stringTwo= "Sensor: 150";
|
||||
ATS_PrintTestStatus("19. The compareTo() String with integers", stringOne.compareTo(stringTwo) < 0);
|
||||
|
||||
|
||||
// compareTo() String with numnber > String with number append integer, matches example code:
|
||||
stringOne = "Sensor: ";
|
||||
stringTwo= "Sensor: ";
|
||||
stringOne += 50;
|
||||
stringTwo += 150;
|
||||
ATS_PrintTestStatus("20. The compareTo() compare strings with appended integers", stringOne.compareTo(stringTwo) < 0);
|
||||
|
||||
|
||||
/*
|
||||
* setup up String Append Operation Tests
|
||||
*/
|
||||
// Serious awful problem here
|
||||
stringOne = String("Sensor ");
|
||||
stringTwo = String("value");
|
||||
|
||||
stringOne += stringTwo;
|
||||
ATS_PrintTestStatus("21. Adding string to string += ", stringOne.equals("Sensor value"));
|
||||
|
||||
ATS_PrintTestStatus("22. The compareTo() compare strings with appended integers", stringOne.compareTo(stringTwo) < 0);
|
||||
/*
|
||||
* Test complete
|
||||
*/
|
||||
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,250 @@
|
|||
//************************************************************************
|
||||
//* Arduino Test Suite
|
||||
//* ATS_ToneTest
|
||||
//*
|
||||
//* Copyright (c) 2010 Mark Sproul 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
|
||||
//************************************************************************
|
||||
//* Aug 31, 2010 <MLS> Started on TestArduino
|
||||
//* Oct 23, 2010 <MLS> Started on ToneTest
|
||||
//************************************************************************
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
#define kBoard_PinCount 20
|
||||
#define kBoard_AnalogCount 6
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define kBoard_PinCount 70
|
||||
#define kBoard_AnalogCount 16
|
||||
#endif
|
||||
|
||||
#include <ArduinoTestSuite.h>
|
||||
|
||||
//************************************************************************
|
||||
void TestTonePin(uint8_t toneOutputPinNumber)
|
||||
{
|
||||
uint8_t helperpin;
|
||||
unsigned long startMilliSecs;
|
||||
unsigned long highCount, lowCount;
|
||||
int previousState;
|
||||
int currentState;
|
||||
char testNameString[80];
|
||||
long outputFreq;
|
||||
long measuredFreq;
|
||||
boolean passed;
|
||||
long percentError;
|
||||
long deltaFreq;
|
||||
|
||||
if ((toneOutputPinNumber % 2) == 0)
|
||||
{
|
||||
//* if its EVEN, add 1
|
||||
helperpin = toneOutputPinNumber + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//* if its ODD
|
||||
helperpin = toneOutputPinNumber - 1;
|
||||
}
|
||||
|
||||
//* dont set the mode of the OUTPUT pin, the tone command does that
|
||||
|
||||
pinMode(helperpin, INPUT);
|
||||
|
||||
previousState = digitalRead(helperpin);
|
||||
startMilliSecs = millis();
|
||||
highCount = 0;
|
||||
lowCount = 0;
|
||||
measuredFreq = 0;
|
||||
//* we are going to watch for one second
|
||||
outputFreq = random(200, 2000);
|
||||
|
||||
tone(toneOutputPinNumber, outputFreq);
|
||||
while ((millis() - startMilliSecs) < 1000)
|
||||
{
|
||||
currentState = digitalRead(helperpin);
|
||||
if (currentState == HIGH)
|
||||
{
|
||||
highCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowCount++;
|
||||
}
|
||||
//* check to see if it changed state
|
||||
if ((currentState == HIGH) && (previousState == LOW))
|
||||
{
|
||||
measuredFreq++;
|
||||
}
|
||||
|
||||
previousState = currentState;
|
||||
}
|
||||
noTone(toneOutputPinNumber);
|
||||
|
||||
deltaFreq = abs(measuredFreq - outputFreq);
|
||||
|
||||
percentError = 100 - abs(((outputFreq - deltaFreq) * 100) / outputFreq);
|
||||
|
||||
sprintf(testNameString, "ToneTest.%02d (out freq= %4ld measured freq= %4ld err= %ld%%)", toneOutputPinNumber, outputFreq, measuredFreq, percentError);
|
||||
if (percentError < 5)
|
||||
{
|
||||
passed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
|
||||
ATS_PrintTestStatus(testNameString, passed);
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
//* this test to make sure the duration option works
|
||||
void TestToneDuration(uint8_t toneOutputPinNumber)
|
||||
{
|
||||
uint8_t helperpin;
|
||||
unsigned long startMilliSecs;
|
||||
unsigned long highCount, lowCount;
|
||||
int previousState;
|
||||
int currentState;
|
||||
char testNameString[80];
|
||||
long outputFreq;
|
||||
long measuredFreq;
|
||||
boolean passed;
|
||||
long percentError;
|
||||
long deltaFreq;
|
||||
long durationTime;
|
||||
|
||||
if ((toneOutputPinNumber % 2) == 0)
|
||||
{
|
||||
//* if its EVEN, add 1
|
||||
helperpin = toneOutputPinNumber + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
//* if its ODD
|
||||
helperpin = toneOutputPinNumber - 1;
|
||||
}
|
||||
|
||||
//* dont set the mode of the OUTPUT pin, the tone command does that
|
||||
|
||||
pinMode(helperpin, INPUT);
|
||||
|
||||
previousState = digitalRead(helperpin);
|
||||
startMilliSecs = millis();
|
||||
highCount = 0;
|
||||
lowCount = 0;
|
||||
measuredFreq = 0;
|
||||
durationTime = 0;
|
||||
//* we are going to watch for one second
|
||||
outputFreq = random(500, 2000);
|
||||
|
||||
tone(toneOutputPinNumber, outputFreq, 1000);
|
||||
while ((millis() - startMilliSecs) < 2000)
|
||||
{
|
||||
currentState = digitalRead(helperpin);
|
||||
if (currentState == HIGH)
|
||||
{
|
||||
highCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
lowCount++;
|
||||
}
|
||||
//* count the freq
|
||||
if ((currentState == HIGH) && (previousState == LOW))
|
||||
{
|
||||
measuredFreq++;
|
||||
}
|
||||
|
||||
//* check to see if it changed state
|
||||
if (currentState != previousState)
|
||||
{
|
||||
durationTime = millis() - startMilliSecs;
|
||||
}
|
||||
|
||||
previousState = currentState;
|
||||
}
|
||||
|
||||
deltaFreq = abs(measuredFreq - outputFreq);
|
||||
|
||||
percentError = 100 - abs(((outputFreq - deltaFreq) * 100) / outputFreq);
|
||||
|
||||
sprintf(testNameString, "ToneTesDurationt.%02d (durationTime =%4ld/1000 freq err= %ld%%)", toneOutputPinNumber, durationTime, percentError);
|
||||
if ((durationTime > 990) && (durationTime < 1010) && (percentError < 5))
|
||||
{
|
||||
passed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = false;
|
||||
}
|
||||
noTone(toneOutputPinNumber);
|
||||
|
||||
ATS_PrintTestStatus(testNameString, passed);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void setup()
|
||||
{
|
||||
short ii;
|
||||
uint8_t timerNumber;
|
||||
int startMemoryUsage;
|
||||
|
||||
startMemoryUsage = ATS_GetFreeMemory();
|
||||
|
||||
ATS_begin("Arduino", "ToneTest");
|
||||
|
||||
|
||||
//* we start at 2 because 0/1 are RXD/TXD
|
||||
for (ii=2; ii<kBoard_PinCount; ii++)
|
||||
{
|
||||
TestTonePin(ii);
|
||||
}
|
||||
|
||||
|
||||
//* we dont need to test every pin
|
||||
for (ii=2; ii<kBoard_PinCount; ii += 5)
|
||||
{
|
||||
TestToneDuration(ii);
|
||||
}
|
||||
|
||||
|
||||
ATS_ReportMemoryUsage(startMemoryUsage);
|
||||
|
||||
ATS_end();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//************************************************************************
|
||||
void loop()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
50
arduino-0022-linux-x64/libraries/EEPROM/EEPROM.cpp
Normal file
50
arduino-0022-linux-x64/libraries/EEPROM/EEPROM.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
EEPROM.cpp - EEPROM library
|
||||
Copyright (c) 2006 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
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Includes
|
||||
******************************************************************************/
|
||||
|
||||
#include <avr/eeprom.h>
|
||||
#include "WConstants.h"
|
||||
#include "EEPROM.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Constructors
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* User API
|
||||
******************************************************************************/
|
||||
|
||||
uint8_t EEPROMClass::read(int address)
|
||||
{
|
||||
return eeprom_read_byte((unsigned char *) address);
|
||||
}
|
||||
|
||||
void EEPROMClass::write(int address, uint8_t value)
|
||||
{
|
||||
eeprom_write_byte((unsigned char *) address, value);
|
||||
}
|
||||
|
||||
EEPROMClass EEPROM;
|
35
arduino-0022-linux-x64/libraries/EEPROM/EEPROM.h
Normal file
35
arduino-0022-linux-x64/libraries/EEPROM/EEPROM.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
EEPROM.h - EEPROM library
|
||||
Copyright (c) 2006 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
|
||||
*/
|
||||
|
||||
#ifndef EEPROM_h
|
||||
#define EEPROM_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
class EEPROMClass
|
||||
{
|
||||
public:
|
||||
uint8_t read(int);
|
||||
void write(int, uint8_t);
|
||||
};
|
||||
|
||||
extern EEPROMClass EEPROM;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* EEPROM Clear
|
||||
*
|
||||
* Sets all of the bytes of the EEPROM to 0.
|
||||
* This example code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
|
||||
void setup()
|
||||
{
|
||||
// write a 0 to all 512 bytes of the EEPROM
|
||||
for (int i = 0; i < 512; i++)
|
||||
EEPROM.write(i, 0);
|
||||
|
||||
// turn the LED on when we're done
|
||||
digitalWrite(13, HIGH);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* EEPROM Read
|
||||
*
|
||||
* Reads the value of each byte of the EEPROM and prints it
|
||||
* to the computer.
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
|
||||
// start reading from the first byte (address 0) of the EEPROM
|
||||
int address = 0;
|
||||
byte value;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// read a byte from the current address of the EEPROM
|
||||
value = EEPROM.read(address);
|
||||
|
||||
Serial.print(address);
|
||||
Serial.print("\t");
|
||||
Serial.print(value, DEC);
|
||||
Serial.println();
|
||||
|
||||
// advance to the next address of the EEPROM
|
||||
address = address + 1;
|
||||
|
||||
// there are only 512 bytes of EEPROM, from 0 to 511, so if we're
|
||||
// on address 512, wrap around to address 0
|
||||
if (address == 512)
|
||||
address = 0;
|
||||
|
||||
delay(500);
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* EEPROM Write
|
||||
*
|
||||
* Stores values read from analog input 0 into the EEPROM.
|
||||
* These values will stay in the EEPROM when the board is
|
||||
* turned off and may be retrieved later by another sketch.
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
|
||||
// the current address in the EEPROM (i.e. which byte
|
||||
// we're going to write to next)
|
||||
int addr = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// need to divide by 4 because analog inputs range from
|
||||
// 0 to 1023 and each byte of the EEPROM can only hold a
|
||||
// value from 0 to 255.
|
||||
int val = analogRead(0) / 4;
|
||||
|
||||
// write the value to the appropriate byte of the EEPROM.
|
||||
// these values will remain there when the board is
|
||||
// turned off.
|
||||
EEPROM.write(addr, val);
|
||||
|
||||
// advance to the next address. there are 512 bytes in
|
||||
// the EEPROM, so go back to 0 when we hit 512.
|
||||
addr = addr + 1;
|
||||
if (addr == 512)
|
||||
addr = 0;
|
||||
|
||||
delay(100);
|
||||
}
|
18
arduino-0022-linux-x64/libraries/EEPROM/keywords.txt
Normal file
18
arduino-0022-linux-x64/libraries/EEPROM/keywords.txt
Normal file
|
@ -0,0 +1,18 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Ultrasound
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
EEPROM KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
147
arduino-0022-linux-x64/libraries/Ethernet/Client.cpp
Normal file
147
arduino-0022-linux-x64/libraries/Ethernet/Client.cpp
Normal file
|
@ -0,0 +1,147 @@
|
|||
#include "w5100.h"
|
||||
#include "socket.h"
|
||||
|
||||
extern "C" {
|
||||
#include "string.h"
|
||||
}
|
||||
|
||||
#include "WProgram.h"
|
||||
|
||||
#include "Ethernet.h"
|
||||
#include "Client.h"
|
||||
#include "Server.h"
|
||||
|
||||
uint16_t Client::_srcport = 1024;
|
||||
|
||||
Client::Client(uint8_t sock) : _sock(sock) {
|
||||
}
|
||||
|
||||
Client::Client(uint8_t *ip, uint16_t port) : _ip(ip), _port(port), _sock(MAX_SOCK_NUM) {
|
||||
}
|
||||
|
||||
uint8_t Client::connect() {
|
||||
if (_sock != MAX_SOCK_NUM)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < MAX_SOCK_NUM; i++) {
|
||||
uint8_t s = W5100.readSnSR(i);
|
||||
if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) {
|
||||
_sock = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_sock == MAX_SOCK_NUM)
|
||||
return 0;
|
||||
|
||||
_srcport++;
|
||||
if (_srcport == 0) _srcport = 1024;
|
||||
socket(_sock, SnMR::TCP, _srcport, 0);
|
||||
|
||||
if (!::connect(_sock, _ip, _port)) {
|
||||
_sock = MAX_SOCK_NUM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (status() != SnSR::ESTABLISHED) {
|
||||
delay(1);
|
||||
if (status() == SnSR::CLOSED) {
|
||||
_sock = MAX_SOCK_NUM;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Client::write(uint8_t b) {
|
||||
if (_sock != MAX_SOCK_NUM)
|
||||
send(_sock, &b, 1);
|
||||
}
|
||||
|
||||
void Client::write(const char *str) {
|
||||
if (_sock != MAX_SOCK_NUM)
|
||||
send(_sock, (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);
|
||||
}
|
||||
|
||||
int Client::available() {
|
||||
if (_sock != MAX_SOCK_NUM)
|
||||
return W5100.getRXReceivedSize(_sock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Client::read() {
|
||||
uint8_t b;
|
||||
if (!available())
|
||||
return -1;
|
||||
recv(_sock, &b, 1);
|
||||
return b;
|
||||
}
|
||||
|
||||
int Client::peek() {
|
||||
uint8_t b;
|
||||
if (!available())
|
||||
return -1;
|
||||
::peek(_sock, &b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void Client::flush() {
|
||||
while (available())
|
||||
read();
|
||||
}
|
||||
|
||||
void Client::stop() {
|
||||
if (_sock == MAX_SOCK_NUM)
|
||||
return;
|
||||
|
||||
// attempt to close the connection gracefully (send a FIN to other side)
|
||||
disconnect(_sock);
|
||||
unsigned long start = millis();
|
||||
|
||||
// wait a second for the connection to close
|
||||
while (status() != SnSR::CLOSED && millis() - start < 1000)
|
||||
delay(1);
|
||||
|
||||
// if it hasn't closed, close it forcefully
|
||||
if (status() != SnSR::CLOSED)
|
||||
close(_sock);
|
||||
|
||||
EthernetClass::_server_port[_sock] = 0;
|
||||
_sock = MAX_SOCK_NUM;
|
||||
}
|
||||
|
||||
uint8_t Client::connected() {
|
||||
if (_sock == MAX_SOCK_NUM) return 0;
|
||||
|
||||
uint8_t s = status();
|
||||
return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT ||
|
||||
(s == SnSR::CLOSE_WAIT && !available()));
|
||||
}
|
||||
|
||||
uint8_t Client::status() {
|
||||
if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED;
|
||||
return W5100.readSnSR(_sock);
|
||||
}
|
||||
|
||||
// the next three functions are a hack so we can compare the client returned
|
||||
// by Server::available() to null, or use it as the condition in an
|
||||
// if-statement. this lets us stay compatible with the Processing network
|
||||
// library.
|
||||
|
||||
uint8_t Client::operator==(int p) {
|
||||
return _sock == MAX_SOCK_NUM;
|
||||
}
|
||||
|
||||
uint8_t Client::operator!=(int p) {
|
||||
return _sock != MAX_SOCK_NUM;
|
||||
}
|
||||
|
||||
Client::operator bool() {
|
||||
return _sock != MAX_SOCK_NUM;
|
||||
}
|
37
arduino-0022-linux-x64/libraries/Ethernet/Client.h
Normal file
37
arduino-0022-linux-x64/libraries/Ethernet/Client.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef client_h
|
||||
#define client_h
|
||||
#include "WProgram.h"
|
||||
#include "Print.h"
|
||||
|
||||
class Client : public Stream {
|
||||
|
||||
public:
|
||||
Client();
|
||||
Client(uint8_t);
|
||||
Client(uint8_t *, uint16_t);
|
||||
|
||||
uint8_t status();
|
||||
uint8_t connect();
|
||||
virtual void write(uint8_t);
|
||||
virtual void write(const char *str);
|
||||
virtual void write(const uint8_t *buf, size_t size);
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
void stop();
|
||||
uint8_t connected();
|
||||
uint8_t operator==(int);
|
||||
uint8_t operator!=(int);
|
||||
operator bool();
|
||||
|
||||
friend class Server;
|
||||
|
||||
private:
|
||||
static uint16_t _srcport;
|
||||
uint8_t _sock;
|
||||
uint8_t *_ip;
|
||||
uint16_t _port;
|
||||
};
|
||||
|
||||
#endif
|
36
arduino-0022-linux-x64/libraries/Ethernet/Ethernet.cpp
Normal file
36
arduino-0022-linux-x64/libraries/Ethernet/Ethernet.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include "w5100.h"
|
||||
#include "Ethernet.h"
|
||||
|
||||
// XXX: don't make assumptions about the value of MAX_SOCK_NUM.
|
||||
uint8_t EthernetClass::_state[MAX_SOCK_NUM] = {
|
||||
0, 0, 0, 0 };
|
||||
uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {
|
||||
0, 0, 0, 0 };
|
||||
|
||||
void EthernetClass::begin(uint8_t *mac, uint8_t *ip)
|
||||
{
|
||||
uint8_t gateway[4];
|
||||
gateway[0] = ip[0];
|
||||
gateway[1] = ip[1];
|
||||
gateway[2] = ip[2];
|
||||
gateway[3] = 1;
|
||||
begin(mac, ip, gateway);
|
||||
}
|
||||
|
||||
void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway)
|
||||
{
|
||||
uint8_t subnet[] = {
|
||||
255, 255, 255, 0 };
|
||||
begin(mac, ip, gateway, subnet);
|
||||
}
|
||||
|
||||
void EthernetClass::begin(uint8_t *mac, uint8_t *ip, uint8_t *gateway, uint8_t *subnet)
|
||||
{
|
||||
W5100.init();
|
||||
W5100.setMACAddress(mac);
|
||||
W5100.setIPAddress(ip);
|
||||
W5100.setGatewayIp(gateway);
|
||||
W5100.setSubnetMask(subnet);
|
||||
}
|
||||
|
||||
EthernetClass Ethernet;
|
25
arduino-0022-linux-x64/libraries/Ethernet/Ethernet.h
Normal file
25
arduino-0022-linux-x64/libraries/Ethernet/Ethernet.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef ethernet_h
|
||||
#define ethernet_h
|
||||
|
||||
#include <inttypes.h>
|
||||
//#include "w5100.h"
|
||||
#include "Client.h"
|
||||
#include "Server.h"
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
class EthernetClass {
|
||||
private:
|
||||
public:
|
||||
static uint8_t _state[MAX_SOCK_NUM];
|
||||
static uint16_t _server_port[MAX_SOCK_NUM];
|
||||
void begin(uint8_t *, uint8_t *);
|
||||
void begin(uint8_t *, uint8_t *, uint8_t *);
|
||||
void begin(uint8_t *, uint8_t *, uint8_t *, uint8_t *);
|
||||
friend class Client;
|
||||
friend class Server;
|
||||
};
|
||||
|
||||
extern EthernetClass Ethernet;
|
||||
|
||||
#endif
|
92
arduino-0022-linux-x64/libraries/Ethernet/Server.cpp
Normal file
92
arduino-0022-linux-x64/libraries/Ethernet/Server.cpp
Normal file
|
@ -0,0 +1,92 @@
|
|||
#include "w5100.h"
|
||||
#include "socket.h"
|
||||
extern "C" {
|
||||
#include "string.h"
|
||||
}
|
||||
|
||||
#include "Ethernet.h"
|
||||
#include "Client.h"
|
||||
#include "Server.h"
|
||||
|
||||
Server::Server(uint16_t port)
|
||||
{
|
||||
_port = port;
|
||||
}
|
||||
|
||||
void Server::begin()
|
||||
{
|
||||
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
|
||||
Client client(sock);
|
||||
if (client.status() == SnSR::CLOSED) {
|
||||
socket(sock, SnMR::TCP, _port, 0);
|
||||
listen(sock);
|
||||
EthernetClass::_server_port[sock] = _port;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::accept()
|
||||
{
|
||||
int listening = 0;
|
||||
|
||||
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
|
||||
Client client(sock);
|
||||
|
||||
if (EthernetClass::_server_port[sock] == _port) {
|
||||
if (client.status() == SnSR::LISTEN) {
|
||||
listening = 1;
|
||||
}
|
||||
else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) {
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!listening) {
|
||||
begin();
|
||||
}
|
||||
}
|
||||
|
||||
Client Server::available()
|
||||
{
|
||||
accept();
|
||||
|
||||
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
|
||||
Client client(sock);
|
||||
if (EthernetClass::_server_port[sock] == _port &&
|
||||
(client.status() == SnSR::ESTABLISHED ||
|
||||
client.status() == SnSR::CLOSE_WAIT)) {
|
||||
if (client.available()) {
|
||||
// XXX: don't always pick the lowest numbered socket.
|
||||
return client;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Client(MAX_SOCK_NUM);
|
||||
}
|
||||
|
||||
void Server::write(uint8_t b)
|
||||
{
|
||||
write(&b, 1);
|
||||
}
|
||||
|
||||
void Server::write(const char *str)
|
||||
{
|
||||
write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
void Server::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
accept();
|
||||
|
||||
for (int sock = 0; sock < MAX_SOCK_NUM; sock++) {
|
||||
Client client(sock);
|
||||
|
||||
if (EthernetClass::_server_port[sock] == _port &&
|
||||
client.status() == SnSR::ESTABLISHED) {
|
||||
client.write(buffer, size);
|
||||
}
|
||||
}
|
||||
}
|
22
arduino-0022-linux-x64/libraries/Ethernet/Server.h
Normal file
22
arduino-0022-linux-x64/libraries/Ethernet/Server.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
class Client;
|
||||
|
||||
class Server :
|
||||
public Print {
|
||||
private:
|
||||
uint16_t _port;
|
||||
void accept();
|
||||
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);
|
||||
};
|
||||
|
||||
#endif
|
136
arduino-0022-linux-x64/libraries/Ethernet/Udp.cpp
Normal file
136
arduino-0022-linux-x64/libraries/Ethernet/Udp.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
|
||||
* This version only offers minimal wrapping of socket.c/socket.h
|
||||
* Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#include "w5100.h"
|
||||
#include "socket.h"
|
||||
#include "Ethernet.h"
|
||||
#include "Udp.h"
|
||||
|
||||
/* Start UDP socket, listening at local port PORT */
|
||||
void UdpClass::begin(uint16_t port) {
|
||||
_port = port;
|
||||
_sock = 0; //TODO: should not be hardcoded
|
||||
socket(_sock, SnMR::UDP, _port, 0);
|
||||
}
|
||||
|
||||
/* Send packet contained in buf of length len to peer at specified ip, and port */
|
||||
/* Use this function to transmit binary data that might contain 0x00 bytes*/
|
||||
/* This function returns sent data size for success else -1. */
|
||||
uint16_t UdpClass::sendPacket(uint8_t * buf, uint16_t len, uint8_t * ip, uint16_t port){
|
||||
return sendto(_sock,(const uint8_t *)buf,len,ip,port);
|
||||
}
|
||||
|
||||
/* Send zero-terminated string str as packet to peer at specified ip, and port */
|
||||
/* This function returns sent data size for success else -1. */
|
||||
uint16_t UdpClass::sendPacket(const char str[], uint8_t * ip, uint16_t port){
|
||||
// compute strlen
|
||||
const char *s;
|
||||
for(s = str; *s; ++s);
|
||||
uint16_t len = (s-str);
|
||||
// send packet
|
||||
return sendto(_sock,(const uint8_t *)str,len,ip,port);
|
||||
}
|
||||
/* Is data available in rx buffer? Returns 0 if no, number of available bytes if yes.
|
||||
* returned value includes 8 byte UDP header!*/
|
||||
int UdpClass::available() {
|
||||
return W5100.getRXReceivedSize(_sock);
|
||||
}
|
||||
|
||||
|
||||
/* Read a received packet into buffer buf (which is of maximum length len); */
|
||||
/* store calling ip and port as well. Call available() to make sure data is ready first. */
|
||||
/* NOTE: I don't believe len is ever checked in implementation of recvfrom(),*/
|
||||
/* so it's easy to overflow buffer. so we check and truncate. */
|
||||
/* returns number of bytes read, or negative number of bytes we would have needed if we truncated */
|
||||
int UdpClass::readPacket(uint8_t * buf, uint16_t bufLen, uint8_t *ip, uint16_t *port) {
|
||||
int packetLen = available()-8; //skip UDP header;
|
||||
if(packetLen < 0 ) return 0; // no real data here
|
||||
if(packetLen > (int)bufLen) {
|
||||
//packet is too large - truncate
|
||||
//HACK - hand-parse the UDP packet using TCP recv method
|
||||
uint8_t tmpBuf[8];
|
||||
int i;
|
||||
//read 8 header bytes and get IP and port from it
|
||||
recv(_sock,tmpBuf,8);
|
||||
ip[0] = tmpBuf[0];
|
||||
ip[1] = tmpBuf[1];
|
||||
ip[2] = tmpBuf[2];
|
||||
ip[3] = tmpBuf[3];
|
||||
*port = tmpBuf[4];
|
||||
*port = (*port << 8) + tmpBuf[5];
|
||||
|
||||
//now copy first (bufLen) bytes into buf
|
||||
for(i=0;i<(int)bufLen;i++) {
|
||||
recv(_sock,tmpBuf,1);
|
||||
buf[i]=tmpBuf[0];
|
||||
}
|
||||
|
||||
//and just read the rest byte by byte and throw it away
|
||||
while(available()) {
|
||||
recv(_sock,tmpBuf,1);
|
||||
}
|
||||
|
||||
return (-1*packetLen);
|
||||
|
||||
//ALTERNATIVE: requires stdlib - takes a bunch of space
|
||||
/*//create new buffer and read everything into it
|
||||
uint8_t * tmpBuf = (uint8_t *)malloc(packetLen);
|
||||
recvfrom(_sock,tmpBuf,packetLen,ip,port);
|
||||
if(!tmpBuf) return 0; //couldn't allocate
|
||||
// copy first bufLen bytes
|
||||
for(unsigned int i=0; i<bufLen; i++) {
|
||||
buf[i]=tmpBuf[i];
|
||||
}
|
||||
//free temp buffer
|
||||
free(tmpBuf);
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
return recvfrom(_sock,buf,bufLen,ip,port);
|
||||
}
|
||||
|
||||
/* Read a received packet, throw away peer's ip and port. See note above. */
|
||||
int UdpClass::readPacket(uint8_t * buf, uint16_t len) {
|
||||
uint8_t ip[4];
|
||||
uint16_t port[1];
|
||||
return recvfrom(_sock,buf,len,ip,port);
|
||||
}
|
||||
|
||||
int UdpClass::readPacket(char * buf, uint16_t bufLen, uint8_t *ip, uint16_t &port) {
|
||||
uint16_t myPort;
|
||||
uint16_t ret = readPacket( (byte*)buf, bufLen, ip, &myPort);
|
||||
port = myPort;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Create one global object */
|
||||
UdpClass Udp;
|
63
arduino-0022-linux-x64/libraries/Ethernet/Udp.h
Normal file
63
arduino-0022-linux-x64/libraries/Ethernet/Udp.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield.
|
||||
* This version only offers minimal wrapping of socket.c/socket.h
|
||||
* Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/
|
||||
*
|
||||
* NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these)
|
||||
* 1) UDP does not guarantee the order in which assembled UDP packets are received. This
|
||||
* might not happen often in practice, but in larger network topologies, a UDP
|
||||
* packet can be received out of sequence.
|
||||
* 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being
|
||||
* aware of it. Again, this may not be a concern in practice on small local networks.
|
||||
* For more information, see http://www.cafeaulait.org/course/week12/35.html
|
||||
*
|
||||
* MIT License:
|
||||
* Copyright (c) 2008 Bjoern Hartmann
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* bjoern@cs.stanford.edu 12/30/2008
|
||||
*/
|
||||
|
||||
#ifndef udp_h
|
||||
#define udp_h
|
||||
|
||||
#define UDP_TX_PACKET_MAX_SIZE 24
|
||||
|
||||
class UdpClass {
|
||||
private:
|
||||
uint8_t _sock; // socket ID for Wiz5100
|
||||
uint16_t _port; // local port to listen on
|
||||
|
||||
public:
|
||||
void begin(uint16_t); // initialize, start listening on specified port
|
||||
int available(); // has data been received?
|
||||
|
||||
// C-style buffer-oriented functions
|
||||
uint16_t sendPacket(uint8_t *, uint16_t, uint8_t *, uint16_t); //send a packet to specified peer
|
||||
uint16_t sendPacket(const char[], uint8_t *, uint16_t); //send a string as a packet to specified peer
|
||||
int readPacket(uint8_t *, uint16_t); // read a received packet
|
||||
int readPacket(uint8_t *, uint16_t, uint8_t *, uint16_t *); // read a received packet, also return sender's ip and port
|
||||
// readPacket that fills a character string buffer
|
||||
int readPacket(char *, uint16_t, uint8_t *, uint16_t &);
|
||||
|
||||
};
|
||||
|
||||
extern UdpClass Udp;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
SCP1000 Barometric Pressure Sensor Display
|
||||
|
||||
Serves the output of a Barometric Pressure Sensor as a web page.
|
||||
Uses the SPI library. For details on the sensor, see:
|
||||
http://www.sparkfun.com/commerce/product_info.php?products_id=8161
|
||||
http://www.vti.fi/en/support/obsolete_products/pressure_sensors/
|
||||
|
||||
This sketch adapted from Nathan Seidle's SCP1000 example for PIC:
|
||||
http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip
|
||||
|
||||
Circuit:
|
||||
SCP1000 sensor attached to pins 6,7, and 11 - 13:
|
||||
DRDY: pin 6
|
||||
CSB: pin 7
|
||||
MOSI: pin 11
|
||||
MISO: pin 12
|
||||
SCK: pin 13
|
||||
|
||||
created 31 July 2010
|
||||
by Tom Igoe
|
||||
*/
|
||||
|
||||
#include <Ethernet.h>
|
||||
// the sensor communicates using SPI, so include the library:
|
||||
#include <SPI.h>
|
||||
|
||||
|
||||
// assign a MAC address for the ethernet controller.
|
||||
// fill in your address here:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
// assign an IP address for the controller:
|
||||
byte ip[] = {
|
||||
192,168,1,20 };
|
||||
byte gateway[] = {
|
||||
192,168,1,1};
|
||||
byte subnet[] = {
|
||||
255, 255, 255, 0 };
|
||||
|
||||
|
||||
// Initialize the Ethernet server library
|
||||
// with the IP address and port you want to use
|
||||
// (port 80 is default for HTTP):
|
||||
Server server(80);
|
||||
|
||||
|
||||
//Sensor's memory register addresses:
|
||||
const int PRESSURE = 0x1F; //3 most significant bits of pressure
|
||||
const int PRESSURE_LSB = 0x20; //16 least significant bits of pressure
|
||||
const int TEMPERATURE = 0x21; //16 bit temperature reading
|
||||
|
||||
// pins used for the connection with the sensor
|
||||
// the others you need are controlled by the SPI library):
|
||||
const int dataReadyPin = 6;
|
||||
const int chipSelectPin = 7;
|
||||
|
||||
float temperature = 0.0;
|
||||
long pressure = 0;
|
||||
long lastReadingTime = 0;
|
||||
|
||||
void setup() {
|
||||
// start the SPI library:
|
||||
SPI.begin();
|
||||
|
||||
// start the Ethernet connection and the server:
|
||||
Ethernet.begin(mac, ip);
|
||||
server.begin();
|
||||
|
||||
// initalize the data ready and chip select pins:
|
||||
pinMode(dataReadyPin, INPUT);
|
||||
pinMode(chipSelectPin, OUTPUT);
|
||||
|
||||
Serial.begin(9600);
|
||||
|
||||
//Configure SCP1000 for low noise configuration:
|
||||
writeRegister(0x02, 0x2D);
|
||||
writeRegister(0x01, 0x03);
|
||||
writeRegister(0x03, 0x02);
|
||||
|
||||
// give the sensor and Ethernet shield time to set up:
|
||||
delay(1000);
|
||||
|
||||
//Set the sensor to high resolution mode tp start readings:
|
||||
writeRegister(0x03, 0x0A);
|
||||
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// check for a reading no more than once a second.
|
||||
if (millis() - lastReadingTime > 1000){
|
||||
// if there's a reading ready, read it:
|
||||
// don't do anything until the data ready pin is high:
|
||||
if (digitalRead(dataReadyPin) == HIGH) {
|
||||
getData();
|
||||
// timestamp the last time you got a reading:
|
||||
lastReadingTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
// listen for incoming Ethernet connections:
|
||||
listenForClients();
|
||||
}
|
||||
|
||||
|
||||
void getData() {
|
||||
Serial.println("Getting reading");
|
||||
//Read the temperature data
|
||||
int tempData = readRegister(0x21, 2);
|
||||
|
||||
// convert the temperature to celsius and display it:
|
||||
temperature = (float)tempData / 20.0;
|
||||
|
||||
//Read the pressure data highest 3 bits:
|
||||
byte pressureDataHigh = readRegister(0x1F, 1);
|
||||
pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0
|
||||
|
||||
//Read the pressure data lower 16 bits:
|
||||
unsigned int pressureDataLow = readRegister(0x20, 2);
|
||||
//combine the two parts into one 19-bit number:
|
||||
pressure = ((pressureDataHigh << 16) | pressureDataLow)/4;
|
||||
|
||||
Serial.print("Temperature: ");
|
||||
Serial.print(temperature);
|
||||
Serial.println(" degrees C");
|
||||
Serial.print("Pressure: " + String(pressure));
|
||||
Serial.println(" Pa");
|
||||
}
|
||||
|
||||
void listenForClients() {
|
||||
// listen for incoming clients
|
||||
Client client = server.available();
|
||||
if (client) {
|
||||
Serial.println("Got a client");
|
||||
// an http request ends with a blank line
|
||||
boolean currentLineIsBlank = true;
|
||||
while (client.connected()) {
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
// if you've gotten to the end of the line (received a newline
|
||||
// character) and the line is blank, the http request has ended,
|
||||
// so you can send a reply
|
||||
if (c == '\n' && currentLineIsBlank) {
|
||||
// send a standard http response header
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-Type: text/html");
|
||||
client.println();
|
||||
// print the current readings, in HTML format:
|
||||
client.print("Temperature: ");
|
||||
client.print(temperature);
|
||||
client.print(" degrees C");
|
||||
client.println("<br />");
|
||||
client.print("Pressure: " + String(pressure));
|
||||
client.print(" Pa");
|
||||
client.println("<br />");
|
||||
break;
|
||||
}
|
||||
if (c == '\n') {
|
||||
// you're starting a new line
|
||||
currentLineIsBlank = true;
|
||||
}
|
||||
else if (c != '\r') {
|
||||
// you've gotten a character on the current line
|
||||
currentLineIsBlank = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// give the web browser time to receive the data
|
||||
delay(1);
|
||||
// close the connection:
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Send a write command to SCP1000
|
||||
void writeRegister(byte registerName, byte registerValue) {
|
||||
// SCP1000 expects the register name in the upper 6 bits
|
||||
// of the byte:
|
||||
registerName <<= 2;
|
||||
// command (read or write) goes in the lower two bits:
|
||||
registerName |= 0b00000010; //Write command
|
||||
|
||||
// take the chip select low to select the device:
|
||||
digitalWrite(chipSelectPin, LOW);
|
||||
|
||||
SPI.transfer(registerName); //Send register location
|
||||
SPI.transfer(registerValue); //Send value to record into register
|
||||
|
||||
// take the chip select high to de-select:
|
||||
digitalWrite(chipSelectPin, HIGH);
|
||||
}
|
||||
|
||||
|
||||
//Read register from the SCP1000:
|
||||
unsigned int readRegister(byte registerName, int numBytes) {
|
||||
byte inByte = 0; // incoming from the SPI read
|
||||
unsigned int result = 0; // result to return
|
||||
|
||||
// SCP1000 expects the register name in the upper 6 bits
|
||||
// of the byte:
|
||||
registerName <<= 2;
|
||||
// command (read or write) goes in the lower two bits:
|
||||
registerName &= 0b11111100; //Read command
|
||||
|
||||
// take the chip select low to select the device:
|
||||
digitalWrite(chipSelectPin, LOW);
|
||||
// send the device the register you want to read:
|
||||
int command = SPI.transfer(registerName);
|
||||
// send a value of 0 to read the first byte returned:
|
||||
inByte = SPI.transfer(0x00);
|
||||
|
||||
result = inByte;
|
||||
// if there's more than one byte returned,
|
||||
// shift the first byte then get the second byte:
|
||||
if (numBytes > 1){
|
||||
result = inByte << 8;
|
||||
inByte = SPI.transfer(0x00);
|
||||
result = result |inByte;
|
||||
}
|
||||
// take the chip select high to de-select:
|
||||
digitalWrite(chipSelectPin, HIGH);
|
||||
// return the result:
|
||||
return(result);
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Chat Server
|
||||
|
||||
A simple server that distributes any incoming messages to all
|
||||
connected clients. To use telnet to your device's IP address and type.
|
||||
You can see the client's input in the serial monitor as well.
|
||||
Using an Arduino Wiznet Ethernet shield.
|
||||
|
||||
Circuit:
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
* Analog inputs attached to pins A0 through A5 (optional)
|
||||
|
||||
created 18 Dec 2009
|
||||
by David A. Mellis
|
||||
modified 10 August 2010
|
||||
by Tom Igoe
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network.
|
||||
// gateway and subnet are optional:
|
||||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = { 192,168,1, 177 };
|
||||
byte gateway[] = { 192,168,1, 1 };
|
||||
byte subnet[] = { 255, 255, 0, 0 };
|
||||
|
||||
// telnet defaults to port 23
|
||||
Server server(23);
|
||||
boolean gotAMessage = false; // whether or not you got a message from the client yet
|
||||
|
||||
void setup() {
|
||||
// initialize the ethernet device
|
||||
Ethernet.begin(mac, ip, gateway, subnet);
|
||||
// start listening for clients
|
||||
server.begin();
|
||||
// open the serial port
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// wait for a new client:
|
||||
Client client = server.available();
|
||||
|
||||
// when the client sends the first byte, say hello:
|
||||
if (client) {
|
||||
if (!gotAMessage) {
|
||||
Serial.println("We have a new client");
|
||||
client.println("Hello, client!");
|
||||
gotAMessage = true;
|
||||
}
|
||||
|
||||
// read the bytes incoming from the client:
|
||||
char thisChar = client.read();
|
||||
// echo the bytes back to the client:
|
||||
server.write(thisChar);
|
||||
// echo the bytes to the server as well:
|
||||
Serial.print(thisChar);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
Pachube sensor client
|
||||
|
||||
This sketch connects an analog sensor to Pachube (http://www.pachube.com)
|
||||
using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or
|
||||
the Adafruit Ethernet shield, either one will work, as long as it's got
|
||||
a Wiznet Ethernet module on board.
|
||||
|
||||
Circuit:
|
||||
* Analog sensor attached to analog in 0
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
|
||||
created 15 March 2010
|
||||
updated 4 Sep 2010
|
||||
by Tom Igoe
|
||||
|
||||
http://www.tigoe.net/pcomp/code/category/arduinowiring/873
|
||||
This code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// assign a MAC address for the ethernet controller.
|
||||
// fill in your address here:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
// assign an IP address for the controller:
|
||||
byte ip[] = {
|
||||
192,169,1,20 };
|
||||
byte gateway[] = {
|
||||
192,168,1,1};
|
||||
byte subnet[] = {
|
||||
255, 255, 255, 0 };
|
||||
|
||||
// The address of the server you want to connect to (pachube.com):
|
||||
byte server[] = {
|
||||
209,40,205,190 };
|
||||
|
||||
// initialize the library instance:
|
||||
Client client(server, 80);
|
||||
|
||||
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
|
||||
|
||||
void setup() {
|
||||
// start the ethernet connection and serial port:
|
||||
Ethernet.begin(mac, ip);
|
||||
Serial.begin(9600);
|
||||
// give the ethernet module time to boot up:
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// read the analog sensor:
|
||||
int sensorReading = analogRead(A0);
|
||||
|
||||
// if there's incoming data from the net connection.
|
||||
// send it out the serial port. This is for debugging
|
||||
// purposes only:
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
|
||||
// if there's no net connection, but there was one last time
|
||||
// through the loop, then stop the client:
|
||||
if (!client.connected() && lastConnected) {
|
||||
Serial.println();
|
||||
Serial.println("disconnecting.");
|
||||
client.stop();
|
||||
}
|
||||
|
||||
// if you're not connected, and ten seconds have passed since
|
||||
// your last connection, then connect again and send data:
|
||||
if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
|
||||
sendData(sensorReading);
|
||||
}
|
||||
// store the state of the connection for next time through
|
||||
// the loop:
|
||||
lastConnected = client.connected();
|
||||
}
|
||||
|
||||
// this method makes a HTTP connection to the server:
|
||||
void sendData(int thisData) {
|
||||
// if there's a successful connection:
|
||||
if (client.connect()) {
|
||||
Serial.println("connecting...");
|
||||
// send the HTTP PUT request.
|
||||
// fill in your feed address here:
|
||||
client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n");
|
||||
client.print("Host: www.pachube.com\n");
|
||||
// fill in your Pachube API key here:
|
||||
client.print("X-PachubeApiKey: YOUR_KEY_HERE\n");
|
||||
client.print("Content-Length: ");
|
||||
|
||||
// calculate the length of the sensor reading in bytes:
|
||||
int thisLength = getLength(thisData);
|
||||
client.println(thisLength, DEC);
|
||||
|
||||
// last pieces of the HTTP PUT request:
|
||||
client.print("Content-Type: text/csv\n");
|
||||
client.println("Connection: close\n");
|
||||
|
||||
// here's the actual content of the PUT request:
|
||||
client.println(thisData, DEC);
|
||||
|
||||
// note the time that the connection was made:
|
||||
lastConnectionTime = millis();
|
||||
}
|
||||
else {
|
||||
// if you couldn't make a connection:
|
||||
Serial.println("connection failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This method calculates the number of digits in the
|
||||
// sensor reading. Since each digit of the ASCII decimal
|
||||
// representation is a byte, the number of digits equals
|
||||
// the number of bytes:
|
||||
|
||||
int getLength(int someValue) {
|
||||
// there's at least one byte:
|
||||
int digits = 1;
|
||||
// continually divide the value by ten,
|
||||
// adding one to the digit count for each
|
||||
// time you divide, until you're at 0:
|
||||
int dividend = someValue /10;
|
||||
while (dividend > 0) {
|
||||
dividend = dividend /10;
|
||||
digits++;
|
||||
}
|
||||
// return the number of digits:
|
||||
return digits;
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
Pachube sensor client with Strings
|
||||
|
||||
This sketch connects an analog sensor to Pachube (http://www.pachube.com)
|
||||
using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or
|
||||
the Adafruit Ethernet shield, either one will work, as long as it's got
|
||||
a Wiznet Ethernet module on board.
|
||||
|
||||
This example uses the String library, which is part of the Arduino core from
|
||||
version 0019.
|
||||
|
||||
Circuit:
|
||||
* Analog sensor attached to analog in 0
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
|
||||
created 15 March 2010
|
||||
updated 4 Sep 2010
|
||||
by Tom Igoe
|
||||
|
||||
This code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// assign a MAC address for the ethernet controller.
|
||||
// fill in your address here:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
||||
// assign an IP address for the controller:
|
||||
byte ip[] = {
|
||||
192,169,1,20 };
|
||||
byte gateway[] = {
|
||||
192,168,1,1};
|
||||
byte subnet[] = {
|
||||
255, 255, 255, 0 };
|
||||
|
||||
// The address of the server you want to connect to (pachube.com):
|
||||
byte server[] = {
|
||||
209,40,205,190 };
|
||||
|
||||
// initialize the library instance:
|
||||
Client client(server, 80);
|
||||
|
||||
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
|
||||
|
||||
void setup() {
|
||||
// start the ethernet connection and serial port:
|
||||
Ethernet.begin(mac, ip);
|
||||
Serial.begin(9600);
|
||||
// give the ethernet module time to boot up:
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// read the analog sensor:
|
||||
int sensorReading = analogRead(A0);
|
||||
// convert the data to a String to send it:
|
||||
String dataString = String(sensorReading);
|
||||
|
||||
// you can append multiple readings to this String if your
|
||||
// pachube feed is set up to handle multiple values:
|
||||
int otherSensorReading = analogRead(A1);
|
||||
dataString += ",";
|
||||
dataString += String(otherSensorReading);
|
||||
|
||||
// if there's incoming data from the net connection.
|
||||
// send it out the serial port. This is for debugging
|
||||
// purposes only:
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
|
||||
// if there's no net connection, but there was one last time
|
||||
// through the loop, then stop the client:
|
||||
if (!client.connected() && lastConnected) {
|
||||
Serial.println();
|
||||
Serial.println("disconnecting.");
|
||||
client.stop();
|
||||
}
|
||||
|
||||
// if you're not connected, and ten seconds have passed since
|
||||
// your last connection, then connect again and send data:
|
||||
if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) {
|
||||
sendData(dataString);
|
||||
}
|
||||
// store the state of the connection for next time through
|
||||
// the loop:
|
||||
lastConnected = client.connected();
|
||||
}
|
||||
|
||||
// this method makes a HTTP connection to the server:
|
||||
void sendData(String thisData) {
|
||||
// if there's a successful connection:
|
||||
if (client.connect()) {
|
||||
Serial.println("connecting...");
|
||||
// send the HTTP PUT request.
|
||||
// fill in your feed address here:
|
||||
client.print("PUT /api/YOUR_FEED_HERE.csv HTTP/1.1\n");
|
||||
client.print("Host: www.pachube.com\n");
|
||||
// fill in your Pachube API key here:
|
||||
client.print("X-PachubeApiKey: YOUR_KEY_HERE\n");
|
||||
client.print("Content-Length: ");
|
||||
client.println(thisData.length(), DEC);
|
||||
|
||||
// last pieces of the HTTP PUT request:
|
||||
client.print("Content-Type: text/csv\n");
|
||||
client.println("Connection: close\n");
|
||||
|
||||
// here's the actual content of the PUT request:
|
||||
client.println(thisData);
|
||||
|
||||
// note the time that the connection was made:
|
||||
lastConnectionTime = millis();
|
||||
}
|
||||
else {
|
||||
// if you couldn't make a connection:
|
||||
Serial.println("connection failed");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
Telnet client
|
||||
|
||||
This sketch connects to a a telnet server (http://www.google.com)
|
||||
using an Arduino Wiznet Ethernet shield. You'll need a telnet server
|
||||
to test this with.
|
||||
Processing's ChatServer example (part of the network library) works well,
|
||||
running on port 10002. It can be found as part of the examples
|
||||
in the Processing application, available at
|
||||
http://processing.org/
|
||||
|
||||
Circuit:
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
|
||||
created 14 Sep 2010
|
||||
by Tom Igoe
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = {
|
||||
192,168,1,177 };
|
||||
|
||||
// Enter the IP address of the server you're connecting to:
|
||||
byte server[] = {
|
||||
1,1,1,1 };
|
||||
|
||||
// Initialize the Ethernet client library
|
||||
// with the IP address and port of the server
|
||||
// that you want to connect to (port 23 is default for telnet;
|
||||
// if you're using Processing's ChatServer, use port 10002):
|
||||
Client client(server, 10002);
|
||||
|
||||
void setup() {
|
||||
// start the Ethernet connection:
|
||||
Ethernet.begin(mac, ip);
|
||||
// start the serial library:
|
||||
Serial.begin(9600);
|
||||
// give the Ethernet shield a second to initialize:
|
||||
delay(1000);
|
||||
Serial.println("connecting...");
|
||||
|
||||
// if you get a connection, report back via serial:
|
||||
if (client.connect()) {
|
||||
Serial.println("connected");
|
||||
}
|
||||
else {
|
||||
// if you didn't get a connection to the server:
|
||||
Serial.println("connection failed");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// if there are incoming bytes available
|
||||
// from the server, read them and print them:
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
|
||||
// as long as there are bytes in the serial queue,
|
||||
// read them and send them out the socket if it's open:
|
||||
while (Serial.available() > 0) {
|
||||
char inChar = Serial.read();
|
||||
if (client.connected()) {
|
||||
client.print(inChar);
|
||||
}
|
||||
}
|
||||
|
||||
// if the server's disconnected, stop the client:
|
||||
if (!client.connected()) {
|
||||
Serial.println();
|
||||
Serial.println("disconnecting.");
|
||||
client.stop();
|
||||
// do nothing:
|
||||
while(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
UDPSendReceive.pde:
|
||||
This sketch receives UDP message strings, prints them to the serial port
|
||||
and sends an "acknowledge" string back to the sender
|
||||
|
||||
A Processing sketch is included at the end of file that can be used to send
|
||||
and received messages for testing with a computer.
|
||||
|
||||
created 21 Aug 2010
|
||||
by Michael Margolis
|
||||
|
||||
This code is in the public domain.
|
||||
*/
|
||||
|
||||
|
||||
#include <SPI.h> // needed for Arduino versions later than 0018
|
||||
#include <Ethernet.h>
|
||||
#include <Udp.h> // UDP library from: bjoern@cs.stanford.edu 12/30/2008
|
||||
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = {
|
||||
192,168,1,177 };
|
||||
|
||||
unsigned int localPort = 8888; // local port to listen on
|
||||
|
||||
// the next two variables are set when a packet is received
|
||||
byte remoteIp[4]; // holds received packet's originating IP
|
||||
unsigned int remotePort; // holds received packet's originating port
|
||||
|
||||
// buffers for receiving and sending data
|
||||
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
|
||||
char ReplyBuffer[] = "acknowledged"; // a string to send back
|
||||
|
||||
|
||||
void setup() {
|
||||
// start the Ethernet and UDP:
|
||||
Ethernet.begin(mac,ip);
|
||||
Udp.begin(localPort);
|
||||
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// if there's data available, read a packet
|
||||
int packetSize = Udp.available(); // note that this includes the UDP header
|
||||
if(packetSize)
|
||||
{
|
||||
packetSize = packetSize - 8; // subtract the 8 byte header
|
||||
Serial.print("Received packet of size ");
|
||||
Serial.println(packetSize);
|
||||
|
||||
// read the packet into packetBufffer and get the senders IP addr and port number
|
||||
Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort);
|
||||
Serial.println("Contents:");
|
||||
Serial.println(packetBuffer);
|
||||
|
||||
Udp.sendPacket( ReplyBuffer, remoteIp, remotePort);
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Processing sketch to run with this example
|
||||
=====================================================
|
||||
|
||||
// Processing UDP example to send and receive string data from Arduino
|
||||
// press any key to send the "Hello Arduino" message
|
||||
|
||||
|
||||
import hypermedia.net.*;
|
||||
|
||||
UDP udp; // define the UDP object
|
||||
|
||||
|
||||
void setup() {
|
||||
udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000
|
||||
//udp.log( true ); // <-- printout the connection activity
|
||||
udp.listen( true ); // and wait for incoming message
|
||||
}
|
||||
|
||||
void draw()
|
||||
{
|
||||
}
|
||||
|
||||
void keyPressed() {
|
||||
String ip = "192.168.1.177"; // the remote IP address
|
||||
int port = 8888; // the destination port
|
||||
|
||||
udp.send("Hello World", ip, port ); // the message to send
|
||||
|
||||
}
|
||||
|
||||
void receive( byte[] data ) { // <-- default handler
|
||||
//void receive( byte[] data, String ip, int port ) { // <-- extended handler
|
||||
|
||||
for(int i=0; i < data.length; i++)
|
||||
print(char(data[i]));
|
||||
println();
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
|
||||
Udp NTP Client
|
||||
|
||||
Get the time from a Network Time Protocol (NTP) time server
|
||||
Demonstrates use of UDP sendPacket and ReceivePacket
|
||||
For more on NTP time servers and the messages needed to communicate with them,
|
||||
see http://en.wikipedia.org/wiki/Network_Time_Protocol
|
||||
|
||||
created 4 Sep 2010
|
||||
by Michael Margolis
|
||||
modified 17 Sep 2010
|
||||
by Tom Igoe
|
||||
|
||||
This code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
#include <Udp.h>
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network:
|
||||
byte mac[] = {
|
||||
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = {
|
||||
192,168,1,177 };
|
||||
|
||||
|
||||
unsigned int localPort = 8888; // local port to listen for UDP packets
|
||||
|
||||
byte timeServer[] = {
|
||||
192, 43, 244, 18}; // time.nist.gov NTP server
|
||||
|
||||
const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message
|
||||
|
||||
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
|
||||
|
||||
void setup()
|
||||
{
|
||||
// start Ethernet and UDP
|
||||
Ethernet.begin(mac,ip);
|
||||
Udp.begin(localPort);
|
||||
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
sendNTPpacket(timeServer); // send an NTP packet to a time server
|
||||
|
||||
// wait to see if a reply is available
|
||||
delay(1000);
|
||||
if ( Udp.available() ) {
|
||||
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer
|
||||
|
||||
//the timestamp starts at byte 40 of the received packet and is four bytes,
|
||||
// or two words, long. First, esxtract the two words:
|
||||
|
||||
unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
|
||||
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
|
||||
// combine the four bytes (two words) into a long integer
|
||||
// this is NTP time (seconds since Jan 1 1900):
|
||||
unsigned long secsSince1900 = highWord << 16 | lowWord;
|
||||
Serial.print("Seconds since Jan 1 1900 = " );
|
||||
Serial.println(secsSince1900);
|
||||
|
||||
// now convert NTP time into everyday time:
|
||||
Serial.print("Unix time = ");
|
||||
// Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
|
||||
const unsigned long seventyYears = 2208988800UL;
|
||||
// subtract seventy years:
|
||||
unsigned long epoch = secsSince1900 - seventyYears;
|
||||
// print Unix time:
|
||||
Serial.println(epoch);
|
||||
|
||||
|
||||
// print the hour, minute and second:
|
||||
Serial.print("The UTC time is "); // UTC is the time at Greenwich Meridian (GMT)
|
||||
Serial.print((epoch % 86400L) / 3600); // print the hour (86400 equals secs per day)
|
||||
Serial.print(':');
|
||||
Serial.print((epoch % 3600) / 60); // print the minute (3600 equals secs per minute)
|
||||
Serial.print(':');
|
||||
Serial.println(epoch %60); // print the second
|
||||
}
|
||||
// wait ten seconds before asking for the time again
|
||||
delay(10000);
|
||||
}
|
||||
|
||||
// send an NTP request to the time server at the given address
|
||||
unsigned long sendNTPpacket(byte *address)
|
||||
{
|
||||
// set all bytes in the buffer to 0
|
||||
memset(packetBuffer, 0, NTP_PACKET_SIZE);
|
||||
// Initialize values needed to form NTP request
|
||||
// (see URL above for details on the packets)
|
||||
packetBuffer[0] = 0b11100011; // LI, Version, Mode
|
||||
packetBuffer[1] = 0; // Stratum, or type of clock
|
||||
packetBuffer[2] = 6; // Polling Interval
|
||||
packetBuffer[3] = 0xEC; // Peer Clock Precision
|
||||
// 8 bytes of zero for Root Delay & Root Dispersion
|
||||
packetBuffer[12] = 49;
|
||||
packetBuffer[13] = 0x4E;
|
||||
packetBuffer[14] = 49;
|
||||
packetBuffer[15] = 52;
|
||||
|
||||
// all NTP fields have been given values, now
|
||||
// you can send a packet requesting a timestamp:
|
||||
Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE, address, 123); //NTP requests are to port 123
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
Web client
|
||||
|
||||
This sketch connects to a website (http://www.google.com)
|
||||
using an Arduino Wiznet Ethernet shield.
|
||||
|
||||
Circuit:
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
|
||||
created 18 Dec 2009
|
||||
by David A. Mellis
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network:
|
||||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = { 192,168,1,177 };
|
||||
byte server[] = { 173,194,33,104 }; // Google
|
||||
|
||||
// Initialize the Ethernet client library
|
||||
// with the IP address and port of the server
|
||||
// that you want to connect to (port 80 is default for HTTP):
|
||||
Client client(server, 80);
|
||||
|
||||
void setup() {
|
||||
// start the Ethernet connection:
|
||||
Ethernet.begin(mac, ip);
|
||||
// start the serial library:
|
||||
Serial.begin(9600);
|
||||
// give the Ethernet shield a second to initialize:
|
||||
delay(1000);
|
||||
Serial.println("connecting...");
|
||||
|
||||
// if you get a connection, report back via serial:
|
||||
if (client.connect()) {
|
||||
Serial.println("connected");
|
||||
// Make a HTTP request:
|
||||
client.println("GET /search?q=arduino HTTP/1.0");
|
||||
client.println();
|
||||
}
|
||||
else {
|
||||
// kf you didn't get a connection to the server:
|
||||
Serial.println("connection failed");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// if there are incoming bytes available
|
||||
// from the server, read them and print them:
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
|
||||
// if the server's disconnected, stop the client:
|
||||
if (!client.connected()) {
|
||||
Serial.println();
|
||||
Serial.println("disconnecting.");
|
||||
client.stop();
|
||||
|
||||
// do nothing forevermore:
|
||||
for(;;)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
Web Server
|
||||
|
||||
A simple web server that shows the value of the analog input pins.
|
||||
using an Arduino Wiznet Ethernet shield.
|
||||
|
||||
Circuit:
|
||||
* Ethernet shield attached to pins 10, 11, 12, 13
|
||||
* Analog inputs attached to pins A0 through A5 (optional)
|
||||
|
||||
created 18 Dec 2009
|
||||
by David A. Mellis
|
||||
modified 4 Sep 2010
|
||||
by Tom Igoe
|
||||
|
||||
*/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Ethernet.h>
|
||||
|
||||
// Enter a MAC address and IP address for your controller below.
|
||||
// The IP address will be dependent on your local network:
|
||||
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
|
||||
byte ip[] = { 192,168,1, 177 };
|
||||
|
||||
// Initialize the Ethernet server library
|
||||
// with the IP address and port you want to use
|
||||
// (port 80 is default for HTTP):
|
||||
Server server(80);
|
||||
|
||||
void setup()
|
||||
{
|
||||
// start the Ethernet connection and the server:
|
||||
Ethernet.begin(mac, ip);
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// listen for incoming clients
|
||||
Client client = server.available();
|
||||
if (client) {
|
||||
// an http request ends with a blank line
|
||||
boolean currentLineIsBlank = true;
|
||||
while (client.connected()) {
|
||||
if (client.available()) {
|
||||
char c = client.read();
|
||||
// if you've gotten to the end of the line (received a newline
|
||||
// character) and the line is blank, the http request has ended,
|
||||
// so you can send a reply
|
||||
if (c == '\n' && currentLineIsBlank) {
|
||||
// send a standard http response header
|
||||
client.println("HTTP/1.1 200 OK");
|
||||
client.println("Content-Type: text/html");
|
||||
client.println();
|
||||
|
||||
// output the value of each analog input pin
|
||||
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
|
||||
client.print("analog input ");
|
||||
client.print(analogChannel);
|
||||
client.print(" is ");
|
||||
client.print(analogRead(analogChannel));
|
||||
client.println("<br />");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (c == '\n') {
|
||||
// you're starting a new line
|
||||
currentLineIsBlank = true;
|
||||
}
|
||||
else if (c != '\r') {
|
||||
// you've gotten a character on the current line
|
||||
currentLineIsBlank = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// give the web browser time to receive the data
|
||||
delay(1);
|
||||
// close the connection:
|
||||
client.stop();
|
||||
}
|
||||
}
|
30
arduino-0022-linux-x64/libraries/Ethernet/keywords.txt
Normal file
30
arduino-0022-linux-x64/libraries/Ethernet/keywords.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Ethernet
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Ethernet KEYWORD1
|
||||
Client KEYWORD1
|
||||
Server KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
status KEYWORD2
|
||||
connect KEYWORD2
|
||||
write KEYWORD2
|
||||
available KEYWORD2
|
||||
read KEYWORD2
|
||||
flush KEYWORD2
|
||||
stop KEYWORD2
|
||||
connected KEYWORD2
|
||||
begin KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
327
arduino-0022-linux-x64/libraries/Ethernet/utility/socket.cpp
Normal file
327
arduino-0022-linux-x64/libraries/Ethernet/utility/socket.cpp
Normal file
|
@ -0,0 +1,327 @@
|
|||
#include "w5100.h"
|
||||
#include "socket.h"
|
||||
|
||||
static uint16_t local_port;
|
||||
|
||||
/**
|
||||
* @brief This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it.
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag)
|
||||
{
|
||||
uint8_t ret;
|
||||
if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE))
|
||||
{
|
||||
close(s);
|
||||
W5100.writeSnMR(s, protocol | flag);
|
||||
if (port != 0) {
|
||||
W5100.writeSnPORT(s, port);
|
||||
}
|
||||
else {
|
||||
local_port++; // if don't set the source port, set local_port number.
|
||||
W5100.writeSnPORT(s, local_port);
|
||||
}
|
||||
|
||||
W5100.execCmdSn(s, Sock_OPEN);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function close the socket and parameter is "s" which represent the socket number
|
||||
*/
|
||||
void close(SOCKET s)
|
||||
{
|
||||
W5100.execCmdSn(s, Sock_CLOSE);
|
||||
W5100.writeSnIR(s, 0xFF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function established the connection for the channel in passive (server) mode. This function waits for the request from the peer.
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t listen(SOCKET s)
|
||||
{
|
||||
if (W5100.readSnSR(s) != SnSR::INIT)
|
||||
return 0;
|
||||
W5100.execCmdSn(s, Sock_LISTEN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function established the connection for the channel in Active (client) mode.
|
||||
* This function waits for the untill the connection is established.
|
||||
*
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port)
|
||||
{
|
||||
if
|
||||
(
|
||||
((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) ||
|
||||
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
|
||||
(port == 0x00)
|
||||
)
|
||||
return 0;
|
||||
|
||||
// set destination IP
|
||||
W5100.writeSnDIPR(s, addr);
|
||||
W5100.writeSnDPORT(s, port);
|
||||
W5100.execCmdSn(s, Sock_CONNECT);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function used for disconnect the socket and parameter is "s" which represent the socket number
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
void disconnect(SOCKET s)
|
||||
{
|
||||
W5100.execCmdSn(s, Sock_DISCON);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function used to send the data in TCP mode
|
||||
* @return 1 for success else 0.
|
||||
*/
|
||||
uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
uint8_t status=0;
|
||||
uint16_t ret=0;
|
||||
uint16_t freesize=0;
|
||||
|
||||
if (len > W5100.SSIZE)
|
||||
ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else
|
||||
ret = len;
|
||||
|
||||
// if freebuf is available, start.
|
||||
do
|
||||
{
|
||||
freesize = W5100.getTXFreeSize(s);
|
||||
status = W5100.readSnSR(s);
|
||||
if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT))
|
||||
{
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (freesize < ret);
|
||||
|
||||
// copy data
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
/* +2008.01 bj */
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
/* m2008.01 [bj] : reduce code */
|
||||
if ( W5100.readSnSR(s) == SnSR::CLOSED )
|
||||
{
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* +2008.01 bj */
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to receive the data in TCP mode.
|
||||
* It continues to wait for data as much as the application wants to receive.
|
||||
*
|
||||
* @return received data size for success else -1.
|
||||
*/
|
||||
uint16_t recv(SOCKET s, uint8_t *buf, uint16_t len)
|
||||
{
|
||||
uint16_t ret=0;
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
W5100.recv_data_processing(s, buf, len);
|
||||
W5100.execCmdSn(s, Sock_RECV);
|
||||
ret = len;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Returns the first byte in the receive queue (no checking)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
uint16_t peek(SOCKET s, uint8_t *buf)
|
||||
{
|
||||
W5100.recv_data_processing(s, buf, 1, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to send the data for other then TCP mode.
|
||||
* Unlike TCP transmission, The peer's destination address and the port is needed.
|
||||
*
|
||||
* @return This function return send data size for success else -1.
|
||||
*/
|
||||
uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port)
|
||||
{
|
||||
uint16_t ret=0;
|
||||
|
||||
if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else ret = len;
|
||||
|
||||
if
|
||||
(
|
||||
((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) ||
|
||||
((port == 0x00)) ||(ret == 0)
|
||||
)
|
||||
{
|
||||
/* +2008.01 [bj] : added return value */
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
W5100.writeSnDIPR(s, addr);
|
||||
W5100.writeSnDPORT(s, port);
|
||||
|
||||
// copy data
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
/* +2008.01 bj */
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
|
||||
{
|
||||
/* +2008.01 [bj]: clear interrupt */
|
||||
W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* +2008.01 bj */
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is an application I/F function which is used to receive the data in other then
|
||||
* TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well.
|
||||
*
|
||||
* @return This function return received data size for success else -1.
|
||||
*/
|
||||
uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port)
|
||||
{
|
||||
uint8_t head[8];
|
||||
uint16_t data_len=0;
|
||||
uint16_t ptr=0;
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
ptr = W5100.readSnRX_RD(s);
|
||||
switch (W5100.readSnMR(s) & 0x07)
|
||||
{
|
||||
case SnMR::UDP :
|
||||
W5100.read_data(s, (uint8_t *)ptr, head, 0x08);
|
||||
ptr += 8;
|
||||
// read peer's IP address, port number.
|
||||
addr[0] = head[0];
|
||||
addr[1] = head[1];
|
||||
addr[2] = head[2];
|
||||
addr[3] = head[3];
|
||||
*port = head[4];
|
||||
*port = (*port << 8) + head[5];
|
||||
data_len = head[6];
|
||||
data_len = (data_len << 8) + head[7];
|
||||
|
||||
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
|
||||
ptr += data_len;
|
||||
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
case SnMR::IPRAW :
|
||||
W5100.read_data(s, (uint8_t *)ptr, head, 0x06);
|
||||
ptr += 6;
|
||||
|
||||
addr[0] = head[0];
|
||||
addr[1] = head[1];
|
||||
addr[2] = head[2];
|
||||
addr[3] = head[3];
|
||||
data_len = head[4];
|
||||
data_len = (data_len << 8) + head[5];
|
||||
|
||||
W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy.
|
||||
ptr += data_len;
|
||||
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
case SnMR::MACRAW:
|
||||
W5100.read_data(s,(uint8_t*)ptr,head,2);
|
||||
ptr+=2;
|
||||
data_len = head[0];
|
||||
data_len = (data_len<<8) + head[1] - 2;
|
||||
|
||||
W5100.read_data(s,(uint8_t*) ptr,buf,data_len);
|
||||
ptr += data_len;
|
||||
W5100.writeSnRX_RD(s, ptr);
|
||||
break;
|
||||
|
||||
default :
|
||||
break;
|
||||
}
|
||||
W5100.execCmdSn(s, Sock_RECV);
|
||||
}
|
||||
return data_len;
|
||||
}
|
||||
|
||||
|
||||
uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len)
|
||||
{
|
||||
uint8_t status=0;
|
||||
uint16_t ret=0;
|
||||
|
||||
if (len > W5100.SSIZE)
|
||||
ret = W5100.SSIZE; // check size not to exceed MAX size.
|
||||
else
|
||||
ret = len;
|
||||
|
||||
if (ret == 0)
|
||||
return 0;
|
||||
|
||||
W5100.send_data_processing(s, (uint8_t *)buf, ret);
|
||||
W5100.execCmdSn(s, Sock_SEND);
|
||||
|
||||
while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )
|
||||
{
|
||||
status = W5100.readSnSR(s);
|
||||
if (W5100.readSnIR(s) & SnIR::TIMEOUT)
|
||||
{
|
||||
/* in case of igmp, if send fails, then socket closed */
|
||||
/* if you want change, remove this code. */
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
W5100.writeSnIR(s, SnIR::SEND_OK);
|
||||
return ret;
|
||||
}
|
||||
|
20
arduino-0022-linux-x64/libraries/Ethernet/utility/socket.h
Normal file
20
arduino-0022-linux-x64/libraries/Ethernet/utility/socket.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef _SOCKET_H_
|
||||
#define _SOCKET_H_
|
||||
|
||||
#include "w5100.h"
|
||||
|
||||
extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode)
|
||||
extern void close(SOCKET s); // Close socket
|
||||
extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection)
|
||||
extern void disconnect(SOCKET s); // disconnect the connection
|
||||
extern uint8_t listen(SOCKET s); // Establish TCP connection (Passive connection)
|
||||
extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP)
|
||||
extern uint16_t recv(SOCKET s, uint8_t * buf, uint16_t len); // Receive data (TCP)
|
||||
extern uint16_t peek(SOCKET s, uint8_t *buf);
|
||||
extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW)
|
||||
extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW)
|
||||
|
||||
extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len);
|
||||
|
||||
#endif
|
||||
/* _SOCKET_H_ */
|
182
arduino-0022-linux-x64/libraries/Ethernet/utility/w5100.cpp
Normal file
182
arduino-0022-linux-x64/libraries/Ethernet/utility/w5100.cpp
Normal file
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <avr/interrupt.h>
|
||||
|
||||
#include "w5100.h"
|
||||
|
||||
// W5100 controller instance
|
||||
W5100Class W5100;
|
||||
|
||||
#define TX_RX_MAX_BUF_SIZE 2048
|
||||
#define TX_BUF 0x1100
|
||||
#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE)
|
||||
|
||||
#define TXBUF_BASE 0x4000
|
||||
#define RXBUF_BASE 0x6000
|
||||
|
||||
void W5100Class::init(void)
|
||||
{
|
||||
delay(300);
|
||||
|
||||
SPI.begin();
|
||||
initSS();
|
||||
|
||||
writeMR(1<<RST);
|
||||
writeTMSR(0x55);
|
||||
writeRMSR(0x55);
|
||||
|
||||
for (int i=0; i<MAX_SOCK_NUM; i++) {
|
||||
SBASE[i] = TXBUF_BASE + SSIZE * i;
|
||||
RBASE[i] = RXBUF_BASE + RSIZE * i;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t W5100Class::getTXFreeSize(SOCKET s)
|
||||
{
|
||||
uint16_t val=0, val1=0;
|
||||
do {
|
||||
val1 = readSnTX_FSR(s);
|
||||
if (val1 != 0)
|
||||
val = readSnTX_FSR(s);
|
||||
}
|
||||
while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::getRXReceivedSize(SOCKET s)
|
||||
{
|
||||
uint16_t val=0,val1=0;
|
||||
do {
|
||||
val1 = readSnRX_RSR(s);
|
||||
if (val1 != 0)
|
||||
val = readSnRX_RSR(s);
|
||||
}
|
||||
while (val != val1);
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void W5100Class::send_data_processing(SOCKET s, uint8_t *data, uint16_t len)
|
||||
{
|
||||
uint16_t ptr = readSnTX_WR(s);
|
||||
|
||||
uint16_t offset = ptr & SMASK;
|
||||
uint16_t dstAddr = offset + SBASE[s];
|
||||
|
||||
if (offset + len > SSIZE)
|
||||
{
|
||||
// Wrap around circular buffer
|
||||
uint16_t size = SSIZE - offset;
|
||||
write(dstAddr, data, size);
|
||||
write(SBASE[s], data + size, len - size);
|
||||
}
|
||||
else {
|
||||
write(dstAddr, data, len);
|
||||
}
|
||||
|
||||
ptr += len;
|
||||
writeSnTX_WR(s, ptr);
|
||||
}
|
||||
|
||||
|
||||
void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek)
|
||||
{
|
||||
uint16_t ptr;
|
||||
ptr = readSnRX_RD(s);
|
||||
read_data(s, (uint8_t *)ptr, data, len);
|
||||
if (!peek)
|
||||
{
|
||||
ptr += len;
|
||||
writeSnRX_RD(s, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len)
|
||||
{
|
||||
uint16_t size;
|
||||
uint16_t src_mask;
|
||||
uint16_t src_ptr;
|
||||
|
||||
src_mask = (uint16_t)src & RMASK;
|
||||
src_ptr = RBASE[s] + src_mask;
|
||||
|
||||
if( (src_mask + len) > RSIZE )
|
||||
{
|
||||
size = RSIZE - src_mask;
|
||||
read(src_ptr, (uint8_t *)dst, size);
|
||||
dst += size;
|
||||
read(RBASE[s], (uint8_t *) dst, len - size);
|
||||
}
|
||||
else
|
||||
read(src_ptr, (uint8_t *) dst, len);
|
||||
}
|
||||
|
||||
|
||||
uint8_t W5100Class::write(uint16_t _addr, uint8_t _data)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0xF0);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
SPI.transfer(_data);
|
||||
resetSS();
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::write(uint16_t _addr, uint8_t *_buf, uint16_t _len)
|
||||
{
|
||||
for (int i=0; i<_len; i++)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0xF0);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
_addr++;
|
||||
SPI.transfer(_buf[i]);
|
||||
resetSS();
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
uint8_t W5100Class::read(uint16_t _addr)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0x0F);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
uint8_t _data = SPI.transfer(0);
|
||||
resetSS();
|
||||
return _data;
|
||||
}
|
||||
|
||||
uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len)
|
||||
{
|
||||
for (int i=0; i<_len; i++)
|
||||
{
|
||||
setSS();
|
||||
SPI.transfer(0x0F);
|
||||
SPI.transfer(_addr >> 8);
|
||||
SPI.transfer(_addr & 0xFF);
|
||||
_addr++;
|
||||
_buf[i] = SPI.transfer(0);
|
||||
resetSS();
|
||||
}
|
||||
return _len;
|
||||
}
|
||||
|
||||
void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) {
|
||||
// Send command to socket
|
||||
writeSnCR(s, _cmd);
|
||||
// Wait for command to complete
|
||||
while (readSnCR(s))
|
||||
;
|
||||
}
|
381
arduino-0022-linux-x64/libraries/Ethernet/utility/w5100.h
Normal file
381
arduino-0022-linux-x64/libraries/Ethernet/utility/w5100.h
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*
|
||||
* Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of either the GNU General Public License version 2
|
||||
* or the GNU Lesser General Public License version 2.1, both as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef W5100_H_INCLUDED
|
||||
#define W5100_H_INCLUDED
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
#include <SPI.h>
|
||||
|
||||
#define MAX_SOCK_NUM 4
|
||||
|
||||
typedef uint8_t SOCKET;
|
||||
|
||||
#define IDM_OR 0x8000
|
||||
#define IDM_AR0 0x8001
|
||||
#define IDM_AR1 0x8002
|
||||
#define IDM_DR 0x8003
|
||||
/*
|
||||
class MR {
|
||||
public:
|
||||
static const uint8_t RST = 0x80;
|
||||
static const uint8_t PB = 0x10;
|
||||
static const uint8_t PPPOE = 0x08;
|
||||
static const uint8_t LB = 0x04;
|
||||
static const uint8_t AI = 0x02;
|
||||
static const uint8_t IND = 0x01;
|
||||
};
|
||||
*/
|
||||
/*
|
||||
class IR {
|
||||
public:
|
||||
static const uint8_t CONFLICT = 0x80;
|
||||
static const uint8_t UNREACH = 0x40;
|
||||
static const uint8_t PPPoE = 0x20;
|
||||
static const uint8_t SOCK0 = 0x01;
|
||||
static const uint8_t SOCK1 = 0x02;
|
||||
static const uint8_t SOCK2 = 0x04;
|
||||
static const uint8_t SOCK3 = 0x08;
|
||||
static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); };
|
||||
};
|
||||
*/
|
||||
|
||||
class SnMR {
|
||||
public:
|
||||
static const uint8_t CLOSE = 0x00;
|
||||
static const uint8_t TCP = 0x01;
|
||||
static const uint8_t UDP = 0x02;
|
||||
static const uint8_t IPRAW = 0x03;
|
||||
static const uint8_t MACRAW = 0x04;
|
||||
static const uint8_t PPPOE = 0x05;
|
||||
static const uint8_t ND = 0x20;
|
||||
static const uint8_t MULTI = 0x80;
|
||||
};
|
||||
|
||||
enum SockCMD {
|
||||
Sock_OPEN = 0x01,
|
||||
Sock_LISTEN = 0x02,
|
||||
Sock_CONNECT = 0x04,
|
||||
Sock_DISCON = 0x08,
|
||||
Sock_CLOSE = 0x10,
|
||||
Sock_SEND = 0x20,
|
||||
Sock_SEND_MAC = 0x21,
|
||||
Sock_SEND_KEEP = 0x22,
|
||||
Sock_RECV = 0x40
|
||||
};
|
||||
|
||||
/*class SnCmd {
|
||||
public:
|
||||
static const uint8_t OPEN = 0x01;
|
||||
static const uint8_t LISTEN = 0x02;
|
||||
static const uint8_t CONNECT = 0x04;
|
||||
static const uint8_t DISCON = 0x08;
|
||||
static const uint8_t CLOSE = 0x10;
|
||||
static const uint8_t SEND = 0x20;
|
||||
static const uint8_t SEND_MAC = 0x21;
|
||||
static const uint8_t SEND_KEEP = 0x22;
|
||||
static const uint8_t RECV = 0x40;
|
||||
};
|
||||
*/
|
||||
|
||||
class SnIR {
|
||||
public:
|
||||
static const uint8_t SEND_OK = 0x10;
|
||||
static const uint8_t TIMEOUT = 0x08;
|
||||
static const uint8_t RECV = 0x04;
|
||||
static const uint8_t DISCON = 0x02;
|
||||
static const uint8_t CON = 0x01;
|
||||
};
|
||||
|
||||
class SnSR {
|
||||
public:
|
||||
static const uint8_t CLOSED = 0x00;
|
||||
static const uint8_t INIT = 0x13;
|
||||
static const uint8_t LISTEN = 0x14;
|
||||
static const uint8_t SYNSENT = 0x15;
|
||||
static const uint8_t SYNRECV = 0x16;
|
||||
static const uint8_t ESTABLISHED = 0x17;
|
||||
static const uint8_t FIN_WAIT = 0x18;
|
||||
static const uint8_t CLOSING = 0x1A;
|
||||
static const uint8_t TIME_WAIT = 0x1B;
|
||||
static const uint8_t CLOSE_WAIT = 0x1C;
|
||||
static const uint8_t LAST_ACK = 0x1D;
|
||||
static const uint8_t UDP = 0x22;
|
||||
static const uint8_t IPRAW = 0x32;
|
||||
static const uint8_t MACRAW = 0x42;
|
||||
static const uint8_t PPPOE = 0x5F;
|
||||
};
|
||||
|
||||
class IPPROTO {
|
||||
public:
|
||||
static const uint8_t IP = 0;
|
||||
static const uint8_t ICMP = 1;
|
||||
static const uint8_t IGMP = 2;
|
||||
static const uint8_t GGP = 3;
|
||||
static const uint8_t TCP = 6;
|
||||
static const uint8_t PUP = 12;
|
||||
static const uint8_t UDP = 17;
|
||||
static const uint8_t IDP = 22;
|
||||
static const uint8_t ND = 77;
|
||||
static const uint8_t RAW = 255;
|
||||
};
|
||||
|
||||
class W5100Class {
|
||||
|
||||
public:
|
||||
void init();
|
||||
|
||||
/**
|
||||
* @brief This function is being used for copy the data form Receive buffer of the chip to application buffer.
|
||||
*
|
||||
* It calculate the actual physical address where one has to read
|
||||
* the data from Receive buffer. Here also take care of the condition while it exceed
|
||||
* the Rx memory uper-bound of socket.
|
||||
*/
|
||||
void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief This function is being called by send() and sendto() function also.
|
||||
*
|
||||
* This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer
|
||||
* register. User should read upper byte first and lower byte later to get proper value.
|
||||
*/
|
||||
void send_data_processing(SOCKET s, uint8_t *data, uint16_t len);
|
||||
|
||||
/**
|
||||
* @brief This function is being called by recv() also.
|
||||
*
|
||||
* This function read the Rx read pointer register
|
||||
* and after copy the data from receive buffer update the Rx write pointer register.
|
||||
* User should read upper byte first and lower byte later to get proper value.
|
||||
*/
|
||||
void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0);
|
||||
|
||||
inline void setGatewayIp(uint8_t *_addr);
|
||||
inline void getGatewayIp(uint8_t *_addr);
|
||||
|
||||
inline void setSubnetMask(uint8_t *_addr);
|
||||
inline void getSubnetMask(uint8_t *_addr);
|
||||
|
||||
inline void setMACAddress(uint8_t * addr);
|
||||
inline void getMACAddress(uint8_t * addr);
|
||||
|
||||
inline void setIPAddress(uint8_t * addr);
|
||||
inline void getIPAddress(uint8_t * addr);
|
||||
|
||||
inline void setRetransmissionTime(uint16_t timeout);
|
||||
inline void setRetransmissionCount(uint8_t _retry);
|
||||
|
||||
void execCmdSn(SOCKET s, SockCMD _cmd);
|
||||
|
||||
uint16_t getTXFreeSize(SOCKET s);
|
||||
uint16_t getRXReceivedSize(SOCKET s);
|
||||
|
||||
|
||||
// W5100 Registers
|
||||
// ---------------
|
||||
private:
|
||||
static uint8_t write(uint16_t _addr, uint8_t _data);
|
||||
static uint16_t write(uint16_t addr, uint8_t *buf, uint16_t len);
|
||||
static uint8_t read(uint16_t addr);
|
||||
static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len);
|
||||
|
||||
#define __GP_REGISTER8(name, address) \
|
||||
static inline void write##name(uint8_t _data) { \
|
||||
write(address, _data); \
|
||||
} \
|
||||
static inline uint8_t read##name() { \
|
||||
return read(address); \
|
||||
}
|
||||
#define __GP_REGISTER16(name, address) \
|
||||
static void write##name(uint16_t _data) { \
|
||||
write(address, _data >> 8); \
|
||||
write(address+1, _data & 0xFF); \
|
||||
} \
|
||||
static uint16_t read##name() { \
|
||||
uint16_t res = read(address); \
|
||||
res = (res << 8) + read(address + 1); \
|
||||
return res; \
|
||||
}
|
||||
#define __GP_REGISTER_N(name, address, size) \
|
||||
static uint16_t write##name(uint8_t *_buff) { \
|
||||
return write(address, _buff, size); \
|
||||
} \
|
||||
static uint16_t read##name(uint8_t *_buff) { \
|
||||
return read(address, _buff, size); \
|
||||
}
|
||||
|
||||
public:
|
||||
__GP_REGISTER8 (MR, 0x0000); // Mode
|
||||
__GP_REGISTER_N(GAR, 0x0001, 4); // Gateway IP address
|
||||
__GP_REGISTER_N(SUBR, 0x0005, 4); // Subnet mask address
|
||||
__GP_REGISTER_N(SHAR, 0x0009, 6); // Source MAC address
|
||||
__GP_REGISTER_N(SIPR, 0x000F, 4); // Source IP address
|
||||
__GP_REGISTER8 (IR, 0x0015); // Interrupt
|
||||
__GP_REGISTER8 (IMR, 0x0016); // Interrupt Mask
|
||||
__GP_REGISTER16(RTR, 0x0017); // Timeout address
|
||||
__GP_REGISTER8 (RCR, 0x0019); // Retry count
|
||||
__GP_REGISTER8 (RMSR, 0x001A); // Receive memory size
|
||||
__GP_REGISTER8 (TMSR, 0x001B); // Transmit memory size
|
||||
__GP_REGISTER8 (PATR, 0x001C); // Authentication type address in PPPoE mode
|
||||
__GP_REGISTER8 (PTIMER, 0x0028); // PPP LCP Request Timer
|
||||
__GP_REGISTER8 (PMAGIC, 0x0029); // PPP LCP Magic Number
|
||||
__GP_REGISTER_N(UIPR, 0x002A, 4); // Unreachable IP address in UDP mode
|
||||
__GP_REGISTER16(UPORT, 0x002E); // Unreachable Port address in UDP mode
|
||||
|
||||
#undef __GP_REGISTER8
|
||||
#undef __GP_REGISTER16
|
||||
#undef __GP_REGISTER_N
|
||||
|
||||
// W5100 Socket registers
|
||||
// ----------------------
|
||||
private:
|
||||
static inline uint8_t readSn(SOCKET _s, uint16_t _addr);
|
||||
static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data);
|
||||
static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
|
||||
static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len);
|
||||
|
||||
static const uint16_t CH_BASE = 0x0400;
|
||||
static const uint16_t CH_SIZE = 0x0100;
|
||||
|
||||
#define __SOCKET_REGISTER8(name, address) \
|
||||
static inline void write##name(SOCKET _s, uint8_t _data) { \
|
||||
writeSn(_s, address, _data); \
|
||||
} \
|
||||
static inline uint8_t read##name(SOCKET _s) { \
|
||||
return readSn(_s, address); \
|
||||
}
|
||||
#define __SOCKET_REGISTER16(name, address) \
|
||||
static void write##name(SOCKET _s, uint16_t _data) { \
|
||||
writeSn(_s, address, _data >> 8); \
|
||||
writeSn(_s, address+1, _data & 0xFF); \
|
||||
} \
|
||||
static uint16_t read##name(SOCKET _s) { \
|
||||
uint16_t res = readSn(_s, address); \
|
||||
res = (res << 8) + readSn(_s, address + 1); \
|
||||
return res; \
|
||||
}
|
||||
#define __SOCKET_REGISTER_N(name, address, size) \
|
||||
static uint16_t write##name(SOCKET _s, uint8_t *_buff) { \
|
||||
return writeSn(_s, address, _buff, size); \
|
||||
} \
|
||||
static uint16_t read##name(SOCKET _s, uint8_t *_buff) { \
|
||||
return readSn(_s, address, _buff, size); \
|
||||
}
|
||||
|
||||
public:
|
||||
__SOCKET_REGISTER8(SnMR, 0x0000) // Mode
|
||||
__SOCKET_REGISTER8(SnCR, 0x0001) // Command
|
||||
__SOCKET_REGISTER8(SnIR, 0x0002) // Interrupt
|
||||
__SOCKET_REGISTER8(SnSR, 0x0003) // Status
|
||||
__SOCKET_REGISTER16(SnPORT, 0x0004) // Source Port
|
||||
__SOCKET_REGISTER_N(SnDHAR, 0x0006, 6) // Destination Hardw Addr
|
||||
__SOCKET_REGISTER_N(SnDIPR, 0x000C, 4) // Destination IP Addr
|
||||
__SOCKET_REGISTER16(SnDPORT, 0x0010) // Destination Port
|
||||
__SOCKET_REGISTER16(SnMSSR, 0x0012) // Max Segment Size
|
||||
__SOCKET_REGISTER8(SnPROTO, 0x0014) // Protocol in IP RAW Mode
|
||||
__SOCKET_REGISTER8(SnTOS, 0x0015) // IP TOS
|
||||
__SOCKET_REGISTER8(SnTTL, 0x0016) // IP TTL
|
||||
__SOCKET_REGISTER16(SnTX_FSR, 0x0020) // TX Free Size
|
||||
__SOCKET_REGISTER16(SnTX_RD, 0x0022) // TX Read Pointer
|
||||
__SOCKET_REGISTER16(SnTX_WR, 0x0024) // TX Write Pointer
|
||||
__SOCKET_REGISTER16(SnRX_RSR, 0x0026) // RX Free Size
|
||||
__SOCKET_REGISTER16(SnRX_RD, 0x0028) // RX Read Pointer
|
||||
__SOCKET_REGISTER16(SnRX_WR, 0x002A) // RX Write Pointer (supported?)
|
||||
|
||||
#undef __SOCKET_REGISTER8
|
||||
#undef __SOCKET_REGISTER16
|
||||
#undef __SOCKET_REGISTER_N
|
||||
|
||||
|
||||
private:
|
||||
static const uint8_t RST = 7; // Reset BIT
|
||||
|
||||
static const int SOCKETS = 4;
|
||||
static const uint16_t SMASK = 0x07FF; // Tx buffer MASK
|
||||
static const uint16_t RMASK = 0x07FF; // Rx buffer MASK
|
||||
public:
|
||||
static const uint16_t SSIZE = 2048; // Max Tx buffer size
|
||||
private:
|
||||
static const uint16_t RSIZE = 2048; // Max Rx buffer size
|
||||
uint16_t SBASE[SOCKETS]; // Tx buffer base address
|
||||
uint16_t RBASE[SOCKETS]; // Rx buffer base address
|
||||
|
||||
private:
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
inline static void initSS() { DDRB |= _BV(4); };
|
||||
inline static void setSS() { PORTB &= ~_BV(4); };
|
||||
inline static void resetSS() { PORTB |= _BV(4); };
|
||||
#else
|
||||
inline static void initSS() { DDRB |= _BV(2); };
|
||||
inline static void setSS() { PORTB &= ~_BV(2); };
|
||||
inline static void resetSS() { PORTB |= _BV(2); };
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
extern W5100Class W5100;
|
||||
|
||||
uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) {
|
||||
return read(CH_BASE + _s * CH_SIZE + _addr);
|
||||
}
|
||||
|
||||
uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) {
|
||||
return write(CH_BASE + _s * CH_SIZE + _addr, _data);
|
||||
}
|
||||
|
||||
uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
|
||||
return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
|
||||
}
|
||||
|
||||
uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) {
|
||||
return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len);
|
||||
}
|
||||
|
||||
void W5100Class::getGatewayIp(uint8_t *_addr) {
|
||||
readGAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setGatewayIp(uint8_t *_addr) {
|
||||
writeGAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getSubnetMask(uint8_t *_addr) {
|
||||
readSUBR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setSubnetMask(uint8_t *_addr) {
|
||||
writeSUBR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getMACAddress(uint8_t *_addr) {
|
||||
readSHAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setMACAddress(uint8_t *_addr) {
|
||||
writeSHAR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::getIPAddress(uint8_t *_addr) {
|
||||
readSIPR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setIPAddress(uint8_t *_addr) {
|
||||
writeSIPR(_addr);
|
||||
}
|
||||
|
||||
void W5100Class::setRetransmissionTime(uint16_t _timeout) {
|
||||
writeRTR(_timeout);
|
||||
}
|
||||
|
||||
void W5100Class::setRetransmissionCount(uint8_t _retry) {
|
||||
writeRCR(_retry);
|
||||
}
|
||||
|
||||
#endif
|
335
arduino-0022-linux-x64/libraries/Firmata/Boards.h
Normal file
335
arduino-0022-linux-x64/libraries/Firmata/Boards.h
Normal file
|
@ -0,0 +1,335 @@
|
|||
/* Boards.h - Hardware Abstraction Layer for Firmata library */
|
||||
|
||||
#ifndef Firmata_Boards_h
|
||||
#define Firmata_Boards_h
|
||||
|
||||
#include <WProgram.h> // for digitalRead, digitalWrite, etc
|
||||
|
||||
// Normally Servo.h must be included before Firmata.h (which then includes
|
||||
// this file). If Servo.h wasn't included, this allows the code to still
|
||||
// compile, but without support for any Servos. Hopefully that's what the
|
||||
// user intended by not including Servo.h
|
||||
#ifndef MAX_SERVOS
|
||||
#define MAX_SERVOS 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
Firmata Hardware Abstraction Layer
|
||||
|
||||
Firmata is built on top of the hardware abstraction functions of Arduino,
|
||||
specifically digitalWrite, digitalRead, analogWrite, analogRead, and
|
||||
pinMode. While these functions offer simple integer pin numbers, Firmata
|
||||
needs more information than is provided by Arduino. This file provides
|
||||
all other hardware specific details. To make Firmata support a new board,
|
||||
only this file should require editing.
|
||||
|
||||
The key concept is every "pin" implemented by Firmata may be mapped to
|
||||
any pin as implemented by Arduino. Usually a simple 1-to-1 mapping is
|
||||
best, but such mapping should not be assumed. This hardware abstraction
|
||||
layer allows Firmata to implement any number of pins which map onto the
|
||||
Arduino implemented pins in almost any arbitrary way.
|
||||
|
||||
|
||||
General Constants:
|
||||
|
||||
These constants provide basic information Firmata requires.
|
||||
|
||||
TOTAL_PINS: The total number of pins Firmata implemented by Firmata.
|
||||
Usually this will match the number of pins the Arduino functions
|
||||
implement, including any pins pins capable of analog or digital.
|
||||
However, Firmata may implement any number of pins. For example,
|
||||
on Arduino Mini with 8 analog inputs, 6 of these may be used
|
||||
for digital functions, and 2 are analog only. On such boards,
|
||||
Firmata can implement more pins than Arduino's pinMode()
|
||||
function, in order to accommodate those special pins. The
|
||||
Firmata protocol supports a maximum of 128 pins, so this
|
||||
constant must not exceed 128.
|
||||
|
||||
TOTAL_ANALOG_PINS: The total number of analog input pins implemented.
|
||||
The Firmata protocol allows up to 16 analog inputs, accessed
|
||||
using offsets 0 to 15. Because Firmata presents the analog
|
||||
inputs using different offsets than the actual pin numbers
|
||||
(a legacy of Arduino's analogRead function, and the way the
|
||||
analog input capable pins are physically labeled on all
|
||||
Arduino boards), the total number of analog input signals
|
||||
must be specified. 16 is the maximum.
|
||||
|
||||
VERSION_BLINK_PIN: When Firmata starts up, it will blink the version
|
||||
number. This constant is the Arduino pin number where a
|
||||
LED is connected.
|
||||
|
||||
|
||||
Pin Mapping Macros:
|
||||
|
||||
These macros provide the mapping between pins as implemented by
|
||||
Firmata protocol and the actual pin numbers used by the Arduino
|
||||
functions. Even though such mappings are often simple, pin
|
||||
numbers received by Firmata protocol should always be used as
|
||||
input to these macros, and the result of the macro should be
|
||||
used with with any Arduino function.
|
||||
|
||||
When Firmata is extended to support a new pin mode or feature,
|
||||
a pair of macros should be added and used for all hardware
|
||||
access. For simple 1:1 mapping, these macros add no actual
|
||||
overhead, yet their consistent use allows source code which
|
||||
uses them consistently to be easily adapted to all other boards
|
||||
with different requirements.
|
||||
|
||||
IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero
|
||||
if a pin as implemented by Firmata corresponds to a pin
|
||||
that actually implements the named feature.
|
||||
|
||||
PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as
|
||||
implemented by Firmata to the pin numbers needed as inputs
|
||||
to the Arduino functions. The corresponding IS_PIN macro
|
||||
should always be tested before using a PIN_TO macro, so
|
||||
these macros only need to handle valid Firmata pin
|
||||
numbers for the named feature.
|
||||
|
||||
|
||||
Port Access Inline Funtions:
|
||||
|
||||
For efficiency, Firmata protocol provides access to digital
|
||||
input and output pins grouped by 8 bit ports. When these
|
||||
groups of 8 correspond to actual 8 bit ports as implemented
|
||||
by the hardware, these inline functions can provide high
|
||||
speed direct port access. Otherwise, a default implementation
|
||||
using 8 calls to digitalWrite or digitalRead is used.
|
||||
|
||||
When porting Firmata to a new board, it is recommended to
|
||||
use the default functions first and focus only on the constants
|
||||
and macros above. When those are working, if optimized port
|
||||
access is desired, these inline functions may be extended.
|
||||
The recommended approach defines a symbol indicating which
|
||||
optimization to use, and then conditional complication is
|
||||
used within these functions.
|
||||
|
||||
readPort(port, bitmask): Read an 8 bit port, returning the value.
|
||||
port: The port number, Firmata pins port*8 to port*8+7
|
||||
bitmask: The actual pins to read, indicated by 1 bits.
|
||||
|
||||
writePort(port, value, bitmask): Write an 8 bit port.
|
||||
port: The port number, Firmata pins port*8 to port*8+7
|
||||
value: The 8 bit value to write
|
||||
bitmask: The actual pins to write, indicated by 1 bits.
|
||||
*/
|
||||
|
||||
/*==============================================================================
|
||||
* Board Specific Configuration
|
||||
*============================================================================*/
|
||||
|
||||
// Arduino Duemilanove, Diecimila, and NG
|
||||
#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 24 // 14 digital + 2 unused + 8 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 23)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 16)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
#define ARDUINO_PINOUT_OPTIMIZE 1
|
||||
|
||||
|
||||
// old Arduinos
|
||||
#elif defined(__AVR_ATmega8__)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 22 // 14 digital + 2 unused + 6 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21))
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 21)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 16)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
#define ARDUINO_PINOUT_OPTIMIZE 1
|
||||
|
||||
|
||||
// Arduino Mega
|
||||
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
#define TOTAL_ANALOG_PINS 16
|
||||
#define TOTAL_PINS 70 // 54 digital + 16 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 54 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 54)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Wiring
|
||||
#elif defined(__AVR_ATmega128__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 51
|
||||
#define VERSION_BLINK_PIN 48
|
||||
// TODO: hardware abstraction for wiring board
|
||||
|
||||
|
||||
// Teensy 1.0
|
||||
#elif defined(__AVR_AT90USB162__)
|
||||
#define TOTAL_ANALOG_PINS 0
|
||||
#define TOTAL_PINS 21 // 21 digital + no analog
|
||||
#define VERSION_BLINK_PIN 6
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) (0)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (0)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy 2.0
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#define TOTAL_ANALOG_PINS 12
|
||||
#define TOTAL_PINS 25 // 11 digital + 12 analog
|
||||
#define VERSION_BLINK_PIN 11
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 11 && (p) <= 22)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) (((p)<22)?21-(p):11)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Teensy++ 1.0 and 2.0
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 46 // 38 digital + 8 analog
|
||||
#define VERSION_BLINK_PIN 6
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 38 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 38)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) (p)
|
||||
|
||||
|
||||
// Sanguino
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
#define TOTAL_ANALOG_PINS 8
|
||||
#define TOTAL_PINS 32 // 24 digital + 8 analog
|
||||
#define VERSION_BLINK_PIN 0
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 24 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 24)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// Illuminato
|
||||
#elif defined(__AVR_ATmega645__)
|
||||
#define TOTAL_ANALOG_PINS 6
|
||||
#define TOTAL_PINS 42 // 36 digital + 6 analog
|
||||
#define VERSION_BLINK_PIN 13
|
||||
#define IS_PIN_DIGITAL(p) ((p) >= 2 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_ANALOG(p) ((p) >= 36 && (p) < TOTAL_PINS)
|
||||
#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p)
|
||||
#define IS_PIN_SERVO(p) ((p) >= 0 && (p) < MAX_SERVOS)
|
||||
#define IS_PIN_I2C(p) (0)
|
||||
#define PIN_TO_DIGITAL(p) (p)
|
||||
#define PIN_TO_ANALOG(p) ((p) - 36)
|
||||
#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p)
|
||||
#define PIN_TO_SERVO(p) ((p) - 2)
|
||||
|
||||
|
||||
// anything else
|
||||
#else
|
||||
#error "Please edit Boards.h with a hardware abstraction for this board"
|
||||
#endif
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* readPort() - Read an 8 bit port
|
||||
*============================================================================*/
|
||||
|
||||
static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused));
|
||||
static inline unsigned char readPort(byte port, byte bitmask)
|
||||
{
|
||||
#if defined(ARDUINO_PINOUT_OPTIMIZE)
|
||||
if (port == 0) return PIND & B11111100 & bitmask; // ignore Rx/Tx 0/1
|
||||
if (port == 1) return PINB & B00111111 & bitmask; // pins 8-13 (14,15 are disabled for the crystal)
|
||||
if (port == 2) return PINC & bitmask;
|
||||
return 0;
|
||||
#else
|
||||
unsigned char out=0, pin=port*8;
|
||||
if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01;
|
||||
if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02;
|
||||
if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04;
|
||||
if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08;
|
||||
if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10;
|
||||
if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20;
|
||||
if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40;
|
||||
if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80;
|
||||
return out;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* writePort() - Write an 8 bit port, only touch pins specified by a bitmask
|
||||
*============================================================================*/
|
||||
|
||||
static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused));
|
||||
static inline unsigned char writePort(byte port, byte value, byte bitmask)
|
||||
{
|
||||
#if defined(ARDUINO_PINOUT_OPTIMIZE)
|
||||
if (port == 0) {
|
||||
bitmask = bitmask & 0xFC; // Tx & Rx pins
|
||||
cli();
|
||||
PORTD = (PORTD & ~bitmask) | (bitmask & value);
|
||||
sei();
|
||||
} else if (port == 1) {
|
||||
cli();
|
||||
PORTB = (PORTB & ~bitmask) | (bitmask & value);
|
||||
sei();
|
||||
} else if (port == 2) {
|
||||
cli();
|
||||
PORTC = (PORTC & ~bitmask) | (bitmask & value);
|
||||
sei();
|
||||
}
|
||||
#else
|
||||
byte pin=port*8;
|
||||
if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01));
|
||||
if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02));
|
||||
if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04));
|
||||
if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08));
|
||||
if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10));
|
||||
if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20));
|
||||
if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40));
|
||||
if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef TOTAL_PORTS
|
||||
#define TOTAL_PORTS ((TOTAL_PINS + 7) / 8)
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* Firmata_Boards_h */
|
||||
|
442
arduino-0022-linux-x64/libraries/Firmata/Firmata.cpp
Normal file
442
arduino-0022-linux-x64/libraries/Firmata/Firmata.cpp
Normal file
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
Firmata.cpp - Firmata library
|
||||
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
//******************************************************************************
|
||||
//* Includes
|
||||
//******************************************************************************
|
||||
|
||||
#include "WProgram.h"
|
||||
#include "HardwareSerial.h"
|
||||
#include "Firmata.h"
|
||||
|
||||
extern "C" {
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Support Functions
|
||||
//******************************************************************************
|
||||
|
||||
void sendValueAsTwo7bitBytes(int value)
|
||||
{
|
||||
Serial.print(value & B01111111, BYTE); // LSB
|
||||
Serial.print(value >> 7 & B01111111, BYTE); // MSB
|
||||
}
|
||||
|
||||
void startSysex(void)
|
||||
{
|
||||
Serial.print(START_SYSEX, BYTE);
|
||||
}
|
||||
|
||||
void endSysex(void)
|
||||
{
|
||||
Serial.print(END_SYSEX, BYTE);
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Constructors
|
||||
//******************************************************************************
|
||||
|
||||
FirmataClass::FirmataClass(void)
|
||||
{
|
||||
firmwareVersionCount = 0;
|
||||
systemReset();
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
//* Public Methods
|
||||
//******************************************************************************
|
||||
|
||||
/* begin method for overriding default serial bitrate */
|
||||
void FirmataClass::begin(void)
|
||||
{
|
||||
begin(57600);
|
||||
}
|
||||
|
||||
/* begin method for overriding default serial bitrate */
|
||||
void FirmataClass::begin(long speed)
|
||||
{
|
||||
#if defined(__AVR_ATmega128__) // Wiring
|
||||
Serial.begin((uint32_t)speed);
|
||||
#else
|
||||
Serial.begin(speed);
|
||||
#endif
|
||||
blinkVersion();
|
||||
delay(300);
|
||||
printVersion();
|
||||
printFirmwareVersion();
|
||||
}
|
||||
|
||||
// output the protocol version message to the serial port
|
||||
void FirmataClass::printVersion(void) {
|
||||
Serial.print(REPORT_VERSION, BYTE);
|
||||
Serial.print(FIRMATA_MAJOR_VERSION, BYTE);
|
||||
Serial.print(FIRMATA_MINOR_VERSION, BYTE);
|
||||
}
|
||||
|
||||
void FirmataClass::blinkVersion(void)
|
||||
{
|
||||
// flash the pin with the protocol version
|
||||
pinMode(VERSION_BLINK_PIN,OUTPUT);
|
||||
pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400);
|
||||
delay(300);
|
||||
pin13strobe(2,1,4); // separator, a quick burst
|
||||
delay(300);
|
||||
pin13strobe(FIRMATA_MINOR_VERSION, 200, 400);
|
||||
}
|
||||
|
||||
void FirmataClass::printFirmwareVersion(void)
|
||||
{
|
||||
byte i;
|
||||
|
||||
if(firmwareVersionCount) { // make sure that the name has been set before reporting
|
||||
startSysex();
|
||||
Serial.print(REPORT_FIRMWARE, BYTE);
|
||||
Serial.print(firmwareVersionVector[0]); // major version number
|
||||
Serial.print(firmwareVersionVector[1]); // minor version number
|
||||
for(i=2; i<firmwareVersionCount; ++i) {
|
||||
sendValueAsTwo7bitBytes(firmwareVersionVector[i]);
|
||||
}
|
||||
endSysex();
|
||||
}
|
||||
}
|
||||
|
||||
void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor)
|
||||
{
|
||||
const char *filename;
|
||||
char *extension;
|
||||
|
||||
// parse out ".cpp" and "applet/" that comes from using __FILE__
|
||||
extension = strstr(name, ".cpp");
|
||||
filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename
|
||||
// add two bytes for version numbers
|
||||
if(extension && filename) {
|
||||
firmwareVersionCount = extension - filename + 2;
|
||||
} else {
|
||||
firmwareVersionCount = strlen(name) + 2;
|
||||
filename = name;
|
||||
}
|
||||
firmwareVersionVector = (byte *) malloc(firmwareVersionCount);
|
||||
firmwareVersionVector[firmwareVersionCount] = 0;
|
||||
firmwareVersionVector[0] = major;
|
||||
firmwareVersionVector[1] = minor;
|
||||
strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2);
|
||||
// alas, no snprintf on Arduino
|
||||
// snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",
|
||||
// (char)major, (char)minor, firmwareVersionVector);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Serial Receive Handling
|
||||
|
||||
int FirmataClass::available(void)
|
||||
{
|
||||
return Serial.available();
|
||||
}
|
||||
|
||||
|
||||
void FirmataClass::processSysexMessage(void)
|
||||
{
|
||||
switch(storedInputData[0]) { //first byte in buffer is command
|
||||
case REPORT_FIRMWARE:
|
||||
printFirmwareVersion();
|
||||
break;
|
||||
case STRING_DATA:
|
||||
if(currentStringCallback) {
|
||||
byte bufferLength = (sysexBytesRead - 1) / 2;
|
||||
char *buffer = (char*)malloc(bufferLength * sizeof(char));
|
||||
byte i = 1;
|
||||
byte j = 0;
|
||||
while(j < bufferLength) {
|
||||
buffer[j] = (char)storedInputData[i];
|
||||
i++;
|
||||
buffer[j] += (char)(storedInputData[i] << 7);
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
(*currentStringCallback)(buffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if(currentSysexCallback)
|
||||
(*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void FirmataClass::processInput(void)
|
||||
{
|
||||
int inputData = Serial.read(); // this is 'int' to handle -1 when no data
|
||||
int command;
|
||||
|
||||
// TODO make sure it handles -1 properly
|
||||
|
||||
if (parsingSysex) {
|
||||
if(inputData == END_SYSEX) {
|
||||
//stop sysex byte
|
||||
parsingSysex = false;
|
||||
//fire off handler function
|
||||
processSysexMessage();
|
||||
} else {
|
||||
//normal data byte - add to buffer
|
||||
storedInputData[sysexBytesRead] = inputData;
|
||||
sysexBytesRead++;
|
||||
}
|
||||
} else if( (waitForData > 0) && (inputData < 128) ) {
|
||||
waitForData--;
|
||||
storedInputData[waitForData] = inputData;
|
||||
if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message
|
||||
switch(executeMultiByteCommand) {
|
||||
case ANALOG_MESSAGE:
|
||||
if(currentAnalogCallback) {
|
||||
(*currentAnalogCallback)(multiByteChannel,
|
||||
(storedInputData[0] << 7)
|
||||
+ storedInputData[1]);
|
||||
}
|
||||
break;
|
||||
case DIGITAL_MESSAGE:
|
||||
if(currentDigitalCallback) {
|
||||
(*currentDigitalCallback)(multiByteChannel,
|
||||
(storedInputData[0] << 7)
|
||||
+ storedInputData[1]);
|
||||
}
|
||||
break;
|
||||
case SET_PIN_MODE:
|
||||
if(currentPinModeCallback)
|
||||
(*currentPinModeCallback)(storedInputData[1], storedInputData[0]);
|
||||
break;
|
||||
case REPORT_ANALOG:
|
||||
if(currentReportAnalogCallback)
|
||||
(*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]);
|
||||
break;
|
||||
case REPORT_DIGITAL:
|
||||
if(currentReportDigitalCallback)
|
||||
(*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]);
|
||||
break;
|
||||
}
|
||||
executeMultiByteCommand = 0;
|
||||
}
|
||||
} else {
|
||||
// remove channel info from command byte if less than 0xF0
|
||||
if(inputData < 0xF0) {
|
||||
command = inputData & 0xF0;
|
||||
multiByteChannel = inputData & 0x0F;
|
||||
} else {
|
||||
command = inputData;
|
||||
// commands in the 0xF* range don't use channel data
|
||||
}
|
||||
switch (command) {
|
||||
case ANALOG_MESSAGE:
|
||||
case DIGITAL_MESSAGE:
|
||||
case SET_PIN_MODE:
|
||||
waitForData = 2; // two data bytes needed
|
||||
executeMultiByteCommand = command;
|
||||
break;
|
||||
case REPORT_ANALOG:
|
||||
case REPORT_DIGITAL:
|
||||
waitForData = 1; // two data bytes needed
|
||||
executeMultiByteCommand = command;
|
||||
break;
|
||||
case START_SYSEX:
|
||||
parsingSysex = true;
|
||||
sysexBytesRead = 0;
|
||||
break;
|
||||
case SYSTEM_RESET:
|
||||
systemReset();
|
||||
break;
|
||||
case REPORT_VERSION:
|
||||
Firmata.printVersion();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Serial Send Handling
|
||||
|
||||
// send an analog message
|
||||
void FirmataClass::sendAnalog(byte pin, int value)
|
||||
{
|
||||
// pin can only be 0-15, so chop higher bits
|
||||
Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE);
|
||||
sendValueAsTwo7bitBytes(value);
|
||||
}
|
||||
|
||||
// send a single digital pin in a digital message
|
||||
void FirmataClass::sendDigital(byte pin, int value)
|
||||
{
|
||||
/* TODO add single pin digital messages to the protocol, this needs to
|
||||
* track the last digital data sent so that it can be sure to change just
|
||||
* one bit in the packet. This is complicated by the fact that the
|
||||
* numbering of the pins will probably differ on Arduino, Wiring, and
|
||||
* other boards. The DIGITAL_MESSAGE sends 14 bits at a time, but it is
|
||||
* probably easier to send 8 bit ports for any board with more than 14
|
||||
* digital pins.
|
||||
*/
|
||||
|
||||
// TODO: the digital message should not be sent on the serial port every
|
||||
// time sendDigital() is called. Instead, it should add it to an int
|
||||
// which will be sent on a schedule. If a pin changes more than once
|
||||
// before the digital message is sent on the serial port, it should send a
|
||||
// digital message for each change.
|
||||
|
||||
// if(value == 0)
|
||||
// sendDigitalPortPair();
|
||||
}
|
||||
|
||||
|
||||
// send 14-bits in a single digital message (protocol v1)
|
||||
// send an 8-bit port in a single digital message (protocol v2)
|
||||
void FirmataClass::sendDigitalPort(byte portNumber, int portData)
|
||||
{
|
||||
Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE);
|
||||
Serial.print((byte)portData % 128, BYTE); // Tx bits 0-6
|
||||
Serial.print(portData >> 7, BYTE); // Tx bits 7-13
|
||||
}
|
||||
|
||||
|
||||
void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)
|
||||
{
|
||||
byte i;
|
||||
startSysex();
|
||||
Serial.print(command, BYTE);
|
||||
for(i=0; i<bytec; i++) {
|
||||
sendValueAsTwo7bitBytes(bytev[i]);
|
||||
}
|
||||
endSysex();
|
||||
}
|
||||
|
||||
void FirmataClass::sendString(byte command, const char* string)
|
||||
{
|
||||
sendSysex(command, strlen(string), (byte *)string);
|
||||
}
|
||||
|
||||
|
||||
// send a string as the protocol string type
|
||||
void FirmataClass::sendString(const char* string)
|
||||
{
|
||||
sendString(STRING_DATA, string);
|
||||
}
|
||||
|
||||
|
||||
// Internal Actions/////////////////////////////////////////////////////////////
|
||||
|
||||
// generic callbacks
|
||||
void FirmataClass::attach(byte command, callbackFunction newFunction)
|
||||
{
|
||||
switch(command) {
|
||||
case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break;
|
||||
case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break;
|
||||
case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break;
|
||||
case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break;
|
||||
case SET_PIN_MODE: currentPinModeCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction)
|
||||
{
|
||||
switch(command) {
|
||||
case SYSTEM_RESET: currentSystemResetCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
void FirmataClass::attach(byte command, stringCallbackFunction newFunction)
|
||||
{
|
||||
switch(command) {
|
||||
case STRING_DATA: currentStringCallback = newFunction; break;
|
||||
}
|
||||
}
|
||||
|
||||
void FirmataClass::attach(byte command, sysexCallbackFunction newFunction)
|
||||
{
|
||||
currentSysexCallback = newFunction;
|
||||
}
|
||||
|
||||
void FirmataClass::detach(byte command)
|
||||
{
|
||||
switch(command) {
|
||||
case SYSTEM_RESET: currentSystemResetCallback = NULL; break;
|
||||
case STRING_DATA: currentStringCallback = NULL; break;
|
||||
case START_SYSEX: currentSysexCallback = NULL; break;
|
||||
default:
|
||||
attach(command, (callbackFunction)NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// sysex callbacks
|
||||
/*
|
||||
* this is too complicated for analogReceive, but maybe for Sysex?
|
||||
void FirmataClass::attachSysex(sysexFunction newFunction)
|
||||
{
|
||||
byte i;
|
||||
byte tmpCount = analogReceiveFunctionCount;
|
||||
analogReceiveFunction* tmpArray = analogReceiveFunctionArray;
|
||||
analogReceiveFunctionCount++;
|
||||
analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction));
|
||||
for(i = 0; i < tmpCount; i++) {
|
||||
analogReceiveFunctionArray[i] = tmpArray[i];
|
||||
}
|
||||
analogReceiveFunctionArray[tmpCount] = newFunction;
|
||||
free(tmpArray);
|
||||
}
|
||||
*/
|
||||
|
||||
//******************************************************************************
|
||||
//* Private Methods
|
||||
//******************************************************************************
|
||||
|
||||
|
||||
|
||||
// resets the system state upon a SYSTEM_RESET message from the host software
|
||||
void FirmataClass::systemReset(void)
|
||||
{
|
||||
byte i;
|
||||
|
||||
waitForData = 0; // this flag says the next serial input will be data
|
||||
executeMultiByteCommand = 0; // execute this after getting multi-byte data
|
||||
multiByteChannel = 0; // channel data for multiByteCommands
|
||||
|
||||
|
||||
for(i=0; i<MAX_DATA_BYTES; i++) {
|
||||
storedInputData[i] = 0;
|
||||
}
|
||||
|
||||
parsingSysex = false;
|
||||
sysexBytesRead = 0;
|
||||
|
||||
if(currentSystemResetCallback)
|
||||
(*currentSystemResetCallback)();
|
||||
|
||||
//flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// used for flashing the pin for the version number
|
||||
void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)
|
||||
{
|
||||
byte i;
|
||||
pinMode(VERSION_BLINK_PIN, OUTPUT);
|
||||
for(i=0; i<count; i++) {
|
||||
delay(offInterval);
|
||||
digitalWrite(VERSION_BLINK_PIN, HIGH);
|
||||
delay(onInterval);
|
||||
digitalWrite(VERSION_BLINK_PIN, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// make one instance for the user to use
|
||||
FirmataClass Firmata;
|
||||
|
||||
|
162
arduino-0022-linux-x64/libraries/Firmata/Firmata.h
Normal file
162
arduino-0022-linux-x64/libraries/Firmata/Firmata.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
Firmata.h - Firmata library
|
||||
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
#ifndef Firmata_h
|
||||
#define Firmata_h
|
||||
|
||||
#include <WProgram.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
/* Version numbers for the protocol. The protocol is still changing, so these
|
||||
* version numbers are important. This number can be queried so that host
|
||||
* software can test whether it will be compatible with the currently
|
||||
* installed firmware. */
|
||||
#define FIRMATA_MAJOR_VERSION 2 // for non-compatible changes
|
||||
#define FIRMATA_MINOR_VERSION 2 // for backwards compatible changes
|
||||
|
||||
#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages
|
||||
|
||||
// message command bytes (128-255/0x80-0xFF)
|
||||
#define DIGITAL_MESSAGE 0x90 // send data for a digital pin
|
||||
#define ANALOG_MESSAGE 0xE0 // send data for an analog pin (or PWM)
|
||||
#define REPORT_ANALOG 0xC0 // enable analog input by pin #
|
||||
#define REPORT_DIGITAL 0xD0 // enable digital input by port pair
|
||||
//
|
||||
#define SET_PIN_MODE 0xF4 // set a pin to INPUT/OUTPUT/PWM/etc
|
||||
//
|
||||
#define REPORT_VERSION 0xF9 // report protocol version
|
||||
#define SYSTEM_RESET 0xFF // reset from MIDI
|
||||
//
|
||||
#define START_SYSEX 0xF0 // start a MIDI Sysex message
|
||||
#define END_SYSEX 0xF7 // end a MIDI Sysex message
|
||||
|
||||
// extended command set using sysex (0-127/0x00-0x7F)
|
||||
/* 0x00-0x0F reserved for user-defined commands */
|
||||
#define SERVO_CONFIG 0x70 // set max angle, minPulse, maxPulse, freq
|
||||
#define STRING_DATA 0x71 // a string message with 14-bits per char
|
||||
#define SHIFT_DATA 0x75 // a bitstream to/from a shift register
|
||||
#define I2C_REQUEST 0x76 // send an I2C read/write request
|
||||
#define I2C_REPLY 0x77 // a reply to an I2C read request
|
||||
#define I2C_CONFIG 0x78 // config I2C settings such as delay times and power pins
|
||||
#define EXTENDED_ANALOG 0x6F // analog write (PWM, Servo, etc) to any pin
|
||||
#define PIN_STATE_QUERY 0x6D // ask for a pin's current mode and value
|
||||
#define PIN_STATE_RESPONSE 0x6E // reply with pin's current mode and value
|
||||
#define CAPABILITY_QUERY 0x6B // ask for supported modes and resolution of all pins
|
||||
#define CAPABILITY_RESPONSE 0x6C // reply with supported modes and resolution
|
||||
#define ANALOG_MAPPING_QUERY 0x69 // ask for mapping of analog to pin numbers
|
||||
#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info
|
||||
#define REPORT_FIRMWARE 0x79 // report name and version of the firmware
|
||||
#define SAMPLING_INTERVAL 0x7A // set the poll rate of the main loop
|
||||
#define SYSEX_NON_REALTIME 0x7E // MIDI Reserved for non-realtime messages
|
||||
#define SYSEX_REALTIME 0x7F // MIDI Reserved for realtime messages
|
||||
// these are DEPRECATED to make the naming more consistent
|
||||
#define FIRMATA_STRING 0x71 // same as STRING_DATA
|
||||
#define SYSEX_I2C_REQUEST 0x76 // same as I2C_REQUEST
|
||||
#define SYSEX_I2C_REPLY 0x77 // same as I2C_REPLY
|
||||
#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL
|
||||
|
||||
// pin modes
|
||||
//#define INPUT 0x00 // defined in wiring.h
|
||||
//#define OUTPUT 0x01 // defined in wiring.h
|
||||
#define ANALOG 0x02 // analog pin in analogInput mode
|
||||
#define PWM 0x03 // digital pin in PWM output mode
|
||||
#define SERVO 0x04 // digital pin in Servo output mode
|
||||
#define SHIFT 0x05 // shiftIn/shiftOut mode
|
||||
#define I2C 0x06 // pin included in I2C setup
|
||||
#define TOTAL_PIN_MODES 7
|
||||
|
||||
extern "C" {
|
||||
// callback function types
|
||||
typedef void (*callbackFunction)(byte, int);
|
||||
typedef void (*systemResetCallbackFunction)(void);
|
||||
typedef void (*stringCallbackFunction)(char*);
|
||||
typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv);
|
||||
}
|
||||
|
||||
|
||||
// TODO make it a subclass of a generic Serial/Stream base class
|
||||
class FirmataClass
|
||||
{
|
||||
public:
|
||||
FirmataClass();
|
||||
/* Arduino constructors */
|
||||
void begin();
|
||||
void begin(long);
|
||||
/* querying functions */
|
||||
void printVersion(void);
|
||||
void blinkVersion(void);
|
||||
void printFirmwareVersion(void);
|
||||
//void setFirmwareVersion(byte major, byte minor); // see macro below
|
||||
void setFirmwareNameAndVersion(const char *name, byte major, byte minor);
|
||||
/* serial receive handling */
|
||||
int available(void);
|
||||
void processInput(void);
|
||||
/* serial send handling */
|
||||
void sendAnalog(byte pin, int value);
|
||||
void sendDigital(byte pin, int value); // TODO implement this
|
||||
void sendDigitalPort(byte portNumber, int portData);
|
||||
void sendString(const char* string);
|
||||
void sendString(byte command, const char* string);
|
||||
void sendSysex(byte command, byte bytec, byte* bytev);
|
||||
/* attach & detach callback functions to messages */
|
||||
void attach(byte command, callbackFunction newFunction);
|
||||
void attach(byte command, systemResetCallbackFunction newFunction);
|
||||
void attach(byte command, stringCallbackFunction newFunction);
|
||||
void attach(byte command, sysexCallbackFunction newFunction);
|
||||
void detach(byte command);
|
||||
|
||||
private:
|
||||
/* firmware name and version */
|
||||
byte firmwareVersionCount;
|
||||
byte *firmwareVersionVector;
|
||||
/* input message handling */
|
||||
byte waitForData; // this flag says the next serial input will be data
|
||||
byte executeMultiByteCommand; // execute this after getting multi-byte data
|
||||
byte multiByteChannel; // channel data for multiByteCommands
|
||||
byte storedInputData[MAX_DATA_BYTES]; // multi-byte data
|
||||
/* sysex */
|
||||
boolean parsingSysex;
|
||||
int sysexBytesRead;
|
||||
/* callback functions */
|
||||
callbackFunction currentAnalogCallback;
|
||||
callbackFunction currentDigitalCallback;
|
||||
callbackFunction currentReportAnalogCallback;
|
||||
callbackFunction currentReportDigitalCallback;
|
||||
callbackFunction currentPinModeCallback;
|
||||
systemResetCallbackFunction currentSystemResetCallback;
|
||||
stringCallbackFunction currentStringCallback;
|
||||
sysexCallbackFunction currentSysexCallback;
|
||||
|
||||
/* private methods ------------------------------ */
|
||||
void processSysexMessage(void);
|
||||
void systemReset(void);
|
||||
void pin13strobe(int count, int onInterval, int offInterval);
|
||||
};
|
||||
|
||||
extern FirmataClass Firmata;
|
||||
|
||||
/*==============================================================================
|
||||
* MACROS
|
||||
*============================================================================*/
|
||||
|
||||
/* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the
|
||||
* firmware name. It needs to be a macro so that __FILE__ is included in the
|
||||
* firmware source file rather than the library source file.
|
||||
*/
|
||||
#define setFirmwareVersion(x, y) setFirmwareNameAndVersion(__FILE__, x, y)
|
||||
|
||||
/* Hardware Abstraction Layer */
|
||||
#include "Boards.h"
|
||||
|
||||
#endif /* Firmata_h */
|
||||
|
458
arduino-0022-linux-x64/libraries/Firmata/LICENSE.txt
Normal file
458
arduino-0022-linux-x64/libraries/Firmata/LICENSE.txt
Normal file
|
@ -0,0 +1,458 @@
|
|||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
14
arduino-0022-linux-x64/libraries/Firmata/TODO.txt
Normal file
14
arduino-0022-linux-x64/libraries/Firmata/TODO.txt
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
- make Firmata a subclass of HardwareSerial
|
||||
|
||||
- per-pin digital callback, since the per-port callback is a bit complicated
|
||||
for beginners (maybe Firmata is not for beginners...)
|
||||
|
||||
- simplify SimpleDigitalFirmata, take out the code that checks to see if the
|
||||
data has changed, since it is a bit complicated for this example. Ideally
|
||||
this example would be based on a call
|
||||
|
||||
- turn current SimpleDigitalFirmata into DigitalPortFirmata for a more complex
|
||||
example using the code which checks for changes before doing anything
|
||||
|
||||
- test integration with Wiring
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* This firmware reads all inputs and sends them as fast as it can. It was
|
||||
* inspired by the ease-of-use of the Arduino2Max program.
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
#include <Firmata.h>
|
||||
|
||||
byte pin;
|
||||
|
||||
int analogValue;
|
||||
int previousAnalogValues[TOTAL_ANALOG_PINS];
|
||||
|
||||
byte portStatus[TOTAL_PORTS]; // each bit: 1=pin is digital input, 0=other/ignore
|
||||
byte previousPINs[TOTAL_PORTS];
|
||||
|
||||
/* timer variables */
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you
|
||||
get long, random delays. So only read analogs every 20ms or so */
|
||||
int samplingInterval = 19; // how often to run the main loop (in ms)
|
||||
|
||||
void sendPort(byte portNumber, byte portValue)
|
||||
{
|
||||
portValue = portValue & portStatus[portNumber];
|
||||
if(previousPINs[portNumber] != portValue) {
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
previousPINs[portNumber] = portValue;
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
byte i, port, status;
|
||||
|
||||
Firmata.setFirmwareVersion(0, 1);
|
||||
|
||||
for(pin = 0; pin < TOTAL_PINS; pin++) {
|
||||
if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT);
|
||||
}
|
||||
|
||||
for (port=0; port<TOTAL_PORTS; port++) {
|
||||
status = 0;
|
||||
for (i=0; i<8; i++) {
|
||||
if (IS_PIN_DIGITAL(port * 8 + i)) status |= (1 << i);
|
||||
}
|
||||
portStatus[port] = status;
|
||||
}
|
||||
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
byte i;
|
||||
|
||||
for (i=0; i<TOTAL_PORTS; i++) {
|
||||
sendPort(i, readPort(i));
|
||||
}
|
||||
/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you
|
||||
get long, random delays. So only read analogs every 20ms or so */
|
||||
currentMillis = millis();
|
||||
if(currentMillis - previousMillis > samplingInterval) {
|
||||
previousMillis += samplingInterval;
|
||||
while(Firmata.available()) {
|
||||
Firmata.processInput();
|
||||
}
|
||||
for(pin = 0; pin < TOTAL_ANALOG_PINS; pin++) {
|
||||
analogValue = analogRead(pin);
|
||||
if(analogValue != previousAnalogValues[pin]) {
|
||||
Firmata.sendAnalog(pin, analogValue);
|
||||
previousAnalogValues[pin] = analogValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
/* This firmware supports as many analog ports as possible, all analog inputs,
|
||||
* four PWM outputs, and two with servo support.
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
#include <Servo.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
/* servos */
|
||||
Servo servo9, servo10; // one instance per pin
|
||||
/* analog inputs */
|
||||
int analogInputsToReport = 0; // bitwise array to store pin reporting
|
||||
int analogPin = 0; // counter for reading analog pins
|
||||
/* timer variables */
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
switch(pin) {
|
||||
case 9: servo9.write(value); break;
|
||||
case 10: servo10.write(value); break;
|
||||
case 3:
|
||||
case 5:
|
||||
case 6:
|
||||
case 11: // PWM pins
|
||||
analogWrite(pin, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
// sets bits in a bit array (int) to toggle the reporting of the analogIns
|
||||
void reportAnalogCallback(byte pin, int value)
|
||||
{
|
||||
if(value == 0) {
|
||||
analogInputsToReport = analogInputsToReport &~ (1 << pin);
|
||||
}
|
||||
else { // everything but 0 enables reporting of that pin
|
||||
analogInputsToReport = analogInputsToReport | (1 << pin);
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SETUP()
|
||||
*============================================================================*/
|
||||
void setup()
|
||||
{
|
||||
Firmata.setFirmwareVersion(0, 2);
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
|
||||
|
||||
servo9.attach(9);
|
||||
servo10.attach(10);
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* LOOP()
|
||||
*============================================================================*/
|
||||
void loop()
|
||||
{
|
||||
while(Firmata.available())
|
||||
Firmata.processInput();
|
||||
currentMillis = millis();
|
||||
if(currentMillis - previousMillis > 20) {
|
||||
previousMillis += 20; // run this every 20ms
|
||||
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
|
||||
if( analogInputsToReport & (1 << analogPin) )
|
||||
Firmata.sendAnalog(analogPin, analogRead(analogPin));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/* This sketch accepts strings and raw sysex messages and echos them back.
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
#include <Firmata.h>
|
||||
|
||||
byte analogPin;
|
||||
|
||||
void stringCallback(char *myString)
|
||||
{
|
||||
Firmata.sendString(myString);
|
||||
}
|
||||
|
||||
|
||||
void sysexCallback(byte command, byte argc, byte*argv)
|
||||
{
|
||||
Serial.print(START_SYSEX, BYTE);
|
||||
Serial.print(command, BYTE);
|
||||
for(byte i=0; i<argc; i++) {
|
||||
Serial.print(argv[i], BYTE);
|
||||
}
|
||||
Serial.print(END_SYSEX, BYTE);
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Firmata.setFirmwareVersion(0, 1);
|
||||
Firmata.attach(STRING_DATA, stringCallback);
|
||||
Firmata.attach(START_SYSEX, sysexCallback);
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(Firmata.available()) {
|
||||
Firmata.processInput();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
Copyright (C) 2009 Jeff Hoefs. All rights reserved.
|
||||
Copyright (C) 2009 Shigeru Kobayashi. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
#include <Wire.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
|
||||
#define I2C_WRITE B00000000
|
||||
#define I2C_READ B00001000
|
||||
#define I2C_READ_CONTINUOUSLY B00010000
|
||||
#define I2C_STOP_READING B00011000
|
||||
#define I2C_READ_WRITE_MODE_MASK B00011000
|
||||
|
||||
#define MAX_QUERIES 8
|
||||
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
unsigned int samplingInterval = 32; // default sampling interval is 33ms
|
||||
unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom()
|
||||
unsigned int powerPinsEnabled = 0; // use as boolean to prevent enablePowerPins from being called more than once
|
||||
|
||||
#define MINIMUM_SAMPLING_INTERVAL 10
|
||||
|
||||
#define REGISTER_NOT_SPECIFIED -1
|
||||
|
||||
struct i2c_device_info {
|
||||
byte addr;
|
||||
byte reg;
|
||||
byte bytes;
|
||||
};
|
||||
|
||||
i2c_device_info query[MAX_QUERIES];
|
||||
|
||||
byte i2cRxData[32];
|
||||
boolean readingContinuously = false;
|
||||
byte queryIndex = 0;
|
||||
|
||||
void readAndReportData(byte address, int theRegister, byte numBytes)
|
||||
{
|
||||
if (theRegister != REGISTER_NOT_SPECIFIED) {
|
||||
Wire.beginTransmission(address);
|
||||
Wire.send((byte)theRegister);
|
||||
Wire.endTransmission();
|
||||
delayMicroseconds(i2cReadDelayTime); // delay is necessary for some devices such as WiiNunchuck
|
||||
}
|
||||
else {
|
||||
theRegister = 0; // fill the register with a dummy value
|
||||
}
|
||||
|
||||
Wire.requestFrom(address, numBytes);
|
||||
|
||||
// check to be sure correct number of bytes were returned by slave
|
||||
if(numBytes == Wire.available()) {
|
||||
i2cRxData[0] = address;
|
||||
i2cRxData[1] = theRegister;
|
||||
for (int i = 0; i < numBytes; i++) {
|
||||
i2cRxData[2 + i] = Wire.receive();
|
||||
}
|
||||
// send slave address, register and received bytes
|
||||
Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData);
|
||||
}
|
||||
else {
|
||||
if(numBytes > Wire.available()) {
|
||||
Firmata.sendString("I2C Read Error: Too many bytes received");
|
||||
} else {
|
||||
Firmata.sendString("I2C Read Error: Too few bytes received");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sysexCallback(byte command, byte argc, byte *argv)
|
||||
{
|
||||
byte mode;
|
||||
byte slaveAddress;
|
||||
byte slaveRegister;
|
||||
byte data;
|
||||
int delayTime;
|
||||
|
||||
if (command == I2C_REQUEST) {
|
||||
mode = argv[1] & I2C_READ_WRITE_MODE_MASK;
|
||||
slaveAddress = argv[0];
|
||||
|
||||
switch(mode) {
|
||||
case I2C_WRITE:
|
||||
Wire.beginTransmission(slaveAddress);
|
||||
for (byte i = 2; i < argc; i += 2) {
|
||||
data = argv[i] + (argv[i + 1] << 7);
|
||||
Wire.send(data);
|
||||
}
|
||||
Wire.endTransmission();
|
||||
delayMicroseconds(70); // TODO is this needed?
|
||||
break;
|
||||
case I2C_READ:
|
||||
if (argc == 6) {
|
||||
// a slave register is specified
|
||||
slaveRegister = argv[2] + (argv[3] << 7);
|
||||
data = argv[4] + (argv[5] << 7); // bytes to read
|
||||
readAndReportData(slaveAddress, (int)slaveRegister, data);
|
||||
}
|
||||
else {
|
||||
// a slave register is NOT specified
|
||||
data = argv[2] + (argv[3] << 7); // bytes to read
|
||||
readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data);
|
||||
}
|
||||
break;
|
||||
case I2C_READ_CONTINUOUSLY:
|
||||
if ((queryIndex + 1) >= MAX_QUERIES) {
|
||||
// too many queries, just ignore
|
||||
Firmata.sendString("too many queries");
|
||||
break;
|
||||
}
|
||||
query[queryIndex].addr = slaveAddress;
|
||||
query[queryIndex].reg = argv[2] + (argv[3] << 7);
|
||||
query[queryIndex].bytes = argv[4] + (argv[5] << 7);
|
||||
readingContinuously = true;
|
||||
queryIndex++;
|
||||
break;
|
||||
case I2C_STOP_READING:
|
||||
readingContinuously = false;
|
||||
queryIndex = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (command == SAMPLING_INTERVAL) {
|
||||
samplingInterval = argv[0] + (argv[1] << 7);
|
||||
|
||||
if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
|
||||
samplingInterval = MINIMUM_SAMPLING_INTERVAL;
|
||||
}
|
||||
|
||||
samplingInterval -= 1;
|
||||
Firmata.sendString("sampling interval");
|
||||
}
|
||||
|
||||
else if (command == I2C_CONFIG) {
|
||||
delayTime = (argv[4] + (argv[5] << 7)); // MSB
|
||||
delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7)); // add LSB
|
||||
|
||||
if((argv[0] + (argv[1] << 7)) > 0) {
|
||||
enablePowerPins(PORTC3, PORTC2);
|
||||
}
|
||||
|
||||
if(delayTime > 0) {
|
||||
i2cReadDelayTime = delayTime;
|
||||
}
|
||||
|
||||
if(argc > 6) {
|
||||
// If you extend I2C_Config, handle your data here
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void systemResetCallback()
|
||||
{
|
||||
readingContinuously = false;
|
||||
queryIndex = 0;
|
||||
}
|
||||
|
||||
/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */
|
||||
// Enables Pins A2 and A3 to be used as GND and Power
|
||||
// so that I2C devices can be plugged directly
|
||||
// into Arduino header (pins A2 - A5)
|
||||
static void enablePowerPins(byte pwrpin, byte gndpin)
|
||||
{
|
||||
if(powerPinsEnabled == 0) {
|
||||
DDRC |= _BV(pwrpin) | _BV(gndpin);
|
||||
PORTC &=~ _BV(gndpin);
|
||||
PORTC |= _BV(pwrpin);
|
||||
powerPinsEnabled = 1;
|
||||
Firmata.sendString("Power pins enabled");
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Firmata.setFirmwareVersion(2, 0);
|
||||
|
||||
Firmata.attach(START_SYSEX, sysexCallback);
|
||||
Firmata.attach(SYSTEM_RESET, systemResetCallback);
|
||||
|
||||
for (int i = 0; i < TOTAL_PINS; ++i) {
|
||||
pinMode(i, OUTPUT);
|
||||
}
|
||||
|
||||
Firmata.begin(57600);
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while (Firmata.available()) {
|
||||
Firmata.processInput();
|
||||
}
|
||||
|
||||
currentMillis = millis();
|
||||
if (currentMillis - previousMillis > samplingInterval) {
|
||||
previousMillis += samplingInterval;
|
||||
|
||||
for (byte i = 0; i < queryIndex; i++) {
|
||||
readAndReportData(query[i].addr, query[i].reg, query[i].bytes);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,458 @@
|
|||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an old version of StandardFirmata (v2.0). It is kept here because
|
||||
* its the last version that works on an ATMEGA8 chip. Also, it can be used
|
||||
* for host software that has not been updated to a newer version of the
|
||||
* protocol. It also uses the old baud rate of 115200 rather than 57600.
|
||||
*/
|
||||
|
||||
#include <EEPROM.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
/* analog inputs */
|
||||
int analogInputsToReport = 0; // bitwise array to store pin reporting
|
||||
int analogPin = 0; // counter for reading analog pins
|
||||
|
||||
/* digital pins */
|
||||
byte reportPINs[TOTAL_PORTS]; // PIN == input port
|
||||
byte previousPINs[TOTAL_PORTS]; // PIN == input port
|
||||
byte pinStatus[TOTAL_PINS]; // store pin status, default OUTPUT
|
||||
byte portStatus[TOTAL_PORTS];
|
||||
|
||||
/* timer variables */
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void outputPort(byte portNumber, byte portValue)
|
||||
{
|
||||
portValue = portValue &~ portStatus[portNumber];
|
||||
if(previousPINs[portNumber] != portValue) {
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
previousPINs[portNumber] = portValue;
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* check all the active digital inputs for change of state, then add any events
|
||||
* to the Serial output queue using Serial.print() */
|
||||
void checkDigitalInputs(void)
|
||||
{
|
||||
byte i, tmp;
|
||||
for(i=0; i < TOTAL_PORTS; i++) {
|
||||
if(reportPINs[i]) {
|
||||
switch(i) {
|
||||
case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1
|
||||
case 1: outputPort(1, PINB); break;
|
||||
case 2: outputPort(2, PINC); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets the pin mode to the correct state and sets the relevant bits in the
|
||||
* two bit-arrays that track Digital I/O and PWM status
|
||||
*/
|
||||
void setPinModeCallback(byte pin, int mode) {
|
||||
byte port = 0;
|
||||
byte offset = 0;
|
||||
|
||||
if (pin < 8) {
|
||||
port = 0;
|
||||
offset = 0;
|
||||
} else if (pin < 14) {
|
||||
port = 1;
|
||||
offset = 8;
|
||||
} else if (pin < 22) {
|
||||
port = 2;
|
||||
offset = 14;
|
||||
}
|
||||
|
||||
if(pin > 1) { // ignore RxTx (pins 0 and 1)
|
||||
pinStatus[pin] = mode;
|
||||
switch(mode) {
|
||||
case INPUT:
|
||||
pinMode(pin, INPUT);
|
||||
portStatus[port] = portStatus[port] &~ (1 << (pin - offset));
|
||||
break;
|
||||
case OUTPUT:
|
||||
digitalWrite(pin, LOW); // disable PWM
|
||||
case PWM:
|
||||
pinMode(pin, OUTPUT);
|
||||
portStatus[port] = portStatus[port] | (1 << (pin - offset));
|
||||
break;
|
||||
//case ANALOG: // TODO figure this out
|
||||
default:
|
||||
Firmata.sendString("");
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
}
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
setPinModeCallback(pin,PWM);
|
||||
analogWrite(pin, value);
|
||||
}
|
||||
|
||||
void digitalWriteCallback(byte port, int value)
|
||||
{
|
||||
switch(port) {
|
||||
case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1)
|
||||
// 0xFF03 == B1111111100000011 0x03 == B00000011
|
||||
PORTD = (value &~ 0xFF03) | (PORTD & 0x03);
|
||||
break;
|
||||
case 1: // pins 8-13 (14,15 are disabled for the crystal)
|
||||
PORTB = (byte)value;
|
||||
break;
|
||||
case 2: // analog pins used as digital
|
||||
PORTC = (byte)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
|
||||
*/
|
||||
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
|
||||
//}
|
||||
void reportAnalogCallback(byte pin, int value)
|
||||
{
|
||||
if(value == 0) {
|
||||
analogInputsToReport = analogInputsToReport &~ (1 << pin);
|
||||
}
|
||||
else { // everything but 0 enables reporting of that pin
|
||||
analogInputsToReport = analogInputsToReport | (1 << pin);
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
void reportDigitalCallback(byte port, int value)
|
||||
{
|
||||
reportPINs[port] = (byte)value;
|
||||
if(port == 2) // turn off analog reporting when used as digital
|
||||
analogInputsToReport = 0;
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SETUP()
|
||||
*============================================================================*/
|
||||
void setup()
|
||||
{
|
||||
byte i;
|
||||
|
||||
Firmata.setFirmwareVersion(2, 0);
|
||||
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
|
||||
Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
|
||||
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
|
||||
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
|
||||
|
||||
portStatus[0] = B00000011; // ignore Tx/RX pins
|
||||
portStatus[1] = B11000000; // ignore 14/15 pins
|
||||
portStatus[2] = B00000000;
|
||||
|
||||
// for(i=0; i<TOTAL_PINS; ++i) { // TODO make this work with analogs
|
||||
for(i=0; i<14; ++i) {
|
||||
setPinModeCallback(i,OUTPUT);
|
||||
}
|
||||
// set all outputs to 0 to make sure internal pull-up resistors are off
|
||||
PORTB = 0; // pins 8-15
|
||||
PORTC = 0; // analog port
|
||||
PORTD = 0; // pins 0-7
|
||||
|
||||
// TODO rethink the init, perhaps it should report analog on default
|
||||
for(i=0; i<TOTAL_PORTS; ++i) {
|
||||
reportPINs[i] = false;
|
||||
}
|
||||
// TODO: load state from EEPROM here
|
||||
|
||||
/* send digital inputs here, if enabled, to set the initial state on the
|
||||
* host computer, since once in the loop(), this firmware will only send
|
||||
* digital data on change. */
|
||||
if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1
|
||||
if(reportPINs[1]) outputPort(1, PINB);
|
||||
if(reportPINs[2]) outputPort(2, PINC);
|
||||
|
||||
Firmata.begin(115200);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* LOOP()
|
||||
*============================================================================*/
|
||||
void loop()
|
||||
{
|
||||
/* DIGITALREAD - as fast as possible, check for changes and output them to the
|
||||
* FTDI buffer using Serial.print() */
|
||||
checkDigitalInputs();
|
||||
currentMillis = millis();
|
||||
if(currentMillis - previousMillis > 20) {
|
||||
previousMillis += 20; // run this every 20ms
|
||||
/* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle
|
||||
* all serialReads at once, i.e. empty the buffer */
|
||||
while(Firmata.available())
|
||||
Firmata.processInput();
|
||||
/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
|
||||
* 60 bytes. use a timer to sending an event character every 4 ms to
|
||||
* trigger the buffer to dump. */
|
||||
|
||||
/* ANALOGREAD - right after the event character, do all of the
|
||||
* analogReads(). These only need to be done every 4ms. */
|
||||
for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) {
|
||||
if( analogInputsToReport & (1 << analogPin) ) {
|
||||
Firmata.sendAnalog(analogPin, analogRead(analogPin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/* This firmware supports as many servos as possible using the Servo library
|
||||
* included in Arduino 0017
|
||||
*
|
||||
* TODO add message to configure minPulse/maxPulse/degrees
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
|
||||
#include <Servo.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
Servo servos[MAX_SERVOS];
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
servos[PIN_TO_SERVO(pin)].write(value);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
byte pin;
|
||||
|
||||
Firmata.setFirmwareVersion(0, 2);
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
|
||||
for (pin=0; pin < TOTAL_PINS; pin++) {
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
|
||||
}
|
||||
}
|
||||
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(Firmata.available())
|
||||
Firmata.processInput();
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/* Supports as many analog inputs and analog PWM outputs as possible.
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
#include <Firmata.h>
|
||||
|
||||
byte analogPin = 0;
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
if (IS_PIN_PWM(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
|
||||
analogWrite(PIN_TO_PWM(pin), value);
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Firmata.setFirmwareVersion(0, 1);
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
while(Firmata.available()) {
|
||||
Firmata.processInput();
|
||||
}
|
||||
// do one analogRead per loop, so if PC is sending a lot of
|
||||
// analog write messages, we will only delay 1 analogRead
|
||||
Firmata.sendAnalog(analogPin, analogRead(analogPin));
|
||||
analogPin = analogPin + 1;
|
||||
if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,263 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
CC = avr-gcc
|
||||
CXX = avr-g++
|
||||
OBJCOPY = avr-objcopy
|
||||
OBJDUMP = avr-objdump
|
||||
SIZE = avr-size
|
||||
NM = avr-nm
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/* Supports as many digital inputs and outputs as possible.
|
||||
*
|
||||
* This example code is in the public domain.
|
||||
*/
|
||||
#include <Firmata.h>
|
||||
|
||||
byte previousPIN[TOTAL_PORTS]; // PIN means PORT for input
|
||||
byte previousPORT[TOTAL_PORTS];
|
||||
|
||||
void outputPort(byte portNumber, byte portValue)
|
||||
{
|
||||
// only send the data when it changes, otherwise you get too many messages!
|
||||
if (previousPIN[portNumber] != portValue) {
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
previousPIN[portNumber] = portValue;
|
||||
}
|
||||
}
|
||||
|
||||
void setPinModeCallback(byte pin, int mode) {
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), mode);
|
||||
}
|
||||
}
|
||||
|
||||
void digitalWriteCallback(byte port, int value)
|
||||
{
|
||||
byte i;
|
||||
byte currentPinValue, previousPinValue;
|
||||
|
||||
if (port < TOTAL_PORTS && value != previousPORT[port]) {
|
||||
for(i=0; i<8; i++) {
|
||||
currentPinValue = (byte) value & (1 << i);
|
||||
previousPinValue = previousPORT[port] & (1 << i);
|
||||
if(currentPinValue != previousPinValue) {
|
||||
digitalWrite(i + (port*8), currentPinValue);
|
||||
}
|
||||
}
|
||||
previousPORT[port] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void setup()
|
||||
{
|
||||
Firmata.setFirmwareVersion(0, 1);
|
||||
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
|
||||
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
|
||||
Firmata.begin(57600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
byte i;
|
||||
|
||||
for (i=0; i<TOTAL_PORTS; i++) {
|
||||
outputPort(i, readPort(i));
|
||||
}
|
||||
|
||||
while(Firmata.available()) {
|
||||
Firmata.processInput();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,458 @@
|
|||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
|
@ -0,0 +1,273 @@
|
|||
# Arduino makefile
|
||||
#
|
||||
# This makefile allows you to build sketches from the command line
|
||||
# without the Arduino environment (or Java).
|
||||
#
|
||||
# The Arduino environment does preliminary processing on a sketch before
|
||||
# compiling it. If you're using this makefile instead, you'll need to do
|
||||
# a few things differently:
|
||||
#
|
||||
# - Give your program's file a .cpp extension (e.g. foo.cpp).
|
||||
#
|
||||
# - Put this line at top of your code: #include <WProgram.h>
|
||||
#
|
||||
# - Write prototypes for all your functions (or define them before you
|
||||
# call them). A prototype declares the types of parameters a
|
||||
# function will take and what type of value it will return. This
|
||||
# means that you can have a call to a function before the definition
|
||||
# of the function. A function prototype looks like the first line of
|
||||
# the function, with a semi-colon at the end. For example:
|
||||
# int digitalRead(int pin);
|
||||
#
|
||||
# Instructions for using the makefile:
|
||||
#
|
||||
# 1. Copy this file into the folder with your sketch.
|
||||
#
|
||||
# 2. Below, modify the line containing "TARGET" to refer to the name of
|
||||
# of your program's file without an extension (e.g. TARGET = foo).
|
||||
#
|
||||
# 3. Modify the line containg "ARDUINO" to point the directory that
|
||||
# contains the Arduino core (for normal Arduino installations, this
|
||||
# is the hardware/cores/arduino sub-directory).
|
||||
#
|
||||
# 4. Modify the line containing "PORT" to refer to the filename
|
||||
# representing the USB or serial connection to your Arduino board
|
||||
# (e.g. PORT = /dev/tty.USB0). If the exact name of this file
|
||||
# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*).
|
||||
#
|
||||
# 5. At the command line, change to the directory containing your
|
||||
# program's file and the makefile.
|
||||
#
|
||||
# 6. Type "make" and press enter to compile/verify your program.
|
||||
#
|
||||
# 7. Type "make upload", reset your Arduino board, and press enter to
|
||||
# upload your program to the Arduino board.
|
||||
#
|
||||
# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $
|
||||
|
||||
PORT = /dev/tty.usbserial-*
|
||||
TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|')
|
||||
ARDUINO = /Applications/arduino
|
||||
ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino
|
||||
ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries
|
||||
ARDUINO_TOOLS = $(ARDUINO)/hardware/tools
|
||||
INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \
|
||||
-I$(ARDUINO_LIB_SRC)/EEPROM \
|
||||
-I$(ARDUINO_LIB_SRC)/Firmata \
|
||||
-I$(ARDUINO_LIB_SRC)/Matrix \
|
||||
-I$(ARDUINO_LIB_SRC)/Servo \
|
||||
-I$(ARDUINO_LIB_SRC)/Wire \
|
||||
-I$(ARDUINO_LIB_SRC)
|
||||
SRC = $(wildcard $(ARDUINO_SRC)/*.c)
|
||||
CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \
|
||||
$(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \
|
||||
$(ARDUINO_LIB_SRC)/Servo/Servo.cpp \
|
||||
$(ARDUINO_SRC)/Print.cpp \
|
||||
$(ARDUINO_SRC)/WMath.cpp
|
||||
HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h)
|
||||
|
||||
MCU = atmega168
|
||||
#MCU = atmega8
|
||||
F_CPU = 16000000
|
||||
FORMAT = ihex
|
||||
UPLOAD_RATE = 19200
|
||||
|
||||
# Name of this Makefile (used for "make depend").
|
||||
MAKEFILE = Makefile
|
||||
|
||||
# Debugging format.
|
||||
# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2.
|
||||
# AVR (extended) COFF requires stabs, plus an avr-objcopy run.
|
||||
DEBUG = stabs
|
||||
|
||||
OPT = s
|
||||
|
||||
# Place -D or -U options here
|
||||
CDEFS = -DF_CPU=$(F_CPU)
|
||||
CXXDEFS = -DF_CPU=$(F_CPU)
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 - "ANSI" C
|
||||
# gnu89 - c89 plus GCC extensions
|
||||
# c99 - ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 - c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
CDEBUG = -g$(DEBUG)
|
||||
CWARN = -Wall -Wstrict-prototypes
|
||||
CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
|
||||
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
|
||||
|
||||
CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
|
||||
CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT)
|
||||
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
|
||||
LDFLAGS =
|
||||
|
||||
|
||||
# Programming support using avrdude. Settings and variables.
|
||||
AVRDUDE_PROGRAMMER = stk500
|
||||
AVRDUDE_PORT = $(PORT)
|
||||
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
|
||||
AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
|
||||
-b $(UPLOAD_RATE) -q -V
|
||||
|
||||
# Program settings
|
||||
ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin
|
||||
CC = $(ARDUINO_AVR_BIN)/avr-gcc
|
||||
CXX = $(ARDUINO_AVR_BIN)/avr-g++
|
||||
OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy
|
||||
OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump
|
||||
SIZE = $(ARDUINO_AVR_BIN)/avr-size
|
||||
NM = $(ARDUINO_AVR_BIN)/avr-nm
|
||||
#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude
|
||||
AVRDUDE = avrdude
|
||||
REMOVE = rm -f
|
||||
MV = mv -f
|
||||
|
||||
# Define all object files.
|
||||
OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o)
|
||||
|
||||
# Define all listing files.
|
||||
LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst)
|
||||
|
||||
# Combine all necessary flags and optional flags.
|
||||
# Add target processor to flags.
|
||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS)
|
||||
ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS)
|
||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||
|
||||
|
||||
# Default target.
|
||||
all: build
|
||||
|
||||
build: applet/$(TARGET).hex
|
||||
|
||||
eep: applet/$(TARGET).eep
|
||||
lss: applet/$(TARGET).lss
|
||||
sym: applet/$(TARGET).sym
|
||||
|
||||
|
||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||
COFFCONVERT=$(OBJCOPY) --debugging \
|
||||
--change-section-address .data-0x800000 \
|
||||
--change-section-address .bss-0x800000 \
|
||||
--change-section-address .noinit-0x800000 \
|
||||
--change-section-address .eeprom-0x810000
|
||||
|
||||
|
||||
coff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
extcoff: applet/$(TARGET).elf
|
||||
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof
|
||||
|
||||
|
||||
.SUFFIXES: .elf .hex .eep .lss .sym .pde
|
||||
|
||||
.elf.hex:
|
||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@
|
||||
|
||||
.elf.eep:
|
||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||
--change-section-lma .eeprom=0 -O $(FORMAT) $< $@
|
||||
|
||||
# Create extended listing file from ELF output file.
|
||||
.elf.lss:
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# Create a symbol table from ELF output file.
|
||||
.elf.sym:
|
||||
$(NM) -n $< > $@
|
||||
|
||||
|
||||
# Compile: create object files from C++ source files.
|
||||
.cpp.o: $(HEADERS)
|
||||
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
|
||||
|
||||
# Compile: create object files from C source files.
|
||||
.c.o: $(HEADERS)
|
||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Compile: create assembler files from C source files.
|
||||
.c.s:
|
||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||
|
||||
|
||||
# Assemble: create object files from assembler source files.
|
||||
.S.o:
|
||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||
|
||||
|
||||
|
||||
applet/$(TARGET).cpp: $(TARGET).pde
|
||||
test -d applet || mkdir applet
|
||||
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
|
||||
echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp
|
||||
sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \
|
||||
grep -v 'loop()' >> applet/$(TARGET).cpp
|
||||
cat $(TARGET).pde >> applet/$(TARGET).cpp
|
||||
cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp
|
||||
|
||||
# Link: create ELF output file from object files.
|
||||
applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ)
|
||||
$(CC) $(ALL_CFLAGS) $(OBJ) -lm --output $@ $(LDFLAGS)
|
||||
# $(CC) $(ALL_CFLAGS) $(OBJ) $(ARDUINO_TOOLS)/avr/avr/lib/avr5/crtm168.o --output $@ $(LDFLAGS)
|
||||
|
||||
pd_close_serial:
|
||||
echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true
|
||||
|
||||
# Program the device.
|
||||
upload: applet/$(TARGET).hex
|
||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
|
||||
|
||||
|
||||
pd_test: build pd_close_serial upload
|
||||
|
||||
# Target: clean project.
|
||||
clean:
|
||||
$(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \
|
||||
applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \
|
||||
applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \
|
||||
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
|
||||
rmdir -- applet
|
||||
|
||||
depend:
|
||||
if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \
|
||||
then \
|
||||
sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \
|
||||
$(MAKEFILE).$$$$ && \
|
||||
$(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \
|
||||
fi
|
||||
echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \
|
||||
>> $(MAKEFILE); \
|
||||
$(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE)
|
||||
|
||||
.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test
|
||||
|
||||
# for emacs
|
||||
etags:
|
||||
make etags_`uname -s`
|
||||
etags *.pde \
|
||||
$(ARDUINO_SRC)/*.[ch] \
|
||||
$(ARDUINO_SRC)/*.cpp \
|
||||
$(ARDUINO_LIB_SRC)/*/*.[ch] \
|
||||
$(ARDUINO_LIB_SRC)/*/*.cpp \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \
|
||||
$(ARDUINO)/hardware/tools/avr/avr/include/*.[ch]
|
||||
|
||||
etags_Darwin:
|
||||
# etags -a
|
||||
|
||||
etags_Linux:
|
||||
# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h
|
||||
|
||||
etags_MINGW:
|
||||
# etags -a /usr/include/*.h /usr/include/sys/*.h
|
||||
|
||||
|
||||
path:
|
||||
echo $(PATH)
|
||||
echo $$PATH
|
||||
|
|
@ -0,0 +1,398 @@
|
|||
/*
|
||||
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
|
||||
formatted using the GNU C formatting and indenting
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: use Program Control to load stored profiles from EEPROM
|
||||
*/
|
||||
|
||||
#include <Servo.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
/* analog inputs */
|
||||
int analogInputsToReport = 0; // bitwise array to store pin reporting
|
||||
|
||||
/* digital input ports */
|
||||
byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence
|
||||
byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent
|
||||
|
||||
/* pins configuration */
|
||||
byte pinConfig[TOTAL_PINS]; // configuration of every pin
|
||||
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
|
||||
int pinState[TOTAL_PINS]; // any value that has been written
|
||||
|
||||
/* timer variables */
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
int samplingInterval = 19; // how often to run the main loop (in ms)
|
||||
|
||||
Servo servos[MAX_SERVOS];
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void outputPort(byte portNumber, byte portValue, byte forceSend)
|
||||
{
|
||||
// pins not configured as INPUT are cleared to zeros
|
||||
portValue = portValue & portConfigInputs[portNumber];
|
||||
// only send if the value is different than previously sent
|
||||
if(forceSend || previousPINs[portNumber] != portValue) {
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
previousPINs[portNumber] = portValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* check all the active digital inputs for change of state, then add any events
|
||||
* to the Serial output queue using Serial.print() */
|
||||
void checkDigitalInputs(void)
|
||||
{
|
||||
/* Using non-looping code allows constants to be given to readPort().
|
||||
* The compiler will apply substantial optimizations if the inputs
|
||||
* to readPort() are compile-time constants. */
|
||||
if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
|
||||
if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
|
||||
if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
|
||||
if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
|
||||
if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
|
||||
if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
|
||||
if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
|
||||
if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
|
||||
if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
|
||||
if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
|
||||
if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
|
||||
if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
|
||||
if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
|
||||
if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
|
||||
if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
|
||||
if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets the pin mode to the correct state and sets the relevant bits in the
|
||||
* two bit-arrays that track Digital I/O and PWM status
|
||||
*/
|
||||
void setPinModeCallback(byte pin, int mode)
|
||||
{
|
||||
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
|
||||
servos[PIN_TO_SERVO(pin)].detach();
|
||||
}
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
|
||||
}
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
if (mode == INPUT) {
|
||||
portConfigInputs[pin/8] |= (1 << (pin & 7));
|
||||
} else {
|
||||
portConfigInputs[pin/8] &= ~(1 << (pin & 7));
|
||||
}
|
||||
}
|
||||
pinState[pin] = 0;
|
||||
switch(mode) {
|
||||
case ANALOG:
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
|
||||
}
|
||||
pinConfig[pin] = ANALOG;
|
||||
}
|
||||
break;
|
||||
case INPUT:
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
|
||||
pinConfig[pin] = INPUT;
|
||||
}
|
||||
break;
|
||||
case OUTPUT:
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
|
||||
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
|
||||
pinConfig[pin] = OUTPUT;
|
||||
}
|
||||
break;
|
||||
case PWM:
|
||||
if (IS_PIN_PWM(pin)) {
|
||||
pinMode(PIN_TO_PWM(pin), OUTPUT);
|
||||
analogWrite(PIN_TO_PWM(pin), 0);
|
||||
pinConfig[pin] = PWM;
|
||||
}
|
||||
break;
|
||||
case SERVO:
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
pinConfig[pin] = SERVO;
|
||||
if (!servos[PIN_TO_SERVO(pin)].attached()) {
|
||||
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
|
||||
} else {
|
||||
Firmata.sendString("Servo only on pins from 2 to 13");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case I2C:
|
||||
pinConfig[pin] = mode;
|
||||
Firmata.sendString("I2C mode not yet supported");
|
||||
break;
|
||||
default:
|
||||
Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
if (pin < TOTAL_PINS) {
|
||||
switch(pinConfig[pin]) {
|
||||
case SERVO:
|
||||
if (IS_PIN_SERVO(pin))
|
||||
servos[PIN_TO_SERVO(pin)].write(value);
|
||||
pinState[pin] = value;
|
||||
break;
|
||||
case PWM:
|
||||
if (IS_PIN_PWM(pin))
|
||||
analogWrite(PIN_TO_PWM(pin), value);
|
||||
pinState[pin] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void digitalWriteCallback(byte port, int value)
|
||||
{
|
||||
byte pin, lastPin, mask=1, pinWriteMask=0;
|
||||
|
||||
if (port < TOTAL_PORTS) {
|
||||
// create a mask of the pins on this port that are writable.
|
||||
lastPin = port*8+8;
|
||||
if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
|
||||
for (pin=port*8; pin < lastPin; pin++) {
|
||||
// do not disturb non-digital pins (eg, Rx & Tx)
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
// only write to OUTPUT and INPUT (enables pullup)
|
||||
// do not touch pins in PWM, ANALOG, SERVO or other modes
|
||||
if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
|
||||
pinWriteMask |= mask;
|
||||
pinState[pin] = ((byte)value & mask) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
writePort(port, (byte)value, pinWriteMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
|
||||
*/
|
||||
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
|
||||
//}
|
||||
void reportAnalogCallback(byte analogPin, int value)
|
||||
{
|
||||
if (analogPin < TOTAL_ANALOG_PINS) {
|
||||
if(value == 0) {
|
||||
analogInputsToReport = analogInputsToReport &~ (1 << analogPin);
|
||||
} else {
|
||||
analogInputsToReport = analogInputsToReport | (1 << analogPin);
|
||||
}
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
void reportDigitalCallback(byte port, int value)
|
||||
{
|
||||
if (port < TOTAL_PORTS) {
|
||||
reportPINs[port] = (byte)value;
|
||||
}
|
||||
// do not disable analog reporting on these 8 pins, to allow some
|
||||
// pins used for digital, others analog. Instead, allow both types
|
||||
// of reporting to be enabled, but check if the pin is configured
|
||||
// as analog when sampling the analog inputs. Likewise, while
|
||||
// scanning digital pins, portConfigInputs will mask off values from any
|
||||
// pins configured as analog
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SYSEX-BASED commands
|
||||
*============================================================================*/
|
||||
|
||||
void sysexCallback(byte command, byte argc, byte *argv)
|
||||
{
|
||||
switch(command) {
|
||||
case SERVO_CONFIG:
|
||||
if(argc > 4) {
|
||||
// these vars are here for clarity, they'll optimized away by the compiler
|
||||
byte pin = argv[0];
|
||||
int minPulse = argv[1] + (argv[2] << 7);
|
||||
int maxPulse = argv[3] + (argv[4] << 7);
|
||||
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
// servos are pins from 2 to 13, so offset for array
|
||||
if (servos[PIN_TO_SERVO(pin)].attached())
|
||||
servos[PIN_TO_SERVO(pin)].detach();
|
||||
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
|
||||
setPinModeCallback(pin, SERVO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SAMPLING_INTERVAL:
|
||||
if (argc > 1)
|
||||
samplingInterval = argv[0] + (argv[1] << 7);
|
||||
else
|
||||
Firmata.sendString("Not enough data");
|
||||
break;
|
||||
case EXTENDED_ANALOG:
|
||||
if (argc > 1) {
|
||||
int val = argv[1];
|
||||
if (argc > 2) val |= (argv[2] << 7);
|
||||
if (argc > 3) val |= (argv[3] << 14);
|
||||
analogWriteCallback(argv[0], val);
|
||||
}
|
||||
break;
|
||||
case CAPABILITY_QUERY:
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(CAPABILITY_RESPONSE);
|
||||
for (byte pin=0; pin < TOTAL_PINS; pin++) {
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
Serial.write((byte)INPUT);
|
||||
Serial.write(1);
|
||||
Serial.write((byte)OUTPUT);
|
||||
Serial.write(1);
|
||||
}
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
Serial.write(ANALOG);
|
||||
Serial.write(10);
|
||||
}
|
||||
if (IS_PIN_PWM(pin)) {
|
||||
Serial.write(PWM);
|
||||
Serial.write(8);
|
||||
}
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
Serial.write(SERVO);
|
||||
Serial.write(14);
|
||||
}
|
||||
Serial.write(127);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
break;
|
||||
case PIN_STATE_QUERY:
|
||||
if (argc > 0) {
|
||||
byte pin=argv[0];
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(PIN_STATE_RESPONSE);
|
||||
Serial.write(pin);
|
||||
if (pin < TOTAL_PINS) {
|
||||
Serial.write((byte)pinConfig[pin]);
|
||||
Serial.write((byte)pinState[pin] & 0x7F);
|
||||
if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F);
|
||||
if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
}
|
||||
break;
|
||||
case ANALOG_MAPPING_QUERY:
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(ANALOG_MAPPING_RESPONSE);
|
||||
for (byte pin=0; pin < TOTAL_PINS; pin++) {
|
||||
Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* SETUP()
|
||||
*============================================================================*/
|
||||
void setup()
|
||||
{
|
||||
byte i;
|
||||
|
||||
Firmata.setFirmwareVersion(2, 2);
|
||||
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
|
||||
Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
|
||||
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
|
||||
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
|
||||
Firmata.attach(START_SYSEX, sysexCallback);
|
||||
|
||||
// TODO: load state from EEPROM here
|
||||
|
||||
/* these are initialized to zero by the compiler startup code
|
||||
for (i=0; i < TOTAL_PORTS; i++) {
|
||||
reportPINs[i] = false;
|
||||
portConfigInputs[i] = 0;
|
||||
previousPINs[i] = 0;
|
||||
}
|
||||
*/
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (IS_PIN_ANALOG(i)) {
|
||||
// turns off pullup, configures everything
|
||||
setPinModeCallback(i, ANALOG);
|
||||
} else {
|
||||
// sets the output to 0, configures portConfigInputs
|
||||
setPinModeCallback(i, OUTPUT);
|
||||
}
|
||||
}
|
||||
// by defult, do not report any analog inputs
|
||||
analogInputsToReport = 0;
|
||||
|
||||
Firmata.begin(57600);
|
||||
|
||||
/* send digital inputs to set the initial state on the host computer,
|
||||
* since once in the loop(), this firmware will only send on change */
|
||||
for (i=0; i < TOTAL_PORTS; i++) {
|
||||
outputPort(i, readPort(i, portConfigInputs[i]), true);
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* LOOP()
|
||||
*============================================================================*/
|
||||
void loop()
|
||||
{
|
||||
byte pin, analogPin;
|
||||
|
||||
/* DIGITALREAD - as fast as possible, check for changes and output them to the
|
||||
* FTDI buffer using Serial.print() */
|
||||
checkDigitalInputs();
|
||||
|
||||
/* SERIALREAD - processing incoming messagse as soon as possible, while still
|
||||
* checking digital inputs. */
|
||||
while(Firmata.available())
|
||||
Firmata.processInput();
|
||||
|
||||
/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
|
||||
* 60 bytes. use a timer to sending an event character every 4 ms to
|
||||
* trigger the buffer to dump. */
|
||||
|
||||
currentMillis = millis();
|
||||
if (currentMillis - previousMillis > samplingInterval) {
|
||||
previousMillis += samplingInterval;
|
||||
/* ANALOGREAD - do all analogReads() at the configured sampling interval */
|
||||
for(pin=0; pin<TOTAL_PINS; pin++) {
|
||||
if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) {
|
||||
analogPin = PIN_TO_ANALOG(pin);
|
||||
if (analogInputsToReport & (1 << analogPin)) {
|
||||
Firmata.sendAnalog(analogPin, analogRead(analogPin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,436 @@
|
|||
/*
|
||||
This introduces modifications on the normal Firmata made for Arduino so that the LED
|
||||
blinks until receiving the first command over serial.
|
||||
|
||||
Copyright (C) 2010 David Cuartielles. All rights reserved.
|
||||
|
||||
based at 99.9% on Firmata by HC Steiner according to the following license terms:
|
||||
|
||||
Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights 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.
|
||||
|
||||
See file LICENSE.txt for further informations on licensing terms.
|
||||
|
||||
formatted using the GNU C formatting and indenting
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: use Program Control to load stored profiles from EEPROM
|
||||
*/
|
||||
|
||||
#include <Servo.h>
|
||||
#include <Firmata.h>
|
||||
|
||||
/*==============================================================================
|
||||
* GLOBAL VARIABLES
|
||||
*============================================================================*/
|
||||
|
||||
/* has the command arrived? */
|
||||
boolean firstCommand = false;
|
||||
int dataOnSerial = 0;
|
||||
boolean statusLed = false;
|
||||
|
||||
/* analog inputs */
|
||||
int analogInputsToReport = 0; // bitwise array to store pin reporting
|
||||
|
||||
/* digital input ports */
|
||||
byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence
|
||||
byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent
|
||||
|
||||
/* pins configuration */
|
||||
byte pinConfig[TOTAL_PINS]; // configuration of every pin
|
||||
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else
|
||||
int pinState[TOTAL_PINS]; // any value that has been written
|
||||
|
||||
/* timer variables */
|
||||
unsigned long currentMillis; // store the current value from millis()
|
||||
unsigned long previousMillis; // for comparison with currentMillis
|
||||
int samplingInterval = 19; // how often to run the main loop (in ms)
|
||||
unsigned long toggleMillis;
|
||||
|
||||
Servo servos[MAX_SERVOS];
|
||||
|
||||
/*==============================================================================
|
||||
* FUNCTIONS
|
||||
*============================================================================*/
|
||||
|
||||
void toggleLed()
|
||||
{
|
||||
if (millis() - toggleMillis > 500) {
|
||||
statusLed = !statusLed;
|
||||
digitalWrite(13, statusLed);
|
||||
toggleMillis = millis();
|
||||
}
|
||||
}
|
||||
|
||||
void outputPort(byte portNumber, byte portValue, byte forceSend)
|
||||
{
|
||||
// pins not configured as INPUT are cleared to zeros
|
||||
portValue = portValue & portConfigInputs[portNumber];
|
||||
// only send if the value is different than previously sent
|
||||
if(forceSend || previousPINs[portNumber] != portValue) {
|
||||
Firmata.sendDigitalPort(portNumber, portValue);
|
||||
previousPINs[portNumber] = portValue;
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* check all the active digital inputs for change of state, then add any events
|
||||
* to the Serial output queue using Serial.print() */
|
||||
void checkDigitalInputs(void)
|
||||
{
|
||||
/* Using non-looping code allows constants to be given to readPort().
|
||||
* The compiler will apply substantial optimizations if the inputs
|
||||
* to readPort() are compile-time constants. */
|
||||
if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
|
||||
if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
|
||||
if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
|
||||
if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
|
||||
if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
|
||||
if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
|
||||
if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
|
||||
if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
|
||||
if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
|
||||
if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
|
||||
if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
|
||||
if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
|
||||
if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
|
||||
if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
|
||||
if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
|
||||
if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets the pin mode to the correct state and sets the relevant bits in the
|
||||
* two bit-arrays that track Digital I/O and PWM status
|
||||
*/
|
||||
void setPinModeCallback(byte pin, int mode)
|
||||
{
|
||||
if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) {
|
||||
servos[PIN_TO_SERVO(pin)].detach();
|
||||
}
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting
|
||||
}
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
if (mode == INPUT) {
|
||||
portConfigInputs[pin/8] |= (1 << (pin & 7));
|
||||
} else {
|
||||
portConfigInputs[pin/8] &= ~(1 << (pin & 7));
|
||||
}
|
||||
}
|
||||
pinState[pin] = 0;
|
||||
switch(mode) {
|
||||
case ANALOG:
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
|
||||
}
|
||||
pinConfig[pin] = ANALOG;
|
||||
}
|
||||
break;
|
||||
case INPUT:
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
|
||||
pinConfig[pin] = INPUT;
|
||||
}
|
||||
break;
|
||||
case OUTPUT:
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM
|
||||
pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
|
||||
pinConfig[pin] = OUTPUT;
|
||||
}
|
||||
break;
|
||||
case PWM:
|
||||
if (IS_PIN_PWM(pin)) {
|
||||
pinMode(PIN_TO_PWM(pin), OUTPUT);
|
||||
analogWrite(PIN_TO_PWM(pin), 0);
|
||||
pinConfig[pin] = PWM;
|
||||
}
|
||||
break;
|
||||
case SERVO:
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
pinConfig[pin] = SERVO;
|
||||
if (!servos[PIN_TO_SERVO(pin)].attached()) {
|
||||
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
|
||||
} else {
|
||||
Firmata.sendString("Servo only on pins from 2 to 13");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case I2C:
|
||||
pinConfig[pin] = mode;
|
||||
Firmata.sendString("I2C mode not yet supported");
|
||||
break;
|
||||
default:
|
||||
Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
void analogWriteCallback(byte pin, int value)
|
||||
{
|
||||
if (pin < TOTAL_PINS) {
|
||||
switch(pinConfig[pin]) {
|
||||
case SERVO:
|
||||
if (IS_PIN_SERVO(pin))
|
||||
servos[PIN_TO_SERVO(pin)].write(value);
|
||||
pinState[pin] = value;
|
||||
break;
|
||||
case PWM:
|
||||
if (IS_PIN_PWM(pin))
|
||||
analogWrite(PIN_TO_PWM(pin), value);
|
||||
pinState[pin] = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void digitalWriteCallback(byte port, int value)
|
||||
{
|
||||
byte pin, lastPin, mask=1, pinWriteMask=0;
|
||||
|
||||
if (port < TOTAL_PORTS) {
|
||||
// create a mask of the pins on this port that are writable.
|
||||
lastPin = port*8+8;
|
||||
if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
|
||||
for (pin=port*8; pin < lastPin; pin++) {
|
||||
// do not disturb non-digital pins (eg, Rx & Tx)
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
// only write to OUTPUT and INPUT (enables pullup)
|
||||
// do not touch pins in PWM, ANALOG, SERVO or other modes
|
||||
if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) {
|
||||
pinWriteMask |= mask;
|
||||
pinState[pin] = ((byte)value & mask) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
mask = mask << 1;
|
||||
}
|
||||
writePort(port, (byte)value, pinWriteMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
|
||||
*/
|
||||
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
|
||||
//}
|
||||
void reportAnalogCallback(byte analogPin, int value)
|
||||
{
|
||||
if (analogPin < TOTAL_ANALOG_PINS) {
|
||||
if(value == 0) {
|
||||
analogInputsToReport = analogInputsToReport &~ (1 << analogPin);
|
||||
} else {
|
||||
analogInputsToReport = analogInputsToReport | (1 << analogPin);
|
||||
}
|
||||
}
|
||||
// TODO: save status to EEPROM here, if changed
|
||||
}
|
||||
|
||||
void reportDigitalCallback(byte port, int value)
|
||||
{
|
||||
if (port < TOTAL_PORTS) {
|
||||
reportPINs[port] = (byte)value;
|
||||
}
|
||||
// do not disable analog reporting on these 8 pins, to allow some
|
||||
// pins used for digital, others analog. Instead, allow both types
|
||||
// of reporting to be enabled, but check if the pin is configured
|
||||
// as analog when sampling the analog inputs. Likewise, while
|
||||
// scanning digital pins, portConfigInputs will mask off values from any
|
||||
// pins configured as analog
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SYSEX-BASED commands
|
||||
*============================================================================*/
|
||||
|
||||
void sysexCallback(byte command, byte argc, byte *argv)
|
||||
{
|
||||
switch(command) {
|
||||
case SERVO_CONFIG:
|
||||
if(argc > 4) {
|
||||
// these vars are here for clarity, they'll optimized away by the compiler
|
||||
byte pin = argv[0];
|
||||
int minPulse = argv[1] + (argv[2] << 7);
|
||||
int maxPulse = argv[3] + (argv[4] << 7);
|
||||
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
// servos are pins from 2 to 13, so offset for array
|
||||
if (servos[PIN_TO_SERVO(pin)].attached())
|
||||
servos[PIN_TO_SERVO(pin)].detach();
|
||||
servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse);
|
||||
setPinModeCallback(pin, SERVO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SAMPLING_INTERVAL:
|
||||
if (argc > 1)
|
||||
samplingInterval = argv[0] + (argv[1] << 7);
|
||||
else
|
||||
Firmata.sendString("Not enough data");
|
||||
break;
|
||||
case EXTENDED_ANALOG:
|
||||
if (argc > 1) {
|
||||
int val = argv[1];
|
||||
if (argc > 2) val |= (argv[2] << 7);
|
||||
if (argc > 3) val |= (argv[3] << 14);
|
||||
analogWriteCallback(argv[0], val);
|
||||
}
|
||||
break;
|
||||
case CAPABILITY_QUERY:
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(CAPABILITY_RESPONSE);
|
||||
for (byte pin=0; pin < TOTAL_PINS; pin++) {
|
||||
if (IS_PIN_DIGITAL(pin)) {
|
||||
Serial.write((byte)INPUT);
|
||||
Serial.write(1);
|
||||
Serial.write((byte)OUTPUT);
|
||||
Serial.write(1);
|
||||
}
|
||||
if (IS_PIN_ANALOG(pin)) {
|
||||
Serial.write(ANALOG);
|
||||
Serial.write(10);
|
||||
}
|
||||
if (IS_PIN_PWM(pin)) {
|
||||
Serial.write(PWM);
|
||||
Serial.write(8);
|
||||
}
|
||||
if (IS_PIN_SERVO(pin)) {
|
||||
Serial.write(SERVO);
|
||||
Serial.write(14);
|
||||
}
|
||||
Serial.write(127);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
break;
|
||||
case PIN_STATE_QUERY:
|
||||
if (argc > 0) {
|
||||
byte pin=argv[0];
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(PIN_STATE_RESPONSE);
|
||||
Serial.write(pin);
|
||||
if (pin < TOTAL_PINS) {
|
||||
Serial.write((byte)pinConfig[pin]);
|
||||
Serial.write((byte)pinState[pin] & 0x7F);
|
||||
if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F);
|
||||
if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
}
|
||||
break;
|
||||
case ANALOG_MAPPING_QUERY:
|
||||
Serial.write(START_SYSEX);
|
||||
Serial.write(ANALOG_MAPPING_RESPONSE);
|
||||
for (byte pin=0; pin < TOTAL_PINS; pin++) {
|
||||
Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
|
||||
}
|
||||
Serial.write(END_SYSEX);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* SETUP()
|
||||
*============================================================================*/
|
||||
void setup()
|
||||
{
|
||||
byte i;
|
||||
|
||||
Firmata.setFirmwareVersion(2, 2);
|
||||
|
||||
Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
|
||||
Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
|
||||
Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
|
||||
Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
|
||||
Firmata.attach(SET_PIN_MODE, setPinModeCallback);
|
||||
Firmata.attach(START_SYSEX, sysexCallback);
|
||||
|
||||
// TODO: load state from EEPROM here
|
||||
|
||||
/* these are initialized to zero by the compiler startup code
|
||||
for (i=0; i < TOTAL_PORTS; i++) {
|
||||
reportPINs[i] = false;
|
||||
portConfigInputs[i] = 0;
|
||||
previousPINs[i] = 0;
|
||||
}
|
||||
*/
|
||||
for (i=0; i < TOTAL_PINS; i++) {
|
||||
if (IS_PIN_ANALOG(i)) {
|
||||
// turns off pullup, configures everything
|
||||
setPinModeCallback(i, ANALOG);
|
||||
} else {
|
||||
// sets the output to 0, configures portConfigInputs
|
||||
setPinModeCallback(i, OUTPUT);
|
||||
}
|
||||
}
|
||||
// by defult, do not report any analog inputs
|
||||
analogInputsToReport = 0;
|
||||
|
||||
Firmata.begin(57600);
|
||||
|
||||
/* send digital inputs to set the initial state on the host computer,
|
||||
* since once in the loop(), this firmware will only send on change */
|
||||
for (i=0; i < TOTAL_PORTS; i++) {
|
||||
outputPort(i, readPort(i, portConfigInputs[i]), true);
|
||||
}
|
||||
|
||||
/* init the toggleLed counter */
|
||||
toggleMillis = millis();
|
||||
pinMode(13, OUTPUT);
|
||||
}
|
||||
|
||||
/*==============================================================================
|
||||
* LOOP()
|
||||
*============================================================================*/
|
||||
void loop()
|
||||
{
|
||||
byte pin, analogPin;
|
||||
|
||||
/* DIGITALREAD - as fast as possible, check for changes and output them to the
|
||||
* FTDI buffer using Serial.print() */
|
||||
checkDigitalInputs();
|
||||
|
||||
//XXX: hack Firmata to blink until serial command arrives
|
||||
dataOnSerial = Firmata.available();
|
||||
if (dataOnSerial > 0 && !firstCommand) {
|
||||
firstCommand = true;
|
||||
}
|
||||
//XXX: do the blink if the first command hasn't arrived yet
|
||||
// configures pin 13 as output and then back as input
|
||||
if (!firstCommand) {
|
||||
toggleLed();
|
||||
}
|
||||
|
||||
/* SERIALREAD - processing incoming messagse as soon as possible, while still
|
||||
* checking digital inputs. */
|
||||
while(dataOnSerial) {
|
||||
Firmata.processInput();
|
||||
dataOnSerial = Firmata.available();
|
||||
}
|
||||
|
||||
/* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over
|
||||
* 60 bytes. use a timer to sending an event character every 4 ms to
|
||||
* trigger the buffer to dump. */
|
||||
|
||||
currentMillis = millis();
|
||||
if (currentMillis - previousMillis > samplingInterval) {
|
||||
previousMillis += samplingInterval;
|
||||
/* ANALOGREAD - do all analogReads() at the configured sampling interval */
|
||||
for(pin=0; pin<TOTAL_PINS; pin++) {
|
||||
if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) {
|
||||
analogPin = PIN_TO_ANALOG(pin);
|
||||
if (analogInputsToReport & (1 << analogPin)) {
|
||||
Firmata.sendAnalog(analogPin, analogRead(analogPin));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
arduino-0022-linux-x64/libraries/Firmata/keywords.txt
Normal file
62
arduino-0022-linux-x64/libraries/Firmata/keywords.txt
Normal file
|
@ -0,0 +1,62 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Firmata
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Firmata KEYWORD1
|
||||
callbackFunction KEYWORD1
|
||||
systemResetCallbackFunction KEYWORD1
|
||||
stringCallbackFunction KEYWORD1
|
||||
sysexCallbackFunction KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
begin KEYWORD2
|
||||
printVersion KEYWORD2
|
||||
blinkVersion KEYWORD2
|
||||
printFirmwareVersion KEYWORD2
|
||||
setFirmwareVersion KEYWORD2
|
||||
setFirmwareNameAndVersion KEYWORD2
|
||||
available KEYWORD2
|
||||
processInput KEYWORD2
|
||||
sendAnalog KEYWORD2
|
||||
sendDigital KEYWORD2
|
||||
sendDigitalPortPair KEYWORD2
|
||||
sendDigitalPort KEYWORD2
|
||||
sendString KEYWORD2
|
||||
sendString KEYWORD2
|
||||
sendSysex KEYWORD2
|
||||
attach KEYWORD2
|
||||
detach KEYWORD2
|
||||
flush KEYWORD2
|
||||
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
MAX_DATA_BYTES LITERAL1
|
||||
|
||||
DIGITAL_MESSAGE LITERAL1
|
||||
ANALOG_MESSAGE LITERAL1
|
||||
REPORT_ANALOG LITERAL1
|
||||
REPORT_DIGITAL LITERAL1
|
||||
REPORT_VERSION LITERAL1
|
||||
SET_PIN_MODE LITERAL1
|
||||
SYSTEM_RESET LITERAL1
|
||||
|
||||
START_SYSEX LITERAL1
|
||||
END_SYSEX LITERAL1
|
||||
|
||||
PWM LITERAL1
|
||||
|
||||
TOTAL_ANALOG_PINS LITERAL1
|
||||
TOTAL_DIGITAL_PINS LITERAL1
|
||||
TOTAL_PORTS LITERAL1
|
||||
ANALOG_PORT LITERAL1
|
309
arduino-0022-linux-x64/libraries/LiquidCrystal/LiquidCrystal.cpp
Normal file
309
arduino-0022-linux-x64/libraries/LiquidCrystal/LiquidCrystal.cpp
Normal file
|
@ -0,0 +1,309 @@
|
|||
#include "LiquidCrystal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "WProgram.h"
|
||||
|
||||
// When the display powers up, it is configured as follows:
|
||||
//
|
||||
// 1. Display clear
|
||||
// 2. Function set:
|
||||
// DL = 1; 8-bit interface data
|
||||
// N = 0; 1-line display
|
||||
// F = 0; 5x8 dot character font
|
||||
// 3. Display on/off control:
|
||||
// D = 0; Display off
|
||||
// C = 0; Cursor off
|
||||
// B = 0; Blinking off
|
||||
// 4. Entry mode set:
|
||||
// I/D = 1; Increment by 1
|
||||
// S = 0; No shift
|
||||
//
|
||||
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
|
||||
// can't assume that its in that state when a sketch starts (and the
|
||||
// LiquidCrystal constructor is called).
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
init(0, rs, 255, enable, d0, d1, d2, d3, d4, d5, d6, d7);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, rw, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3)
|
||||
{
|
||||
init(1, rs, 255, enable, d0, d1, d2, d3, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void LiquidCrystal::init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7)
|
||||
{
|
||||
_rs_pin = rs;
|
||||
_rw_pin = rw;
|
||||
_enable_pin = enable;
|
||||
|
||||
_data_pins[0] = d0;
|
||||
_data_pins[1] = d1;
|
||||
_data_pins[2] = d2;
|
||||
_data_pins[3] = d3;
|
||||
_data_pins[4] = d4;
|
||||
_data_pins[5] = d5;
|
||||
_data_pins[6] = d6;
|
||||
_data_pins[7] = d7;
|
||||
|
||||
pinMode(_rs_pin, OUTPUT);
|
||||
// we can save 1 pin by not using RW. Indicate by passing 255 instead of pin#
|
||||
if (_rw_pin != 255) {
|
||||
pinMode(_rw_pin, OUTPUT);
|
||||
}
|
||||
pinMode(_enable_pin, OUTPUT);
|
||||
|
||||
if (fourbitmode)
|
||||
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
else
|
||||
_displayfunction = LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
||||
|
||||
begin(16, 1);
|
||||
}
|
||||
|
||||
void LiquidCrystal::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
|
||||
if (lines > 1) {
|
||||
_displayfunction |= LCD_2LINE;
|
||||
}
|
||||
_numlines = lines;
|
||||
_currline = 0;
|
||||
|
||||
// for some 1 line displays you can select a 10 pixel high font
|
||||
if ((dotsize != 0) && (lines == 1)) {
|
||||
_displayfunction |= LCD_5x10DOTS;
|
||||
}
|
||||
|
||||
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
||||
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
||||
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
||||
delayMicroseconds(50000);
|
||||
// Now we pull both RS and R/W low to begin commands
|
||||
digitalWrite(_rs_pin, LOW);
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
//put the LCD into 4 bit or 8 bit mode
|
||||
if (! (_displayfunction & LCD_8BITMODE)) {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// figure 24, pg 46
|
||||
|
||||
// we start in 8bit mode, try to set 4 bit mode
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// second try
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(4500); // wait min 4.1ms
|
||||
|
||||
// third go!
|
||||
write4bits(0x03);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// finally, set to 4-bit interface
|
||||
write4bits(0x02);
|
||||
} else {
|
||||
// this is according to the hitachi HD44780 datasheet
|
||||
// page 45 figure 23
|
||||
|
||||
// Send function set command sequence
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(4500); // wait more than 4.1ms
|
||||
|
||||
// second try
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
delayMicroseconds(150);
|
||||
|
||||
// third go
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
}
|
||||
|
||||
// finally, set # lines, font size, etc.
|
||||
command(LCD_FUNCTIONSET | _displayfunction);
|
||||
|
||||
// turn the display on with no cursor or blinking default
|
||||
_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
|
||||
display();
|
||||
|
||||
// clear it off
|
||||
clear();
|
||||
|
||||
// Initialize to default text direction (for romance languages)
|
||||
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
||||
// set the entry mode
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
|
||||
}
|
||||
|
||||
/********** high level commands, for the user! */
|
||||
void LiquidCrystal::clear()
|
||||
{
|
||||
command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::home()
|
||||
{
|
||||
command(LCD_RETURNHOME); // set cursor position to zero
|
||||
delayMicroseconds(2000); // this command takes a long time!
|
||||
}
|
||||
|
||||
void LiquidCrystal::setCursor(uint8_t col, uint8_t row)
|
||||
{
|
||||
int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
||||
if ( row > _numlines ) {
|
||||
row = _numlines-1; // we count rows starting w/0
|
||||
}
|
||||
|
||||
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
||||
}
|
||||
|
||||
// Turn the display on/off (quickly)
|
||||
void LiquidCrystal::noDisplay() {
|
||||
_displaycontrol &= ~LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::display() {
|
||||
_displaycontrol |= LCD_DISPLAYON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turns the underline cursor on/off
|
||||
void LiquidCrystal::noCursor() {
|
||||
_displaycontrol &= ~LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::cursor() {
|
||||
_displaycontrol |= LCD_CURSORON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// Turn on and off the blinking cursor
|
||||
void LiquidCrystal::noBlink() {
|
||||
_displaycontrol &= ~LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
void LiquidCrystal::blink() {
|
||||
_displaycontrol |= LCD_BLINKON;
|
||||
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
||||
}
|
||||
|
||||
// These commands scroll the display without changing the RAM
|
||||
void LiquidCrystal::scrollDisplayLeft(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
||||
}
|
||||
void LiquidCrystal::scrollDisplayRight(void) {
|
||||
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
||||
}
|
||||
|
||||
// This is for text that flows Left to Right
|
||||
void LiquidCrystal::leftToRight(void) {
|
||||
_displaymode |= LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This is for text that flows Right to Left
|
||||
void LiquidCrystal::rightToLeft(void) {
|
||||
_displaymode &= ~LCD_ENTRYLEFT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'right justify' text from the cursor
|
||||
void LiquidCrystal::autoscroll(void) {
|
||||
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// This will 'left justify' text from the cursor
|
||||
void LiquidCrystal::noAutoscroll(void) {
|
||||
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
||||
command(LCD_ENTRYMODESET | _displaymode);
|
||||
}
|
||||
|
||||
// Allows us to fill the first 8 CGRAM locations
|
||||
// with custom characters
|
||||
void LiquidCrystal::createChar(uint8_t location, uint8_t charmap[]) {
|
||||
location &= 0x7; // we only have 8 locations 0-7
|
||||
command(LCD_SETCGRAMADDR | (location << 3));
|
||||
for (int i=0; i<8; i++) {
|
||||
write(charmap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*********** mid level commands, for sending data/cmds */
|
||||
|
||||
inline void LiquidCrystal::command(uint8_t value) {
|
||||
send(value, LOW);
|
||||
}
|
||||
|
||||
inline void LiquidCrystal::write(uint8_t value) {
|
||||
send(value, HIGH);
|
||||
}
|
||||
|
||||
/************ low level data pushing commands **********/
|
||||
|
||||
// write either command or data, with automatic 4/8-bit selection
|
||||
void LiquidCrystal::send(uint8_t value, uint8_t mode) {
|
||||
digitalWrite(_rs_pin, mode);
|
||||
|
||||
// if there is a RW pin indicated, set it low to Write
|
||||
if (_rw_pin != 255) {
|
||||
digitalWrite(_rw_pin, LOW);
|
||||
}
|
||||
|
||||
if (_displayfunction & LCD_8BITMODE) {
|
||||
write8bits(value);
|
||||
} else {
|
||||
write4bits(value>>4);
|
||||
write4bits(value);
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidCrystal::pulseEnable(void) {
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(1);
|
||||
digitalWrite(_enable_pin, HIGH);
|
||||
delayMicroseconds(1); // enable pulse must be >450ns
|
||||
digitalWrite(_enable_pin, LOW);
|
||||
delayMicroseconds(100); // commands need > 37us to settle
|
||||
}
|
||||
|
||||
void LiquidCrystal::write4bits(uint8_t value) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
||||
|
||||
void LiquidCrystal::write8bits(uint8_t value) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
pinMode(_data_pins[i], OUTPUT);
|
||||
digitalWrite(_data_pins[i], (value >> i) & 0x01);
|
||||
}
|
||||
|
||||
pulseEnable();
|
||||
}
|
104
arduino-0022-linux-x64/libraries/LiquidCrystal/LiquidCrystal.h
Normal file
104
arduino-0022-linux-x64/libraries/LiquidCrystal/LiquidCrystal.h
Normal file
|
@ -0,0 +1,104 @@
|
|||
#ifndef LiquidCrystal_h
|
||||
#define LiquidCrystal_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "Print.h"
|
||||
|
||||
// commands
|
||||
#define LCD_CLEARDISPLAY 0x01
|
||||
#define LCD_RETURNHOME 0x02
|
||||
#define LCD_ENTRYMODESET 0x04
|
||||
#define LCD_DISPLAYCONTROL 0x08
|
||||
#define LCD_CURSORSHIFT 0x10
|
||||
#define LCD_FUNCTIONSET 0x20
|
||||
#define LCD_SETCGRAMADDR 0x40
|
||||
#define LCD_SETDDRAMADDR 0x80
|
||||
|
||||
// flags for display entry mode
|
||||
#define LCD_ENTRYRIGHT 0x00
|
||||
#define LCD_ENTRYLEFT 0x02
|
||||
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
||||
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
||||
|
||||
// flags for display on/off control
|
||||
#define LCD_DISPLAYON 0x04
|
||||
#define LCD_DISPLAYOFF 0x00
|
||||
#define LCD_CURSORON 0x02
|
||||
#define LCD_CURSOROFF 0x00
|
||||
#define LCD_BLINKON 0x01
|
||||
#define LCD_BLINKOFF 0x00
|
||||
|
||||
// flags for display/cursor shift
|
||||
#define LCD_DISPLAYMOVE 0x08
|
||||
#define LCD_CURSORMOVE 0x00
|
||||
#define LCD_MOVERIGHT 0x04
|
||||
#define LCD_MOVELEFT 0x00
|
||||
|
||||
// flags for function set
|
||||
#define LCD_8BITMODE 0x10
|
||||
#define LCD_4BITMODE 0x00
|
||||
#define LCD_2LINE 0x08
|
||||
#define LCD_1LINE 0x00
|
||||
#define LCD_5x10DOTS 0x04
|
||||
#define LCD_5x8DOTS 0x00
|
||||
|
||||
class LiquidCrystal : public Print {
|
||||
public:
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
LiquidCrystal(uint8_t rs, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3);
|
||||
|
||||
void init(uint8_t fourbitmode, uint8_t rs, uint8_t rw, uint8_t enable,
|
||||
uint8_t d0, uint8_t d1, uint8_t d2, uint8_t d3,
|
||||
uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7);
|
||||
|
||||
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
|
||||
|
||||
void clear();
|
||||
void home();
|
||||
|
||||
void noDisplay();
|
||||
void display();
|
||||
void noBlink();
|
||||
void blink();
|
||||
void noCursor();
|
||||
void cursor();
|
||||
void scrollDisplayLeft();
|
||||
void scrollDisplayRight();
|
||||
void leftToRight();
|
||||
void rightToLeft();
|
||||
void autoscroll();
|
||||
void noAutoscroll();
|
||||
|
||||
void createChar(uint8_t, uint8_t[]);
|
||||
void setCursor(uint8_t, uint8_t);
|
||||
virtual void write(uint8_t);
|
||||
void command(uint8_t);
|
||||
private:
|
||||
void send(uint8_t, uint8_t);
|
||||
void write4bits(uint8_t);
|
||||
void write8bits(uint8_t);
|
||||
void pulseEnable();
|
||||
|
||||
uint8_t _rs_pin; // LOW: command. HIGH: character.
|
||||
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
|
||||
uint8_t _enable_pin; // activated by a HIGH pulse.
|
||||
uint8_t _data_pins[8];
|
||||
|
||||
uint8_t _displayfunction;
|
||||
uint8_t _displaycontrol;
|
||||
uint8_t _displaymode;
|
||||
|
||||
uint8_t _initialized;
|
||||
|
||||
uint8_t _numlines,_currline;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
LiquidCrystal Library - Autoscroll
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch demonstrates the use of the autoscroll()
|
||||
and noAutoscroll() functions to make new text scroll or not.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16,2);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// set the cursor to (0,0):
|
||||
lcd.setCursor(0, 0);
|
||||
// print from 0 to 9:
|
||||
for (int thisChar = 0; thisChar < 10; thisChar++) {
|
||||
lcd.print(thisChar);
|
||||
delay(500);
|
||||
}
|
||||
|
||||
// set the cursor to (16,1):
|
||||
lcd.setCursor(16,1);
|
||||
// set the display to automatically scroll:
|
||||
lcd.autoscroll();
|
||||
// print from 0 to 9:
|
||||
for (int thisChar = 0; thisChar < 10; thisChar++) {
|
||||
lcd.print(thisChar);
|
||||
delay(500);
|
||||
}
|
||||
// turn off automatic scrolling
|
||||
lcd.noAutoscroll();
|
||||
|
||||
// clear screen for the next loop:
|
||||
lcd.clear();
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
LiquidCrystal Library - Blink
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints "Hello World!" to the LCD and makes the
|
||||
cursor block blink.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// Print a message to the LCD.
|
||||
lcd.print("hello, world!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Turn off the blinking cursor:
|
||||
lcd.noBlink();
|
||||
delay(3000);
|
||||
// Turn on the blinking cursor:
|
||||
lcd.blink();
|
||||
delay(3000);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
LiquidCrystal Library - Cursor
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints "Hello World!" to the LCD and
|
||||
uses the cursor() and noCursor() methods to turn
|
||||
on and off the cursor.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// Print a message to the LCD.
|
||||
lcd.print("hello, world!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Turn off the cursor:
|
||||
lcd.noCursor();
|
||||
delay(500);
|
||||
// Turn on the cursor:
|
||||
lcd.cursor();
|
||||
delay(500);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
LiquidCrystal Library - display() and noDisplay()
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints "Hello World!" to the LCD and uses the
|
||||
display() and noDisplay() functions to turn on and off
|
||||
the display.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// Print a message to the LCD.
|
||||
lcd.print("hello, world!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Turn off the display:
|
||||
lcd.noDisplay();
|
||||
delay(500);
|
||||
// Turn on the display:
|
||||
lcd.display();
|
||||
delay(500);
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
LiquidCrystal Library - Hello World
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints "Hello World!" to the LCD
|
||||
and shows the time.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// Print a message to the LCD.
|
||||
lcd.print("hello, world!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// set the cursor to column 0, line 1
|
||||
// (note: line 1 is the second row, since counting begins with 0):
|
||||
lcd.setCursor(0, 1);
|
||||
// print the number of seconds since reset:
|
||||
lcd.print(millis()/1000);
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
LiquidCrystal Library - scrollDisplayLeft() and scrollDisplayRight()
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints "Hello World!" to the LCD and uses the
|
||||
scrollDisplayLeft() and scrollDisplayRight() methods to scroll
|
||||
the text.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// Print a message to the LCD.
|
||||
lcd.print("hello, world!");
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// scroll 13 positions (string length) to the left
|
||||
// to move it offscreen left:
|
||||
for (int positionCounter = 0; positionCounter < 13; positionCounter++) {
|
||||
// scroll one position left:
|
||||
lcd.scrollDisplayLeft();
|
||||
// wait a bit:
|
||||
delay(150);
|
||||
}
|
||||
|
||||
// scroll 29 positions (string length + display length) to the right
|
||||
// to move it offscreen right:
|
||||
for (int positionCounter = 0; positionCounter < 29; positionCounter++) {
|
||||
// scroll one position right:
|
||||
lcd.scrollDisplayRight();
|
||||
// wait a bit:
|
||||
delay(150);
|
||||
}
|
||||
|
||||
// scroll 16 positions (display length + string length) to the left
|
||||
// to move it back to center:
|
||||
for (int positionCounter = 0; positionCounter < 16; positionCounter++) {
|
||||
// scroll one position left:
|
||||
lcd.scrollDisplayLeft();
|
||||
// wait a bit:
|
||||
delay(150);
|
||||
}
|
||||
|
||||
// delay at the end of the full loop:
|
||||
delay(1000);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
LiquidCrystal Library - Serial Input
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch displays text sent over the serial port
|
||||
(e.g. from the Serial Monitor) on an attached LCD.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup(){
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// initialize the serial communications:
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// when characters arrive over the serial port...
|
||||
if (Serial.available()) {
|
||||
// wait a bit for the entire message to arrive
|
||||
delay(100);
|
||||
// clear the screen
|
||||
lcd.clear();
|
||||
// read all the available characters
|
||||
while (Serial.available() > 0) {
|
||||
// display each character to the LCD
|
||||
lcd.write(Serial.read());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
LiquidCrystal Library - TextDirection
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch demonstrates how to use leftToRight() and rightToLeft()
|
||||
to move the cursor.
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
int thisChar = 'a';
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(16, 2);
|
||||
// turn on the cursor:
|
||||
lcd.cursor();
|
||||
Serial.begin(9600);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// reverse directions at 'm':
|
||||
if (thisChar == 'm') {
|
||||
// go right for the next letter
|
||||
lcd.rightToLeft();
|
||||
}
|
||||
// reverse again at 's':
|
||||
if (thisChar == 's') {
|
||||
// go left for the next letter
|
||||
lcd.leftToRight();
|
||||
}
|
||||
// reset at 'z':
|
||||
if (thisChar > 'z') {
|
||||
// go to (0,0):
|
||||
lcd.home();
|
||||
// start again at 0
|
||||
thisChar = 'a';
|
||||
}
|
||||
// print the character
|
||||
lcd.print(thisChar, BYTE);
|
||||
// wait a second:
|
||||
delay(1000);
|
||||
// increment the letter:
|
||||
thisChar++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
LiquidCrystal Library - setCursor
|
||||
|
||||
Demonstrates the use a 16x2 LCD display. The LiquidCrystal
|
||||
library works with all LCD displays that are compatible with the
|
||||
Hitachi HD44780 driver. There are many of them out there, and you
|
||||
can usually tell them by the 16-pin interface.
|
||||
|
||||
This sketch prints to all the positions of the LCD using the
|
||||
setCursor(0 method:
|
||||
|
||||
The circuit:
|
||||
* LCD RS pin to digital pin 12
|
||||
* LCD Enable pin to digital pin 11
|
||||
* LCD D4 pin to digital pin 5
|
||||
* LCD D5 pin to digital pin 4
|
||||
* LCD D6 pin to digital pin 3
|
||||
* LCD D7 pin to digital pin 2
|
||||
* LCD R/W pin to ground
|
||||
* 10K resistor:
|
||||
* ends to +5V and ground
|
||||
* wiper to LCD VO pin (pin 3)
|
||||
|
||||
Library originally added 18 Apr 2008
|
||||
by David A. Mellis
|
||||
library modified 5 Jul 2009
|
||||
by Limor Fried (http://www.ladyada.net)
|
||||
example added 9 Jul 2009
|
||||
by Tom Igoe
|
||||
modified 22 Nov 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
http://www.arduino.cc/en/Tutorial/LiquidCrystal
|
||||
*/
|
||||
|
||||
// include the library code:
|
||||
#include <LiquidCrystal.h>
|
||||
|
||||
// these constants won't change. But you can change the size of
|
||||
// your LCD using them:
|
||||
const int numRows = 2;
|
||||
const int numCols = 16;
|
||||
|
||||
// initialize the library with the numbers of the interface pins
|
||||
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
|
||||
|
||||
void setup() {
|
||||
// set up the LCD's number of columns and rows:
|
||||
lcd.begin(numCols,numRows);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// loop from ASCII 'a' to ASCII 'z':
|
||||
for (int thisLetter = 'a'; thisLetter <= 'z'; thisLetter++) {
|
||||
// loop over the columns:
|
||||
for (int thisCol = 0; thisCol < numRows; thisCol++) {
|
||||
// loop over the rows:
|
||||
for (int thisRow = 0; thisRow < numCols; thisRow++) {
|
||||
// set the cursor position:
|
||||
lcd.setCursor(thisRow,thisCol);
|
||||
// print the letter:
|
||||
lcd.print(thisLetter, BYTE);
|
||||
delay(200);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
37
arduino-0022-linux-x64/libraries/LiquidCrystal/keywords.txt
Normal file
37
arduino-0022-linux-x64/libraries/LiquidCrystal/keywords.txt
Normal file
|
@ -0,0 +1,37 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For LiquidCrystal
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
LiquidCrystal KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
begin KEYWORD2
|
||||
clear KEYWORD2
|
||||
home KEYWORD2
|
||||
print KEYWORD2
|
||||
setCursor KEYWORD2
|
||||
cursor KEYWORD2
|
||||
noCursor KEYWORD2
|
||||
blink KEYWORD2
|
||||
noBlink KEYWORD2
|
||||
display KEYWORD2
|
||||
noDisplay KEYWORD2
|
||||
autoscroll KEYWORD2
|
||||
noAutoscroll KEYWORD2
|
||||
leftToRight KEYWORD2
|
||||
rightToLeft KEYWORD2
|
||||
scrollDisplayLeft KEYWORD2
|
||||
scrollDisplayRight KEYWORD2
|
||||
createChar KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
229
arduino-0022-linux-x64/libraries/Matrix/Matrix.cpp
Normal file
229
arduino-0022-linux-x64/libraries/Matrix/Matrix.cpp
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
Matrix.cpp - Max7219 LED Matrix library for Arduino & Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
||||
*/
|
||||
|
||||
// TODO: Support segment displays in api?
|
||||
// TODO: Support varying vendor layouts?
|
||||
|
||||
/******************************************************************************
|
||||
* Includes
|
||||
******************************************************************************/
|
||||
|
||||
extern "C" {
|
||||
// AVR LibC Includes
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Wiring Core Includes
|
||||
#undef abs
|
||||
#include "WConstants.h"
|
||||
|
||||
// Wiring Core Prototypes
|
||||
//void pinMode(uint8_t, uint8_t);
|
||||
//void digitalWrite(int, uint8_t);
|
||||
}
|
||||
|
||||
#include "Sprite.h"
|
||||
#include "Matrix.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
// Matrix registers
|
||||
#define REG_NOOP 0x00
|
||||
#define REG_DIGIT0 0x01
|
||||
#define REG_DIGIT1 0x02
|
||||
#define REG_DIGIT2 0x03
|
||||
#define REG_DIGIT3 0x04
|
||||
#define REG_DIGIT4 0x05
|
||||
#define REG_DIGIT5 0x06
|
||||
#define REG_DIGIT6 0x07
|
||||
#define REG_DIGIT7 0x08
|
||||
#define REG_DECODEMODE 0x09
|
||||
#define REG_INTENSITY 0x0A
|
||||
#define REG_SCANLIMIT 0x0B
|
||||
#define REG_SHUTDOWN 0x0C
|
||||
#define REG_DISPLAYTEST 0x0F
|
||||
|
||||
/******************************************************************************
|
||||
* Constructors
|
||||
******************************************************************************/
|
||||
|
||||
Matrix::Matrix(uint8_t data, uint8_t clock, uint8_t load, uint8_t screens /* = 1 */)
|
||||
{
|
||||
// record pins for sw spi
|
||||
_pinData = data;
|
||||
_pinClock = clock;
|
||||
_pinLoad = load;
|
||||
|
||||
// set ddr for sw spi pins
|
||||
pinMode(_pinClock, OUTPUT);
|
||||
pinMode(_pinData, OUTPUT);
|
||||
pinMode(_pinLoad, OUTPUT);
|
||||
|
||||
// allocate screenbuffers
|
||||
_screens = screens;
|
||||
_buffer = (uint8_t*)calloc(_screens, 64);
|
||||
_maximumX = (_screens * 8);
|
||||
|
||||
// initialize registers
|
||||
clear(); // clear display
|
||||
setScanLimit(0x07); // use all rows/digits
|
||||
setBrightness(0x0F); // maximum brightness
|
||||
setRegister(REG_SHUTDOWN, 0x01); // normal operation
|
||||
setRegister(REG_DECODEMODE, 0x00); // pixels not integers
|
||||
setRegister(REG_DISPLAYTEST, 0x00); // not in test mode
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* MAX7219 SPI
|
||||
******************************************************************************/
|
||||
|
||||
// sends a single byte by sw spi (no latching)
|
||||
void Matrix::putByte(uint8_t data)
|
||||
{
|
||||
uint8_t i = 8;
|
||||
uint8_t mask;
|
||||
while(i > 0) {
|
||||
mask = 0x01 << (i - 1); // get bitmask
|
||||
digitalWrite(_pinClock, LOW); // tick
|
||||
if (data & mask){ // choose bit
|
||||
digitalWrite(_pinData, HIGH); // set 1
|
||||
}else{
|
||||
digitalWrite(_pinData, LOW); // set 0
|
||||
}
|
||||
digitalWrite(_pinClock, HIGH); // tock
|
||||
--i; // move to lesser bit
|
||||
}
|
||||
}
|
||||
|
||||
// sets register to a byte value for all screens
|
||||
void Matrix::setRegister(uint8_t reg, uint8_t data)
|
||||
{
|
||||
digitalWrite(_pinLoad, LOW); // begin
|
||||
for(uint8_t i = 0; i < _screens; ++i){
|
||||
putByte(reg); // specify register
|
||||
putByte(data); // send data
|
||||
}
|
||||
digitalWrite(_pinLoad, HIGH); // latch in data
|
||||
digitalWrite(_pinLoad, LOW); // end
|
||||
}
|
||||
|
||||
// syncs row of display with buffer
|
||||
void Matrix::syncRow(uint8_t row)
|
||||
{
|
||||
if (!_buffer) return;
|
||||
|
||||
// uint8_t's can't be negative, so don't test for negative row
|
||||
if (row >= 8) return;
|
||||
digitalWrite(_pinLoad, LOW); // begin
|
||||
for(uint8_t i = 0; i < _screens; ++i){
|
||||
putByte(8 - row); // specify register
|
||||
putByte(_buffer[row + (8 * i)]); // send data
|
||||
}
|
||||
digitalWrite(_pinLoad, HIGH); // latch in data
|
||||
digitalWrite(_pinLoad, LOW); // end
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* MAX7219 Configuration
|
||||
******************************************************************************/
|
||||
|
||||
// sets how many digits are displayed
|
||||
void Matrix::setScanLimit(uint8_t value)
|
||||
{
|
||||
setRegister(REG_SCANLIMIT, value & 0x07);
|
||||
}
|
||||
|
||||
// sets brightness of the display
|
||||
void Matrix::setBrightness(uint8_t value)
|
||||
{
|
||||
setRegister(REG_INTENSITY, value & 0x0F);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Helper Functions
|
||||
******************************************************************************/
|
||||
|
||||
void Matrix::buffer(uint8_t x, uint8_t y, uint8_t value)
|
||||
{
|
||||
if (!_buffer) return;
|
||||
|
||||
// uint8_t's can't be negative, so don't test for negative x and y.
|
||||
if (x >= _maximumX || y >= 8) return;
|
||||
|
||||
uint8_t offset = x; // record x
|
||||
x %= 8; // make x relative to a single matrix
|
||||
offset -= x; // calculate buffer offset
|
||||
|
||||
// wrap shift relative x for nexus module layout
|
||||
if (x == 0){
|
||||
x = 8;
|
||||
}
|
||||
--x;
|
||||
|
||||
// record value in buffer
|
||||
if(value){
|
||||
_buffer[y + offset] |= 0x01 << x;
|
||||
}else{
|
||||
_buffer[y + offset] &= ~(0x01 << x);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* User API
|
||||
******************************************************************************/
|
||||
|
||||
// buffers and writes to screen
|
||||
void Matrix::write(uint8_t x, uint8_t y, uint8_t value)
|
||||
{
|
||||
buffer(x, y, value);
|
||||
|
||||
// update affected row
|
||||
syncRow(y);
|
||||
}
|
||||
|
||||
void Matrix::write(uint8_t x, uint8_t y, Sprite sprite)
|
||||
{
|
||||
for (uint8_t i = 0; i < sprite.height(); i++){
|
||||
for (uint8_t j = 0; j < sprite.width(); j++)
|
||||
buffer(x + j, y + i, sprite.read(j, i));
|
||||
|
||||
syncRow(y + i);
|
||||
}
|
||||
}
|
||||
|
||||
// clears screens and buffers
|
||||
void Matrix::clear(void)
|
||||
{
|
||||
if (!_buffer) return;
|
||||
|
||||
// clear buffer
|
||||
for(uint8_t i = 0; i < 8; ++i){
|
||||
for(uint8_t j = 0; j < _screens; ++j){
|
||||
_buffer[i + (8 * j)] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// clear registers
|
||||
for(uint8_t i = 0; i < 8; ++i){
|
||||
syncRow(i);
|
||||
}
|
||||
}
|
||||
|
54
arduino-0022-linux-x64/libraries/Matrix/Matrix.h
Normal file
54
arduino-0022-linux-x64/libraries/Matrix/Matrix.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
Matrix.h - Max7219 LED Matrix library for Arduino & Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
||||
*/
|
||||
|
||||
#ifndef Matrix_h
|
||||
#define Matrix_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
class Sprite;
|
||||
|
||||
class Matrix
|
||||
{
|
||||
private:
|
||||
uint8_t _pinData;
|
||||
uint8_t _pinClock;
|
||||
uint8_t _pinLoad;
|
||||
|
||||
uint8_t* _buffer;
|
||||
uint8_t _screens;
|
||||
uint8_t _maximumX;
|
||||
|
||||
void putByte(uint8_t);
|
||||
void setRegister(uint8_t, uint8_t);
|
||||
void syncRow(uint8_t);
|
||||
|
||||
void setScanLimit(uint8_t);
|
||||
|
||||
void buffer(uint8_t, uint8_t, uint8_t);
|
||||
public:
|
||||
Matrix(uint8_t, uint8_t, uint8_t, uint8_t = 1);
|
||||
void setBrightness(uint8_t);
|
||||
void write(uint8_t, uint8_t, uint8_t);
|
||||
void write(uint8_t, uint8_t, Sprite);
|
||||
void clear(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#include <Sprite.h>
|
||||
#include <Matrix.h>
|
||||
|
||||
// Hello Matrix
|
||||
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||
|
||||
// Demonstrates the use of the Matrix library
|
||||
// For MAX7219 LED Matrix Controllers
|
||||
// Blinks welcoming face on screen
|
||||
|
||||
// Created 13 February 2006
|
||||
|
||||
/* create a new Matrix instance
|
||||
pin 0: data (din)
|
||||
pin 1: load (load)
|
||||
pin 2: clock (clk)
|
||||
*/
|
||||
Matrix myMatrix = Matrix(0, 2, 1);
|
||||
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
myMatrix.clear(); // clear display
|
||||
|
||||
delay(1000);
|
||||
|
||||
// turn some pixels on
|
||||
myMatrix.write(1, 5, HIGH);
|
||||
myMatrix.write(2, 2, HIGH);
|
||||
myMatrix.write(2, 6, HIGH);
|
||||
myMatrix.write(3, 6, HIGH);
|
||||
myMatrix.write(4, 6, HIGH);
|
||||
myMatrix.write(5, 2, HIGH);
|
||||
myMatrix.write(5, 6, HIGH);
|
||||
myMatrix.write(6, 5, HIGH);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#include <Sprite.h>
|
||||
#include <Matrix.h>
|
||||
|
||||
// Sprite Animation
|
||||
// by Nicholas Zambetti <http://www.zambetti.com>
|
||||
|
||||
// Demonstrates the use of the Matrix & Sprite libraries
|
||||
// Displays animated waveform graphic on screen
|
||||
|
||||
// Created 29 March 2006
|
||||
|
||||
/* create a new Matrix instance
|
||||
pin 0: data (din)
|
||||
pin 1: load (load)
|
||||
pin 2: clock (clk)
|
||||
*/
|
||||
Matrix myMatrix = Matrix(0, 2, 1);
|
||||
|
||||
/* create a new Sprite instance
|
||||
8 pixels wide, 4 pixels tall
|
||||
*/
|
||||
Sprite wave = Sprite(
|
||||
8, 4,
|
||||
B00011000,
|
||||
B00100100,
|
||||
B01000010,
|
||||
B10000001
|
||||
);
|
||||
|
||||
void setup()
|
||||
{
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
|
||||
void loop()
|
||||
{
|
||||
myMatrix.write(x, 2, wave); // place sprite on screen
|
||||
myMatrix.write(x - 8, 2, wave); // place sprite again, elsewhere on screen
|
||||
delay(75); // wait a little bit
|
||||
myMatrix.clear(); // clear the screen for next animation frame
|
||||
if(x == 8) // if reached end of animation sequence
|
||||
{
|
||||
x = 0; // start from beginning
|
||||
}
|
||||
x++; // advance x coordinate to the right
|
||||
}
|
||||
|
22
arduino-0022-linux-x64/libraries/Matrix/keywords.txt
Normal file
22
arduino-0022-linux-x64/libraries/Matrix/keywords.txt
Normal file
|
@ -0,0 +1,22 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map For Matrix
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Matrix KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
setBrightness KEYWORD2
|
||||
write KEYWORD2
|
||||
clear KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
65
arduino-0022-linux-x64/libraries/SD/File.cpp
Normal file
65
arduino-0022-linux-x64/libraries/SD/File.cpp
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
|
||||
SD - a slightly more friendly wrapper for sdfatlib
|
||||
|
||||
This library aims to expose a subset of SD card functionality
|
||||
in the form of a higher level "wrapper" object.
|
||||
|
||||
License: GNU General Public License V3
|
||||
(Because sdfatlib is licensed with this.)
|
||||
|
||||
(C) Copyright 2010 SparkFun Electronics
|
||||
|
||||
*/
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
void File::write(uint8_t val) {
|
||||
SD.file.write(val);
|
||||
}
|
||||
|
||||
void File::write(const char *str) {
|
||||
SD.file.write(str);
|
||||
}
|
||||
|
||||
void File::write(const uint8_t *buf, size_t size) {
|
||||
SD.file.write(buf, size);
|
||||
}
|
||||
|
||||
int File::peek() {
|
||||
char c = SD.file.read();
|
||||
if (c != -1) SD.file.seekCur(-1);
|
||||
return c;
|
||||
}
|
||||
|
||||
int File::read() {
|
||||
return SD.file.read();
|
||||
}
|
||||
|
||||
int File::available() {
|
||||
return size() - position();
|
||||
}
|
||||
|
||||
void File::flush() {
|
||||
SD.file.sync();
|
||||
}
|
||||
|
||||
boolean File::seek(uint32_t pos) {
|
||||
return SD.file.seekSet(pos);
|
||||
}
|
||||
|
||||
uint32_t File::position() {
|
||||
return SD.file.curPosition();
|
||||
}
|
||||
|
||||
uint32_t File::size() {
|
||||
return SD.file.fileSize();
|
||||
}
|
||||
|
||||
void File::close() {
|
||||
SD.file.close();
|
||||
}
|
||||
|
||||
File::operator bool() {
|
||||
return SD.file.isOpen();
|
||||
}
|
11
arduino-0022-linux-x64/libraries/SD/README.txt
Normal file
11
arduino-0022-linux-x64/libraries/SD/README.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
** SD - a slightly more friendly wrapper for sdfatlib **
|
||||
|
||||
This library aims to expose a subset of SD card functionality in the
|
||||
form of a higher level "wrapper" object.
|
||||
|
||||
License: GNU General Public License V3
|
||||
(Because sdfatlib is licensed with this.)
|
||||
|
||||
(C) Copyright 2010 SparkFun Electronics
|
||||
|
439
arduino-0022-linux-x64/libraries/SD/SD.cpp
Normal file
439
arduino-0022-linux-x64/libraries/SD/SD.cpp
Normal file
|
@ -0,0 +1,439 @@
|
|||
/*
|
||||
|
||||
SD - a slightly more friendly wrapper for sdfatlib
|
||||
|
||||
This library aims to expose a subset of SD card functionality
|
||||
in the form of a higher level "wrapper" object.
|
||||
|
||||
License: GNU General Public License V3
|
||||
(Because sdfatlib is licensed with this.)
|
||||
|
||||
(C) Copyright 2010 SparkFun Electronics
|
||||
|
||||
|
||||
This library provides four key benefits:
|
||||
|
||||
* Including `SD.h` automatically creates a global
|
||||
`SD` object which can be interacted with in a similar
|
||||
manner to other standard global objects like `Serial` and `Ethernet`.
|
||||
|
||||
* Boilerplate initialisation code is contained in one method named
|
||||
`begin` and no further objects need to be created in order to access
|
||||
the SD card.
|
||||
|
||||
* Calls to `open` can supply a full path name including parent
|
||||
directories which simplifies interacting with files in subdirectories.
|
||||
|
||||
* Utility methods are provided to determine whether a file exists
|
||||
and to create a directory heirarchy.
|
||||
|
||||
|
||||
Note however that not all functionality provided by the underlying
|
||||
sdfatlib library is exposed.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Implementation Notes
|
||||
|
||||
In order to handle multi-directory path traversal, functionality that
|
||||
requires this ability is implemented as callback functions.
|
||||
|
||||
Individual methods call the `walkPath` function which performs the actual
|
||||
directory traversal (swapping between two different directory/file handles
|
||||
along the way) and at each level calls the supplied callback function.
|
||||
|
||||
Some types of functionality will take an action at each level (e.g. exists
|
||||
or make directory) which others will only take an action at the bottom
|
||||
level (e.g. open).
|
||||
|
||||
*/
|
||||
|
||||
#include "SD.h"
|
||||
|
||||
// Used by `getNextPathComponent`
|
||||
#define MAX_COMPONENT_LEN 12 // What is max length?
|
||||
#define PATH_COMPONENT_BUFFER_LEN MAX_COMPONENT_LEN+1
|
||||
|
||||
bool getNextPathComponent(char *path, unsigned int *p_offset,
|
||||
char *buffer) {
|
||||
/*
|
||||
|
||||
Parse individual path components from a path.
|
||||
|
||||
e.g. after repeated calls '/foo/bar/baz' will be split
|
||||
into 'foo', 'bar', 'baz'.
|
||||
|
||||
This is similar to `strtok()` but copies the component into the
|
||||
supplied buffer rather than modifying the original string.
|
||||
|
||||
|
||||
`buffer` needs to be PATH_COMPONENT_BUFFER_LEN in size.
|
||||
|
||||
`p_offset` needs to point to an integer of the offset at
|
||||
which the previous path component finished.
|
||||
|
||||
Returns `true` if more components remain.
|
||||
|
||||
Returns `false` if this is the last component.
|
||||
(This means path ended with 'foo' or 'foo/'.)
|
||||
|
||||
*/
|
||||
|
||||
// TODO: Have buffer local to this function, so we know it's the
|
||||
// correct length?
|
||||
|
||||
int bufferOffset = 0;
|
||||
|
||||
int offset = *p_offset;
|
||||
|
||||
// Skip root or other separator
|
||||
if (path[offset] == '/') {
|
||||
offset++;
|
||||
}
|
||||
|
||||
// Copy the next next path segment
|
||||
while (bufferOffset < MAX_COMPONENT_LEN
|
||||
&& (path[offset] != '/')
|
||||
&& (path[offset] != '\0')) {
|
||||
buffer[bufferOffset++] = path[offset++];
|
||||
}
|
||||
|
||||
buffer[bufferOffset] = '\0';
|
||||
|
||||
// Skip trailing separator so we can determine if this
|
||||
// is the last component in the path or not.
|
||||
if (path[offset] == '/') {
|
||||
offset++;
|
||||
}
|
||||
|
||||
*p_offset = offset;
|
||||
|
||||
return (path[offset] != '\0');
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean walkPath(char *filepath, SdFile& parentDir,
|
||||
boolean (*callback)(SdFile& parentDir,
|
||||
char *filePathComponent,
|
||||
boolean isLastComponent,
|
||||
void *object),
|
||||
void *object = NULL) {
|
||||
/*
|
||||
|
||||
When given a file path (and parent directory--normally root),
|
||||
this function traverses the directories in the path and at each
|
||||
level calls the supplied callback function while also providing
|
||||
the supplied object for context if required.
|
||||
|
||||
e.g. given the path '/foo/bar/baz'
|
||||
the callback would be called at the equivalent of
|
||||
'/foo', '/foo/bar' and '/foo/bar/baz'.
|
||||
|
||||
The implementation swaps between two different directory/file
|
||||
handles as it traverses the directories and does not use recursion
|
||||
in an attempt to use memory efficiently.
|
||||
|
||||
If a callback wishes to stop the directory traversal it should
|
||||
return false--in this case the function will stop the traversal,
|
||||
tidy up and return false.
|
||||
|
||||
If a directory path doesn't exist at some point this function will
|
||||
also return false and not subsequently call the callback.
|
||||
|
||||
If a directory path specified is complete, valid and the callback
|
||||
did not indicate the traversal should be interrupted then this
|
||||
function will return true.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
SdFile subfile1;
|
||||
SdFile subfile2;
|
||||
|
||||
char buffer[PATH_COMPONENT_BUFFER_LEN];
|
||||
|
||||
unsigned int offset = 0;
|
||||
|
||||
SdFile *p_parent;
|
||||
SdFile *p_child;
|
||||
|
||||
SdFile *p_tmp_sdfile;
|
||||
|
||||
p_child = &subfile1;
|
||||
|
||||
p_parent = &parentDir;
|
||||
|
||||
while (true) {
|
||||
|
||||
boolean moreComponents = getNextPathComponent(filepath, &offset, buffer);
|
||||
|
||||
boolean shouldContinue = callback((*p_parent), buffer, !moreComponents, object);
|
||||
|
||||
if (!shouldContinue) {
|
||||
// TODO: Don't repeat this code?
|
||||
// If it's one we've created then we
|
||||
// don't need the parent handle anymore.
|
||||
if (p_parent != &parentDir) {
|
||||
(*p_parent).close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!moreComponents) {
|
||||
break;
|
||||
}
|
||||
|
||||
boolean exists = (*p_child).open(*p_parent, buffer, O_RDONLY);
|
||||
|
||||
// If it's one we've created then we
|
||||
// don't need the parent handle anymore.
|
||||
if (p_parent != &parentDir) {
|
||||
(*p_parent).close();
|
||||
}
|
||||
|
||||
// Handle case when it doesn't exist and we can't continue...
|
||||
if (exists) {
|
||||
// We alternate between two file handles as we go down
|
||||
// the path.
|
||||
if (p_parent == &parentDir) {
|
||||
p_parent = &subfile2;
|
||||
}
|
||||
|
||||
p_tmp_sdfile = p_parent;
|
||||
p_parent = p_child;
|
||||
p_child = p_tmp_sdfile;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_parent != &parentDir) {
|
||||
(*p_parent).close(); // TODO: Return/ handle different?
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The callbacks used to implement various functionality follow.
|
||||
|
||||
Each callback is supplied with a parent directory handle,
|
||||
character string with the name of the current file path component,
|
||||
a flag indicating if this component is the last in the path and
|
||||
a pointer to an arbitrary object used for context.
|
||||
|
||||
*/
|
||||
|
||||
boolean callback_pathExists(SdFile& parentDir, char *filePathComponent,
|
||||
boolean isLastComponent, void *object) {
|
||||
/*
|
||||
|
||||
Callback used to determine if a file/directory exists in parent
|
||||
directory.
|
||||
|
||||
Returns true if file path exists.
|
||||
|
||||
*/
|
||||
SdFile child;
|
||||
|
||||
boolean exists = child.open(parentDir, filePathComponent, O_RDONLY);
|
||||
|
||||
if (exists) {
|
||||
child.close();
|
||||
}
|
||||
|
||||
return exists;
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean callback_makeDirPath(SdFile& parentDir, char *filePathComponent,
|
||||
boolean isLastComponent, void *object) {
|
||||
/*
|
||||
|
||||
Callback used to create a directory in the parent directory if
|
||||
it does not already exist.
|
||||
|
||||
Returns true if a directory was created or it already existed.
|
||||
|
||||
*/
|
||||
boolean result = false;
|
||||
SdFile child;
|
||||
|
||||
result = callback_pathExists(parentDir, filePathComponent, isLastComponent, object);
|
||||
if (!result) {
|
||||
result = child.makeDir(parentDir, filePathComponent);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
boolean callback_openPath(SdFile& parentDir, char *filePathComponent,
|
||||
boolean isLastComponent, void *object) {
|
||||
/*
|
||||
|
||||
Callback used to open a file specified by a filepath that may
|
||||
specify one or more directories above it.
|
||||
|
||||
Expects the context object to be an instance of `SDClass` and
|
||||
will use the `file` property of the instance to open the requested
|
||||
file/directory with the associated file open mode property.
|
||||
|
||||
Always returns true if the directory traversal hasn't reached the
|
||||
bottom of the directory heirarchy.
|
||||
|
||||
Returns false once the file has been opened--to prevent the traversal
|
||||
from descending further. (This may be unnecessary.)
|
||||
|
||||
*/
|
||||
if (isLastComponent) {
|
||||
SDClass *p_SD = static_cast<SDClass*>(object);
|
||||
p_SD->file.open(parentDir, filePathComponent, p_SD->fileOpenMode);
|
||||
if (p_SD->fileOpenMode == FILE_WRITE) {
|
||||
p_SD->file.seekSet(p_SD->file.fileSize());
|
||||
}
|
||||
// TODO: Return file open result?
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
boolean callback_remove(SdFile& parentDir, char *filePathComponent,
|
||||
boolean isLastComponent, void *object) {
|
||||
if (isLastComponent) {
|
||||
return SdFile::remove(parentDir, filePathComponent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean callback_rmdir(SdFile& parentDir, char *filePathComponent,
|
||||
boolean isLastComponent, void *object) {
|
||||
if (isLastComponent) {
|
||||
SdFile f;
|
||||
if (!f.open(parentDir, filePathComponent, O_READ)) return false;
|
||||
return f.rmDir();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Implementation of class used to create `SDCard` object. */
|
||||
|
||||
|
||||
|
||||
boolean SDClass::begin(uint8_t csPin) {
|
||||
/*
|
||||
|
||||
Performs the initialisation required by the sdfatlib library.
|
||||
|
||||
Return true if initialization succeeds, false otherwise.
|
||||
|
||||
*/
|
||||
return card.init(SPI_HALF_SPEED, csPin) &&
|
||||
volume.init(card) &&
|
||||
root.openRoot(volume);
|
||||
}
|
||||
|
||||
|
||||
File SDClass::open(char *filepath, uint8_t mode) {
|
||||
/*
|
||||
|
||||
Open the supplied file path for reading or writing.
|
||||
|
||||
The file content can be accessed via the `file` property of
|
||||
the `SDClass` object--this property is currently
|
||||
a standard `SdFile` object from `sdfatlib`.
|
||||
|
||||
Defaults to read only.
|
||||
|
||||
If `write` is true, default action (when `append` is true) is to
|
||||
append data to the end of the file.
|
||||
|
||||
If `append` is false then the file will be truncated first.
|
||||
|
||||
If the file does not exist and it is opened for writing the file
|
||||
will be created.
|
||||
|
||||
An attempt to open a file for reading that does not exist is an
|
||||
error.
|
||||
|
||||
*/
|
||||
|
||||
// TODO: Allow for read&write? (Possibly not, as it requires seek.)
|
||||
|
||||
fileOpenMode = mode;
|
||||
walkPath(filepath, root, callback_openPath, this);
|
||||
|
||||
return File();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//boolean SDClass::close() {
|
||||
// /*
|
||||
//
|
||||
// Closes the file opened by the `open` method.
|
||||
//
|
||||
// */
|
||||
// file.close();
|
||||
//}
|
||||
|
||||
|
||||
boolean SDClass::exists(char *filepath) {
|
||||
/*
|
||||
|
||||
Returns true if the supplied file path exists.
|
||||
|
||||
*/
|
||||
return walkPath(filepath, root, callback_pathExists);
|
||||
}
|
||||
|
||||
|
||||
//boolean SDClass::exists(char *filepath, SdFile& parentDir) {
|
||||
// /*
|
||||
//
|
||||
// Returns true if the supplied file path rooted at `parentDir`
|
||||
// exists.
|
||||
//
|
||||
// */
|
||||
// return walkPath(filepath, parentDir, callback_pathExists);
|
||||
//}
|
||||
|
||||
|
||||
boolean SDClass::mkdir(char *filepath) {
|
||||
/*
|
||||
|
||||
Makes a single directory or a heirarchy of directories.
|
||||
|
||||
A rough equivalent to `mkdir -p`.
|
||||
|
||||
*/
|
||||
return walkPath(filepath, root, callback_makeDirPath);
|
||||
}
|
||||
|
||||
boolean SDClass::rmdir(char *filepath) {
|
||||
/*
|
||||
|
||||
Makes a single directory or a heirarchy of directories.
|
||||
|
||||
A rough equivalent to `mkdir -p`.
|
||||
|
||||
*/
|
||||
return walkPath(filepath, root, callback_rmdir);
|
||||
}
|
||||
|
||||
boolean SDClass::remove(char *filepath) {
|
||||
return walkPath(filepath, root, callback_remove);
|
||||
}
|
||||
|
||||
SDClass SD;
|
88
arduino-0022-linux-x64/libraries/SD/SD.h
Normal file
88
arduino-0022-linux-x64/libraries/SD/SD.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
|
||||
SD - a slightly more friendly wrapper for sdfatlib
|
||||
|
||||
This library aims to expose a subset of SD card functionality
|
||||
in the form of a higher level "wrapper" object.
|
||||
|
||||
License: GNU General Public License V3
|
||||
(Because sdfatlib is licensed with this.)
|
||||
|
||||
(C) Copyright 2010 SparkFun Electronics
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __SD_H__
|
||||
#define __SD_H__
|
||||
|
||||
#include <WProgram.h>
|
||||
|
||||
#include <utility/SdFat.h>
|
||||
#include <utility/SdFatUtil.h>
|
||||
|
||||
#define FILE_READ O_READ
|
||||
#define FILE_WRITE (O_READ | O_WRITE | O_CREAT | O_SYNC)
|
||||
|
||||
class File : public Stream {
|
||||
public:
|
||||
virtual void write(uint8_t);
|
||||
virtual void write(const char *str);
|
||||
virtual void write(const uint8_t *buf, size_t size);
|
||||
virtual int read();
|
||||
virtual int peek();
|
||||
virtual int available();
|
||||
virtual void flush();
|
||||
boolean seek(uint32_t pos);
|
||||
uint32_t position();
|
||||
uint32_t size();
|
||||
void close();
|
||||
operator bool();
|
||||
};
|
||||
|
||||
class SDClass {
|
||||
|
||||
private:
|
||||
// These are required for initialisation and use of sdfatlib
|
||||
Sd2Card card;
|
||||
SdVolume volume;
|
||||
SdFile root;
|
||||
|
||||
public:
|
||||
// This needs to be called to set up the connection to the SD card
|
||||
// before other methods are used.
|
||||
boolean begin(uint8_t csPin = SD_CHIP_SELECT_PIN);
|
||||
|
||||
// Open the specified file/directory with the supplied mode (e.g. read or
|
||||
// write, etc). Returns a File object for interacting with the file.
|
||||
// Note that currently only one file can be open at a time.
|
||||
File open(char *filename, uint8_t mode = FILE_READ);
|
||||
|
||||
// Methods to determine if the requested file path exists.
|
||||
boolean exists(char *filepath);
|
||||
|
||||
// Create the requested directory heirarchy--if intermediate directories
|
||||
// do not exist they will be created.
|
||||
boolean mkdir(char *filepath);
|
||||
|
||||
// Delete the file.
|
||||
boolean remove(char *filepath);
|
||||
|
||||
boolean rmdir(char *filepath);
|
||||
|
||||
private:
|
||||
SdFile file;
|
||||
|
||||
// This is used to determine the mode used to open a file
|
||||
// it's here because it's the easiest place to pass the
|
||||
// information through the directory walking function. But
|
||||
// it's probably not the best place for it.
|
||||
// It shouldn't be set directly--it is set via the parameters to `open`.
|
||||
int fileOpenMode;
|
||||
|
||||
friend class File;
|
||||
friend boolean callback_openPath(SdFile&, char *, boolean, void *);
|
||||
};
|
||||
|
||||
extern SDClass SD;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
SD card datalogger
|
||||
|
||||
This example shows how to log data from three analog sensors
|
||||
to an SD card using the SD library.
|
||||
|
||||
The circuit:
|
||||
* analog sensors on analog ins 0, 1, and 2
|
||||
* SD card attached to SPI bus as follows:
|
||||
** MOSI - pin 11
|
||||
** MISO - pin 12
|
||||
** CLK - pin 13
|
||||
** CS - pin 4
|
||||
|
||||
created 24 Nov 2010
|
||||
updated 2 Dec 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
|
||||
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
|
||||
// 53 on the Mega) must be left as an output or the SD library
|
||||
// functions will not work.
|
||||
const int chipSelect = 4;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.print("Initializing SD card...");
|
||||
// make sure that the default chip select pin is set to
|
||||
// output, even if you don't use it:
|
||||
pinMode(10, OUTPUT);
|
||||
|
||||
// see if the card is present and can be initialized:
|
||||
if (!SD.begin(chipSelect)) {
|
||||
Serial.println("Card failed, or not present");
|
||||
// don't do anything more:
|
||||
return;
|
||||
}
|
||||
Serial.println("card initialized.");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// make a string for assembling the data to log:
|
||||
String dataString = "";
|
||||
|
||||
// read three sensors and append to the string:
|
||||
for (int analogPin = 0; analogPin < 3; analogPin++) {
|
||||
int sensor = analogRead(analogPin);
|
||||
dataString += String(sensor);
|
||||
if (analogPin < 2) {
|
||||
dataString += ",";
|
||||
}
|
||||
}
|
||||
|
||||
// open the file. note that only one file can be open at a time,
|
||||
// so you have to close this one before opening another.
|
||||
File dataFile = SD.open("datalog.txt", FILE_WRITE);
|
||||
|
||||
// if the file is available, write to it:
|
||||
if (dataFile) {
|
||||
dataFile.println(dataString);
|
||||
dataFile.close();
|
||||
// print to the serial port too:
|
||||
Serial.println(dataString);
|
||||
}
|
||||
// if the file isn't open, pop up an error:
|
||||
else {
|
||||
Serial.println("error opening datalog.txt");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
SD card file dump
|
||||
|
||||
This example shows how to read a file from the SD card using the
|
||||
SD library and send it over the serial port.
|
||||
|
||||
The circuit:
|
||||
* SD card attached to SPI bus as follows:
|
||||
** MOSI - pin 11
|
||||
** MISO - pin 12
|
||||
** CLK - pin 13
|
||||
** CS - pin 4
|
||||
|
||||
created 22 December 2010
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
|
||||
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
|
||||
// 53 on the Mega) must be left as an output or the SD library
|
||||
// functions will not work.
|
||||
const int chipSelect = 4;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.print("Initializing SD card...");
|
||||
// make sure that the default chip select pin is set to
|
||||
// output, even if you don't use it:
|
||||
pinMode(10, OUTPUT);
|
||||
|
||||
// see if the card is present and can be initialized:
|
||||
if (!SD.begin(chipSelect)) {
|
||||
Serial.println("Card failed, or not present");
|
||||
// don't do anything more:
|
||||
return;
|
||||
}
|
||||
Serial.println("card initialized.");
|
||||
|
||||
// open the file. note that only one file can be open at a time,
|
||||
// so you have to close this one before opening another.
|
||||
File dataFile = SD.open("datalog.txt");
|
||||
|
||||
// if the file is available, write to it:
|
||||
if (dataFile) {
|
||||
while (dataFile.available()) {
|
||||
Serial.write(dataFile.read());
|
||||
}
|
||||
dataFile.close();
|
||||
}
|
||||
// if the file isn't open, pop up an error:
|
||||
else {
|
||||
Serial.println("error opening datalog.txt");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
78
arduino-0022-linux-x64/libraries/SD/examples/Files/Files.pde
Normal file
78
arduino-0022-linux-x64/libraries/SD/examples/Files/Files.pde
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
SD card basic file example
|
||||
|
||||
This example shows how to create and destroy an SD card file
|
||||
The circuit:
|
||||
* SD card attached to SPI bus as follows:
|
||||
** MOSI - pin 11
|
||||
** MISO - pin 12
|
||||
** CLK - pin 13
|
||||
** CS - pin 4
|
||||
|
||||
created Nov 2010
|
||||
by David A. Mellis
|
||||
updated 2 Dec 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
*/
|
||||
#include <SD.h>
|
||||
|
||||
File myFile;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.print("Initializing SD card...");
|
||||
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
|
||||
// Note that even if it's not used as the CS pin, the hardware SS pin
|
||||
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
|
||||
// or the SD library functions will not work.
|
||||
pinMode(10, OUTPUT);
|
||||
|
||||
if (!SD.begin(4)) {
|
||||
Serial.println("initialization failed!");
|
||||
return;
|
||||
}
|
||||
Serial.println("initialization done.");
|
||||
|
||||
if (SD.exists("example.txt")) {
|
||||
Serial.println("example.txt exists.");
|
||||
}
|
||||
else {
|
||||
Serial.println("example.txt doesn't exist.");
|
||||
}
|
||||
|
||||
// open a new file and immediately close it:
|
||||
Serial.println("Creating example.txt...");
|
||||
myFile = SD.open("example.txt", FILE_WRITE);
|
||||
myFile.close();
|
||||
|
||||
// Check to see if the file exists:
|
||||
if (SD.exists("example.txt")) {
|
||||
Serial.println("example.txt exists.");
|
||||
}
|
||||
else {
|
||||
Serial.println("example.txt doesn't exist.");
|
||||
}
|
||||
|
||||
// delete the file:
|
||||
Serial.println("Removing example.txt...");
|
||||
SD.remove("example.txt");
|
||||
|
||||
if (SD.exists("example.txt")){
|
||||
Serial.println("example.txt exists.");
|
||||
}
|
||||
else {
|
||||
Serial.println("example.txt doesn't exist.");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing happens after setup finishes.
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
SD card read/write
|
||||
|
||||
This example shows how to read and write data to and from an SD card file
|
||||
The circuit:
|
||||
* SD card attached to SPI bus as follows:
|
||||
** MOSI - pin 11
|
||||
** MISO - pin 12
|
||||
** CLK - pin 13
|
||||
** CS - pin 4
|
||||
|
||||
created Nov 2010
|
||||
by David A. Mellis
|
||||
updated 2 Dec 2010
|
||||
by Tom Igoe
|
||||
|
||||
This example code is in the public domain.
|
||||
|
||||
*/
|
||||
|
||||
#include <SD.h>
|
||||
|
||||
File myFile;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.print("Initializing SD card...");
|
||||
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
|
||||
// Note that even if it's not used as the CS pin, the hardware SS pin
|
||||
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
|
||||
// or the SD library functions will not work.
|
||||
pinMode(10, OUTPUT);
|
||||
|
||||
if (!SD.begin(4)) {
|
||||
Serial.println("initialization failed!");
|
||||
return;
|
||||
}
|
||||
Serial.println("initialization done.");
|
||||
|
||||
// open the file. note that only one file can be open at a time,
|
||||
// so you have to close this one before opening another.
|
||||
myFile = SD.open("test.txt", FILE_WRITE);
|
||||
|
||||
// if the file opened okay, write to it:
|
||||
if (myFile) {
|
||||
Serial.print("Writing to test.txt...");
|
||||
myFile.println("testing 1, 2, 3.");
|
||||
// close the file:
|
||||
myFile.close();
|
||||
Serial.println("done.");
|
||||
} else {
|
||||
// if the file didn't open, print an error:
|
||||
Serial.println("error opening test.txt");
|
||||
}
|
||||
|
||||
// re-open the file for reading:
|
||||
myFile = SD.open("test.txt");
|
||||
if (myFile) {
|
||||
Serial.println("test.txt:");
|
||||
|
||||
// read from the file until there's nothing else in it:
|
||||
while (myFile.available()) {
|
||||
Serial.write(myFile.read());
|
||||
}
|
||||
// close the file:
|
||||
myFile.close();
|
||||
} else {
|
||||
// if the file didn't open, print an error:
|
||||
Serial.println("error opening test.txt");
|
||||
}
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
// nothing happens after setup
|
||||
}
|
||||
|
||||
|
30
arduino-0022-linux-x64/libraries/SD/keywords.txt
Normal file
30
arduino-0022-linux-x64/libraries/SD/keywords.txt
Normal file
|
@ -0,0 +1,30 @@
|
|||
#######################################
|
||||
# Syntax Coloring Map SD
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SD KEYWORD1
|
||||
File KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
begin KEYWORD2
|
||||
exists KEYWORD2
|
||||
mkdir KEYWORD2
|
||||
remove KEYWORD2
|
||||
rmdir KEYWORD2
|
||||
open KEYWORD2
|
||||
close KEYWORD2
|
||||
seek KEYWORD2
|
||||
position KEYWORD2
|
||||
size KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
FILE_READ LITERAL1
|
||||
FILE_WRITE LITERAL1
|
418
arduino-0022-linux-x64/libraries/SD/utility/FatStructs.h
Normal file
418
arduino-0022-linux-x64/libraries/SD/utility/FatStructs.h
Normal file
|
@ -0,0 +1,418 @@
|
|||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef FatStructs_h
|
||||
#define FatStructs_h
|
||||
/**
|
||||
* \file
|
||||
* FAT file structures
|
||||
*/
|
||||
/*
|
||||
* mostly from Microsoft document fatgen103.doc
|
||||
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
/** Value for byte 510 of boot block or MBR */
|
||||
uint8_t const BOOTSIG0 = 0X55;
|
||||
/** Value for byte 511 of boot block or MBR */
|
||||
uint8_t const BOOTSIG1 = 0XAA;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct partitionTable
|
||||
* \brief MBR partition table entry
|
||||
*
|
||||
* A partition table entry for a MBR formatted storage device.
|
||||
* The MBR partition table has four entries.
|
||||
*/
|
||||
struct partitionTable {
|
||||
/**
|
||||
* Boot Indicator . Indicates whether the volume is the active
|
||||
* partition. Legal values include: 0X00. Do not use for booting.
|
||||
* 0X80 Active partition.
|
||||
*/
|
||||
uint8_t boot;
|
||||
/**
|
||||
* Head part of Cylinder-head-sector address of the first block in
|
||||
* the partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t beginHead;
|
||||
/**
|
||||
* Sector part of Cylinder-head-sector address of the first block in
|
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
*/
|
||||
unsigned beginSector : 6;
|
||||
/** High bits cylinder for first block in partition. */
|
||||
unsigned beginCylinderHigh : 2;
|
||||
/**
|
||||
* Combine beginCylinderLow with beginCylinderHigh. Legal values
|
||||
* are 0-1023. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t beginCylinderLow;
|
||||
/**
|
||||
* Partition type. See defines that begin with PART_TYPE_ for
|
||||
* some Microsoft partition types.
|
||||
*/
|
||||
uint8_t type;
|
||||
/**
|
||||
* head part of cylinder-head-sector address of the last sector in the
|
||||
* partition. Legal values are 0-255. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t endHead;
|
||||
/**
|
||||
* Sector part of cylinder-head-sector address of the last sector in
|
||||
* the partition. Legal values are 1-63. Only used in old PC BIOS.
|
||||
*/
|
||||
unsigned endSector : 6;
|
||||
/** High bits of end cylinder */
|
||||
unsigned endCylinderHigh : 2;
|
||||
/**
|
||||
* Combine endCylinderLow with endCylinderHigh. Legal values
|
||||
* are 0-1023. Only used in old PC BIOS.
|
||||
*/
|
||||
uint8_t endCylinderLow;
|
||||
/** Logical block address of the first block in the partition. */
|
||||
uint32_t firstSector;
|
||||
/** Length of the partition, in blocks. */
|
||||
uint32_t totalSectors;
|
||||
};
|
||||
/** Type name for partitionTable */
|
||||
typedef struct partitionTable part_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct masterBootRecord
|
||||
*
|
||||
* \brief Master Boot Record
|
||||
*
|
||||
* The first block of a storage device that is formatted with a MBR.
|
||||
*/
|
||||
struct masterBootRecord {
|
||||
/** Code Area for master boot program. */
|
||||
uint8_t codeArea[440];
|
||||
/** Optional WindowsNT disk signature. May contain more boot code. */
|
||||
uint32_t diskSignature;
|
||||
/** Usually zero but may be more boot code. */
|
||||
uint16_t usuallyZero;
|
||||
/** Partition tables. */
|
||||
part_t part[4];
|
||||
/** First MBR signature byte. Must be 0X55 */
|
||||
uint8_t mbrSig0;
|
||||
/** Second MBR signature byte. Must be 0XAA */
|
||||
uint8_t mbrSig1;
|
||||
};
|
||||
/** Type name for masterBootRecord */
|
||||
typedef struct masterBootRecord mbr_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct biosParmBlock
|
||||
*
|
||||
* \brief BIOS parameter block
|
||||
*
|
||||
* The BIOS parameter block describes the physical layout of a FAT volume.
|
||||
*/
|
||||
struct biosParmBlock {
|
||||
/**
|
||||
* Count of bytes per sector. This value may take on only the
|
||||
* following values: 512, 1024, 2048 or 4096
|
||||
*/
|
||||
uint16_t bytesPerSector;
|
||||
/**
|
||||
* Number of sectors per allocation unit. This value must be a
|
||||
* power of 2 that is greater than 0. The legal values are
|
||||
* 1, 2, 4, 8, 16, 32, 64, and 128.
|
||||
*/
|
||||
uint8_t sectorsPerCluster;
|
||||
/**
|
||||
* Number of sectors before the first FAT.
|
||||
* This value must not be zero.
|
||||
*/
|
||||
uint16_t reservedSectorCount;
|
||||
/** The count of FAT data structures on the volume. This field should
|
||||
* always contain the value 2 for any FAT volume of any type.
|
||||
*/
|
||||
uint8_t fatCount;
|
||||
/**
|
||||
* For FAT12 and FAT16 volumes, this field contains the count of
|
||||
* 32-byte directory entries in the root directory. For FAT32 volumes,
|
||||
* this field must be set to 0. For FAT12 and FAT16 volumes, this
|
||||
* value should always specify a count that when multiplied by 32
|
||||
* results in a multiple of bytesPerSector. FAT16 volumes should
|
||||
* use the value 512.
|
||||
*/
|
||||
uint16_t rootDirEntryCount;
|
||||
/**
|
||||
* This field is the old 16-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then totalSectors32
|
||||
* must be non-zero. For FAT32 volumes, this field must be 0. For
|
||||
* FAT12 and FAT16 volumes, this field contains the sector count, and
|
||||
* totalSectors32 is 0 if the total sector count fits
|
||||
* (is less than 0x10000).
|
||||
*/
|
||||
uint16_t totalSectors16;
|
||||
/**
|
||||
* This dates back to the old MS-DOS 1.x media determination and is
|
||||
* no longer usually used for anything. 0xF8 is the standard value
|
||||
* for fixed (non-removable) media. For removable media, 0xF0 is
|
||||
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
|
||||
*/
|
||||
uint8_t mediaType;
|
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
|
||||
* On FAT32 volumes this field must be 0, and sectorsPerFat32
|
||||
* contains the FAT size count.
|
||||
*/
|
||||
uint16_t sectorsPerFat16;
|
||||
/** Sectors per track for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t sectorsPerTrtack;
|
||||
/** Number of heads for interrupt 0x13. Not used otherwise. */
|
||||
uint16_t headCount;
|
||||
/**
|
||||
* Count of hidden sectors preceding the partition that contains this
|
||||
* FAT volume. This field is generally only relevant for media
|
||||
* visible on interrupt 0x13.
|
||||
*/
|
||||
uint32_t hidddenSectors;
|
||||
/**
|
||||
* This field is the new 32-bit total count of sectors on the volume.
|
||||
* This count includes the count of all sectors in all four regions
|
||||
* of the volume. This field can be 0; if it is 0, then
|
||||
* totalSectors16 must be non-zero.
|
||||
*/
|
||||
uint32_t totalSectors32;
|
||||
/**
|
||||
* Count of sectors occupied by one FAT on FAT32 volumes.
|
||||
*/
|
||||
uint32_t sectorsPerFat32;
|
||||
/**
|
||||
* This field is only defined for FAT32 media and does not exist on
|
||||
* FAT12 and FAT16 media.
|
||||
* Bits 0-3 -- Zero-based number of active FAT.
|
||||
* Only valid if mirroring is disabled.
|
||||
* Bits 4-6 -- Reserved.
|
||||
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
|
||||
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
|
||||
* Bits 8-15 -- Reserved.
|
||||
*/
|
||||
uint16_t fat32Flags;
|
||||
/**
|
||||
* FAT32 version. High byte is major revision number.
|
||||
* Low byte is minor revision number. Only 0.0 define.
|
||||
*/
|
||||
uint16_t fat32Version;
|
||||
/**
|
||||
* Cluster number of the first cluster of the root directory for FAT32.
|
||||
* This usually 2 but not required to be 2.
|
||||
*/
|
||||
uint32_t fat32RootCluster;
|
||||
/**
|
||||
* Sector number of FSINFO structure in the reserved area of the
|
||||
* FAT32 volume. Usually 1.
|
||||
*/
|
||||
uint16_t fat32FSInfo;
|
||||
/**
|
||||
* If non-zero, indicates the sector number in the reserved area
|
||||
* of the volume of a copy of the boot record. Usually 6.
|
||||
* No value other than 6 is recommended.
|
||||
*/
|
||||
uint16_t fat32BackBootBlock;
|
||||
/**
|
||||
* Reserved for future expansion. Code that formats FAT32 volumes
|
||||
* should always set all of the bytes of this field to 0.
|
||||
*/
|
||||
uint8_t fat32Reserved[12];
|
||||
};
|
||||
/** Type name for biosParmBlock */
|
||||
typedef struct biosParmBlock bpb_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct fat32BootSector
|
||||
*
|
||||
* \brief Boot sector for a FAT16 or FAT32 volume.
|
||||
*
|
||||
*/
|
||||
struct fat32BootSector {
|
||||
/** X86 jmp to boot program */
|
||||
uint8_t jmpToBootCode[3];
|
||||
/** informational only - don't depend on it */
|
||||
char oemName[8];
|
||||
/** BIOS Parameter Block */
|
||||
bpb_t bpb;
|
||||
/** for int0x13 use value 0X80 for hard drive */
|
||||
uint8_t driveNumber;
|
||||
/** used by Windows NT - should be zero for FAT */
|
||||
uint8_t reserved1;
|
||||
/** 0X29 if next three fields are valid */
|
||||
uint8_t bootSignature;
|
||||
/** usually generated by combining date and time */
|
||||
uint32_t volumeSerialNumber;
|
||||
/** should match volume label in root dir */
|
||||
char volumeLabel[11];
|
||||
/** informational only - don't depend on it */
|
||||
char fileSystemType[8];
|
||||
/** X86 boot code */
|
||||
uint8_t bootCode[420];
|
||||
/** must be 0X55 */
|
||||
uint8_t bootSectorSig0;
|
||||
/** must be 0XAA */
|
||||
uint8_t bootSectorSig1;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// End Of Chain values for FAT entries
|
||||
/** FAT16 end of chain value used by Microsoft. */
|
||||
uint16_t const FAT16EOC = 0XFFFF;
|
||||
/** Minimum value for FAT16 EOC. Use to test for EOC. */
|
||||
uint16_t const FAT16EOC_MIN = 0XFFF8;
|
||||
/** FAT32 end of chain value used by Microsoft. */
|
||||
uint32_t const FAT32EOC = 0X0FFFFFFF;
|
||||
/** Minimum value for FAT32 EOC. Use to test for EOC. */
|
||||
uint32_t const FAT32EOC_MIN = 0X0FFFFFF8;
|
||||
/** Mask a for FAT32 entry. Entries are 28 bits. */
|
||||
uint32_t const FAT32MASK = 0X0FFFFFFF;
|
||||
|
||||
/** Type name for fat32BootSector */
|
||||
typedef struct fat32BootSector fbs_t;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \struct directoryEntry
|
||||
* \brief FAT short directory entry
|
||||
*
|
||||
* Short means short 8.3 name, not the entry size.
|
||||
*
|
||||
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
|
||||
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
|
||||
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
|
||||
* 16-bit word):
|
||||
*
|
||||
* Bits 9-15: Count of years from 1980, valid value range 0-127
|
||||
* inclusive (1980-2107).
|
||||
*
|
||||
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
|
||||
*
|
||||
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
|
||||
*
|
||||
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
|
||||
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
|
||||
* 16-bit word, bit 15 is the MSB of the 16-bit word).
|
||||
*
|
||||
* Bits 11-15: Hours, valid value range 0-23 inclusive.
|
||||
*
|
||||
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
|
||||
*
|
||||
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
|
||||
*
|
||||
* The valid time range is from Midnight 00:00:00 to 23:59:58.
|
||||
*/
|
||||
struct directoryEntry {
|
||||
/**
|
||||
* Short 8.3 name.
|
||||
* The first eight bytes contain the file name with blank fill.
|
||||
* The last three bytes contain the file extension with blank fill.
|
||||
*/
|
||||
uint8_t name[11];
|
||||
/** Entry attributes.
|
||||
*
|
||||
* The upper two bits of the attribute byte are reserved and should
|
||||
* always be set to 0 when a file is created and never modified or
|
||||
* looked at after that. See defines that begin with DIR_ATT_.
|
||||
*/
|
||||
uint8_t attributes;
|
||||
/**
|
||||
* Reserved for use by Windows NT. Set value to 0 when a file is
|
||||
* created and never modify or look at it after that.
|
||||
*/
|
||||
uint8_t reservedNT;
|
||||
/**
|
||||
* The granularity of the seconds part of creationTime is 2 seconds
|
||||
* so this field is a count of tenths of a second and its valid
|
||||
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
|
||||
*/
|
||||
uint8_t creationTimeTenths;
|
||||
/** Time file was created. */
|
||||
uint16_t creationTime;
|
||||
/** Date file was created. */
|
||||
uint16_t creationDate;
|
||||
/**
|
||||
* Last access date. Note that there is no last access time, only
|
||||
* a date. This is the date of last read or write. In the case of
|
||||
* a write, this should be set to the same date as lastWriteDate.
|
||||
*/
|
||||
uint16_t lastAccessDate;
|
||||
/**
|
||||
* High word of this entry's first cluster number (always 0 for a
|
||||
* FAT12 or FAT16 volume).
|
||||
*/
|
||||
uint16_t firstClusterHigh;
|
||||
/** Time of last write. File creation is considered a write. */
|
||||
uint16_t lastWriteTime;
|
||||
/** Date of last write. File creation is considered a write. */
|
||||
uint16_t lastWriteDate;
|
||||
/** Low word of this entry's first cluster number. */
|
||||
uint16_t firstClusterLow;
|
||||
/** 32-bit unsigned holding this file's size in bytes. */
|
||||
uint32_t fileSize;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
// Definitions for directory entries
|
||||
//
|
||||
/** Type name for directoryEntry */
|
||||
typedef struct directoryEntry dir_t;
|
||||
/** escape for name[0] = 0XE5 */
|
||||
uint8_t const DIR_NAME_0XE5 = 0X05;
|
||||
/** name[0] value for entry that is free after being "deleted" */
|
||||
uint8_t const DIR_NAME_DELETED = 0XE5;
|
||||
/** name[0] value for entry that is free and no allocated entries follow */
|
||||
uint8_t const DIR_NAME_FREE = 0X00;
|
||||
/** file is read-only */
|
||||
uint8_t const DIR_ATT_READ_ONLY = 0X01;
|
||||
/** File should hidden in directory listings */
|
||||
uint8_t const DIR_ATT_HIDDEN = 0X02;
|
||||
/** Entry is for a system file */
|
||||
uint8_t const DIR_ATT_SYSTEM = 0X04;
|
||||
/** Directory entry contains the volume label */
|
||||
uint8_t const DIR_ATT_VOLUME_ID = 0X08;
|
||||
/** Entry is for a directory */
|
||||
uint8_t const DIR_ATT_DIRECTORY = 0X10;
|
||||
/** Old DOS archive bit for backup support */
|
||||
uint8_t const DIR_ATT_ARCHIVE = 0X20;
|
||||
/** Test value for long name entry. Test is
|
||||
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
|
||||
uint8_t const DIR_ATT_LONG_NAME = 0X0F;
|
||||
/** Test mask for long name entry */
|
||||
uint8_t const DIR_ATT_LONG_NAME_MASK = 0X3F;
|
||||
/** defined attribute bits */
|
||||
uint8_t const DIR_ATT_DEFINED_BITS = 0X3F;
|
||||
/** Directory entry is part of a long name */
|
||||
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME;
|
||||
}
|
||||
/** Mask for file/subdirectory tests */
|
||||
uint8_t const DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
|
||||
/** Directory entry is for a file */
|
||||
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
|
||||
}
|
||||
/** Directory entry is for a subdirectory */
|
||||
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
|
||||
}
|
||||
/** Directory entry is for a file or subdirectory */
|
||||
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
|
||||
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
|
||||
}
|
||||
#endif // FatStructs_h
|
644
arduino-0022-linux-x64/libraries/SD/utility/Sd2Card.cpp
Normal file
644
arduino-0022-linux-x64/libraries/SD/utility/Sd2Card.cpp
Normal file
|
@ -0,0 +1,644 @@
|
|||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <WProgram.h>
|
||||
#include "Sd2Card.h"
|
||||
//------------------------------------------------------------------------------
|
||||
#ifndef SOFTWARE_SPI
|
||||
// functions for hardware SPI
|
||||
/** Send a byte to the card */
|
||||
static void spiSend(uint8_t b) {
|
||||
SPDR = b;
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
}
|
||||
/** Receive a byte from the card */
|
||||
static uint8_t spiRec(void) {
|
||||
spiSend(0XFF);
|
||||
return SPDR;
|
||||
}
|
||||
#else // SOFTWARE_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
/** nop to tune soft SPI timing */
|
||||
#define nop asm volatile ("nop\n\t")
|
||||
//------------------------------------------------------------------------------
|
||||
/** Soft SPI receive */
|
||||
uint8_t spiRec(void) {
|
||||
uint8_t data = 0;
|
||||
// no interrupts during byte receive - about 8 us
|
||||
cli();
|
||||
// output pin high - like sending 0XFF
|
||||
fastDigitalWrite(SPI_MOSI_PIN, HIGH);
|
||||
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||
|
||||
// adjust so SCK is nice
|
||||
nop;
|
||||
nop;
|
||||
|
||||
data <<= 1;
|
||||
|
||||
if (fastDigitalRead(SPI_MISO_PIN)) data |= 1;
|
||||
|
||||
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||
}
|
||||
// enable interrupts
|
||||
sei();
|
||||
return data;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Soft SPI send */
|
||||
void spiSend(uint8_t data) {
|
||||
// no interrupts during byte send - about 8 us
|
||||
cli();
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||
|
||||
fastDigitalWrite(SPI_MOSI_PIN, data & 0X80);
|
||||
|
||||
data <<= 1;
|
||||
|
||||
fastDigitalWrite(SPI_SCK_PIN, HIGH);
|
||||
}
|
||||
// hold SCK high for a few ns
|
||||
nop;
|
||||
nop;
|
||||
nop;
|
||||
nop;
|
||||
|
||||
fastDigitalWrite(SPI_SCK_PIN, LOW);
|
||||
// enable interrupts
|
||||
sei();
|
||||
}
|
||||
#endif // SOFTWARE_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
// send command and return error code. Return zero for OK
|
||||
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
|
||||
// end read if in partialBlockRead mode
|
||||
readEnd();
|
||||
|
||||
// select card
|
||||
chipSelectLow();
|
||||
|
||||
// wait up to 300 ms if busy
|
||||
waitNotBusy(300);
|
||||
|
||||
// send command
|
||||
spiSend(cmd | 0x40);
|
||||
|
||||
// send argument
|
||||
for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
|
||||
|
||||
// send CRC
|
||||
uint8_t crc = 0XFF;
|
||||
if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
|
||||
if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
|
||||
spiSend(crc);
|
||||
|
||||
// wait for response
|
||||
for (uint8_t i = 0; ((status_ = spiRec()) & 0X80) && i != 0XFF; i++);
|
||||
return status_;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Determine the size of an SD flash memory card.
|
||||
*
|
||||
* \return The number of 512 byte data blocks in the card
|
||||
* or zero if an error occurs.
|
||||
*/
|
||||
uint32_t Sd2Card::cardSize(void) {
|
||||
csd_t csd;
|
||||
if (!readCSD(&csd)) return 0;
|
||||
if (csd.v1.csd_ver == 0) {
|
||||
uint8_t read_bl_len = csd.v1.read_bl_len;
|
||||
uint16_t c_size = (csd.v1.c_size_high << 10)
|
||||
| (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
|
||||
uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
|
||||
| csd.v1.c_size_mult_low;
|
||||
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
|
||||
} else if (csd.v2.csd_ver == 1) {
|
||||
uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
|
||||
| (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
|
||||
return (c_size + 1) << 10;
|
||||
} else {
|
||||
error(SD_CARD_ERROR_BAD_CSD);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void Sd2Card::chipSelectHigh(void) {
|
||||
digitalWrite(chipSelectPin_, HIGH);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void Sd2Card::chipSelectLow(void) {
|
||||
digitalWrite(chipSelectPin_, LOW);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Erase a range of blocks.
|
||||
*
|
||||
* \param[in] firstBlock The address of the first block in the range.
|
||||
* \param[in] lastBlock The address of the last block in the range.
|
||||
*
|
||||
* \note This function requests the SD card to do a flash erase for a
|
||||
* range of blocks. The data on the card after an erase operation is
|
||||
* either 0 or 1, depends on the card vendor. The card must support
|
||||
* single block erase.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
|
||||
if (!eraseSingleBlockEnable()) {
|
||||
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
|
||||
goto fail;
|
||||
}
|
||||
if (type_ != SD_CARD_TYPE_SDHC) {
|
||||
firstBlock <<= 9;
|
||||
lastBlock <<= 9;
|
||||
}
|
||||
if (cardCommand(CMD32, firstBlock)
|
||||
|| cardCommand(CMD33, lastBlock)
|
||||
|| cardCommand(CMD38, 0)) {
|
||||
error(SD_CARD_ERROR_ERASE);
|
||||
goto fail;
|
||||
}
|
||||
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
|
||||
error(SD_CARD_ERROR_ERASE_TIMEOUT);
|
||||
goto fail;
|
||||
}
|
||||
chipSelectHigh();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Determine if card supports single block erase.
|
||||
*
|
||||
* \return The value one, true, is returned if single block erase is supported.
|
||||
* The value zero, false, is returned if single block erase is not supported.
|
||||
*/
|
||||
uint8_t Sd2Card::eraseSingleBlockEnable(void) {
|
||||
csd_t csd;
|
||||
return readCSD(&csd) ? csd.v1.erase_blk_en : 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Initialize an SD flash memory card.
|
||||
*
|
||||
* \param[in] sckRateID SPI clock rate selector. See setSckRate().
|
||||
* \param[in] chipSelectPin SD chip select pin number.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. The reason for failure
|
||||
* can be determined by calling errorCode() and errorData().
|
||||
*/
|
||||
uint8_t Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
|
||||
errorCode_ = inBlock_ = partialBlockRead_ = type_ = 0;
|
||||
chipSelectPin_ = chipSelectPin;
|
||||
// 16-bit init start time allows over a minute
|
||||
uint16_t t0 = (uint16_t)millis();
|
||||
uint32_t arg;
|
||||
|
||||
// set pin modes
|
||||
pinMode(chipSelectPin_, OUTPUT);
|
||||
chipSelectHigh();
|
||||
pinMode(SPI_MISO_PIN, INPUT);
|
||||
pinMode(SPI_MOSI_PIN, OUTPUT);
|
||||
pinMode(SPI_SCK_PIN, OUTPUT);
|
||||
|
||||
#ifndef SOFTWARE_SPI
|
||||
// SS must be in output mode even it is not chip select
|
||||
pinMode(SS_PIN, OUTPUT);
|
||||
digitalWrite(SS_PIN, HIGH); // disable any SPI device using hardware SS pin
|
||||
// Enable SPI, Master, clock rate f_osc/128
|
||||
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
|
||||
// clear double speed
|
||||
SPSR &= ~(1 << SPI2X);
|
||||
#endif // SOFTWARE_SPI
|
||||
|
||||
// must supply min of 74 clock cycles with CS high.
|
||||
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
|
||||
|
||||
chipSelectLow();
|
||||
|
||||
// command to go idle in SPI mode
|
||||
while ((status_ = cardCommand(CMD0, 0)) != R1_IDLE_STATE) {
|
||||
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||
error(SD_CARD_ERROR_CMD0);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
// check SD version
|
||||
if ((cardCommand(CMD8, 0x1AA) & R1_ILLEGAL_COMMAND)) {
|
||||
type(SD_CARD_TYPE_SD1);
|
||||
} else {
|
||||
// only need last byte of r7 response
|
||||
for (uint8_t i = 0; i < 4; i++) status_ = spiRec();
|
||||
if (status_ != 0XAA) {
|
||||
error(SD_CARD_ERROR_CMD8);
|
||||
goto fail;
|
||||
}
|
||||
type(SD_CARD_TYPE_SD2);
|
||||
}
|
||||
// initialize card and send host supports SDHC if SD2
|
||||
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
|
||||
|
||||
while ((status_ = cardAcmd(ACMD41, arg)) != R1_READY_STATE) {
|
||||
// check for timeout
|
||||
if (((uint16_t)millis() - t0) > SD_INIT_TIMEOUT) {
|
||||
error(SD_CARD_ERROR_ACMD41);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
// if SD2 read OCR register to check for SDHC card
|
||||
if (type() == SD_CARD_TYPE_SD2) {
|
||||
if (cardCommand(CMD58, 0)) {
|
||||
error(SD_CARD_ERROR_CMD58);
|
||||
goto fail;
|
||||
}
|
||||
if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
|
||||
// discard rest of ocr - contains allowed voltage range
|
||||
for (uint8_t i = 0; i < 3; i++) spiRec();
|
||||
}
|
||||
chipSelectHigh();
|
||||
|
||||
#ifndef SOFTWARE_SPI
|
||||
return setSckRate(sckRateID);
|
||||
#else // SOFTWARE_SPI
|
||||
return true;
|
||||
#endif // SOFTWARE_SPI
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Enable or disable partial block reads.
|
||||
*
|
||||
* Enabling partial block reads improves performance by allowing a block
|
||||
* to be read over the SPI bus as several sub-blocks. Errors may occur
|
||||
* if the time between reads is too long since the SD card may timeout.
|
||||
* The SPI SS line will be held low until the entire block is read or
|
||||
* readEnd() is called.
|
||||
*
|
||||
* Use this for applications like the Adafruit Wave Shield.
|
||||
*
|
||||
* \param[in] value The value TRUE (non-zero) or FALSE (zero).)
|
||||
*/
|
||||
void Sd2Card::partialBlockRead(uint8_t value) {
|
||||
readEnd();
|
||||
partialBlockRead_ = value;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Read a 512 byte block from an SD card device.
|
||||
*
|
||||
* \param[in] block Logical block to be read.
|
||||
* \param[out] dst Pointer to the location that will receive the data.
|
||||
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::readBlock(uint32_t block, uint8_t* dst) {
|
||||
return readData(block, 0, 512, dst);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Read part of a 512 byte block from an SD card.
|
||||
*
|
||||
* \param[in] block Logical block to be read.
|
||||
* \param[in] offset Number of bytes to skip at start of block
|
||||
* \param[out] dst Pointer to the location that will receive the data.
|
||||
* \param[in] count Number of bytes to read
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::readData(uint32_t block,
|
||||
uint16_t offset, uint16_t count, uint8_t* dst) {
|
||||
uint16_t n;
|
||||
if (count == 0) return true;
|
||||
if ((count + offset) > 512) {
|
||||
goto fail;
|
||||
}
|
||||
if (!inBlock_ || block != block_ || offset < offset_) {
|
||||
block_ = block;
|
||||
// use address if not SDHC card
|
||||
if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
|
||||
if (cardCommand(CMD17, block)) {
|
||||
error(SD_CARD_ERROR_CMD17);
|
||||
goto fail;
|
||||
}
|
||||
if (!waitStartBlock()) {
|
||||
goto fail;
|
||||
}
|
||||
offset_ = 0;
|
||||
inBlock_ = 1;
|
||||
}
|
||||
|
||||
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||
// start first spi transfer
|
||||
SPDR = 0XFF;
|
||||
|
||||
// skip data before offset
|
||||
for (;offset_ < offset; offset_++) {
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
SPDR = 0XFF;
|
||||
}
|
||||
// transfer data
|
||||
n = count - 1;
|
||||
for (uint16_t i = 0; i < n; i++) {
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
dst[i] = SPDR;
|
||||
SPDR = 0XFF;
|
||||
}
|
||||
// wait for last byte
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
dst[n] = SPDR;
|
||||
|
||||
#else // OPTIMIZE_HARDWARE_SPI
|
||||
|
||||
// skip data before offset
|
||||
for (;offset_ < offset; offset_++) {
|
||||
spiRec();
|
||||
}
|
||||
// transfer data
|
||||
for (uint16_t i = 0; i < count; i++) {
|
||||
dst[i] = spiRec();
|
||||
}
|
||||
#endif // OPTIMIZE_HARDWARE_SPI
|
||||
|
||||
offset_ += count;
|
||||
if (!partialBlockRead_ || offset_ >= 512) {
|
||||
// read rest of data, checksum and set chip select high
|
||||
readEnd();
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Skip remaining data in a block when in partial block read mode. */
|
||||
void Sd2Card::readEnd(void) {
|
||||
if (inBlock_) {
|
||||
// skip data and crc
|
||||
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||
// optimize skip for hardware
|
||||
SPDR = 0XFF;
|
||||
while (offset_++ < 513) {
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
SPDR = 0XFF;
|
||||
}
|
||||
// wait for last crc byte
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
#else // OPTIMIZE_HARDWARE_SPI
|
||||
while (offset_++ < 514) spiRec();
|
||||
#endif // OPTIMIZE_HARDWARE_SPI
|
||||
chipSelectHigh();
|
||||
inBlock_ = 0;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** read CID or CSR register */
|
||||
uint8_t Sd2Card::readRegister(uint8_t cmd, void* buf) {
|
||||
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
|
||||
if (cardCommand(cmd, 0)) {
|
||||
error(SD_CARD_ERROR_READ_REG);
|
||||
goto fail;
|
||||
}
|
||||
if (!waitStartBlock()) goto fail;
|
||||
// transfer data
|
||||
for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
|
||||
spiRec(); // get first crc byte
|
||||
spiRec(); // get second crc byte
|
||||
chipSelectHigh();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Set the SPI clock rate.
|
||||
*
|
||||
* \param[in] sckRateID A value in the range [0, 6].
|
||||
*
|
||||
* The SPI clock will be set to F_CPU/pow(2, 1 + sckRateID). The maximum
|
||||
* SPI rate is F_CPU/2 for \a sckRateID = 0 and the minimum rate is F_CPU/128
|
||||
* for \a scsRateID = 6.
|
||||
*
|
||||
* \return The value one, true, is returned for success and the value zero,
|
||||
* false, is returned for an invalid value of \a sckRateID.
|
||||
*/
|
||||
uint8_t Sd2Card::setSckRate(uint8_t sckRateID) {
|
||||
if (sckRateID > 6) {
|
||||
error(SD_CARD_ERROR_SCK_RATE);
|
||||
return false;
|
||||
}
|
||||
// see avr processor datasheet for SPI register bit definitions
|
||||
if ((sckRateID & 1) || sckRateID == 6) {
|
||||
SPSR &= ~(1 << SPI2X);
|
||||
} else {
|
||||
SPSR |= (1 << SPI2X);
|
||||
}
|
||||
SPCR &= ~((1 <<SPR1) | (1 << SPR0));
|
||||
SPCR |= (sckRateID & 4 ? (1 << SPR1) : 0)
|
||||
| (sckRateID & 2 ? (1 << SPR0) : 0);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// wait for card to go not busy
|
||||
uint8_t Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
|
||||
uint16_t t0 = millis();
|
||||
do {
|
||||
if (spiRec() == 0XFF) return true;
|
||||
}
|
||||
while (((uint16_t)millis() - t0) < timeoutMillis);
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Wait for start block token */
|
||||
uint8_t Sd2Card::waitStartBlock(void) {
|
||||
uint16_t t0 = millis();
|
||||
while ((status_ = spiRec()) == 0XFF) {
|
||||
if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
|
||||
error(SD_CARD_ERROR_READ_TIMEOUT);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (status_ != DATA_START_BLOCK) {
|
||||
error(SD_CARD_ERROR_READ);
|
||||
goto fail;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Writes a 512 byte block to an SD card.
|
||||
*
|
||||
* \param[in] blockNumber Logical block to be written.
|
||||
* \param[in] src Pointer to the location of the data to be written.
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
|
||||
#if SD_PROTECT_BLOCK_ZERO
|
||||
// don't allow write to first block
|
||||
if (blockNumber == 0) {
|
||||
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
||||
goto fail;
|
||||
}
|
||||
#endif // SD_PROTECT_BLOCK_ZERO
|
||||
|
||||
// use address if not SDHC card
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||
if (cardCommand(CMD24, blockNumber)) {
|
||||
error(SD_CARD_ERROR_CMD24);
|
||||
goto fail;
|
||||
}
|
||||
if (!writeData(DATA_START_BLOCK, src)) goto fail;
|
||||
|
||||
// wait for flash programming to complete
|
||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||
error(SD_CARD_ERROR_WRITE_TIMEOUT);
|
||||
goto fail;
|
||||
}
|
||||
// response is r2 so get and check two bytes for nonzero
|
||||
if (cardCommand(CMD13, 0) || spiRec()) {
|
||||
error(SD_CARD_ERROR_WRITE_PROGRAMMING);
|
||||
goto fail;
|
||||
}
|
||||
chipSelectHigh();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Write one data block in a multiple block write sequence */
|
||||
uint8_t Sd2Card::writeData(const uint8_t* src) {
|
||||
// wait for previous write to finish
|
||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
|
||||
error(SD_CARD_ERROR_WRITE_MULTIPLE);
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
return writeData(WRITE_MULTIPLE_TOKEN, src);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// send one block of data for write block or write multiple blocks
|
||||
uint8_t Sd2Card::writeData(uint8_t token, const uint8_t* src) {
|
||||
#ifdef OPTIMIZE_HARDWARE_SPI
|
||||
|
||||
// send data - optimized loop
|
||||
SPDR = token;
|
||||
|
||||
// send two byte per iteration
|
||||
for (uint16_t i = 0; i < 512; i += 2) {
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
SPDR = src[i];
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
SPDR = src[i+1];
|
||||
}
|
||||
|
||||
// wait for last data byte
|
||||
while (!(SPSR & (1 << SPIF)));
|
||||
|
||||
#else // OPTIMIZE_HARDWARE_SPI
|
||||
spiSend(token);
|
||||
for (uint16_t i = 0; i < 512; i++) {
|
||||
spiSend(src[i]);
|
||||
}
|
||||
#endif // OPTIMIZE_HARDWARE_SPI
|
||||
spiSend(0xff); // dummy crc
|
||||
spiSend(0xff); // dummy crc
|
||||
|
||||
status_ = spiRec();
|
||||
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
|
||||
error(SD_CARD_ERROR_WRITE);
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Start a write multiple blocks sequence.
|
||||
*
|
||||
* \param[in] blockNumber Address of first block in sequence.
|
||||
* \param[in] eraseCount The number of blocks to be pre-erased.
|
||||
*
|
||||
* \note This function is used with writeData() and writeStop()
|
||||
* for optimized multiple block writes.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
|
||||
#if SD_PROTECT_BLOCK_ZERO
|
||||
// don't allow write to first block
|
||||
if (blockNumber == 0) {
|
||||
error(SD_CARD_ERROR_WRITE_BLOCK_ZERO);
|
||||
goto fail;
|
||||
}
|
||||
#endif // SD_PROTECT_BLOCK_ZERO
|
||||
// send pre-erase count
|
||||
if (cardAcmd(ACMD23, eraseCount)) {
|
||||
error(SD_CARD_ERROR_ACMD23);
|
||||
goto fail;
|
||||
}
|
||||
// use address if not SDHC card
|
||||
if (type() != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
|
||||
if (cardCommand(CMD25, blockNumber)) {
|
||||
error(SD_CARD_ERROR_CMD25);
|
||||
goto fail;
|
||||
}
|
||||
return true;
|
||||
|
||||
fail:
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** End a write multiple blocks sequence.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure.
|
||||
*/
|
||||
uint8_t Sd2Card::writeStop(void) {
|
||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
||||
spiSend(STOP_TRAN_TOKEN);
|
||||
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
|
||||
chipSelectHigh();
|
||||
return true;
|
||||
|
||||
fail:
|
||||
error(SD_CARD_ERROR_STOP_TRAN);
|
||||
chipSelectHigh();
|
||||
return false;
|
||||
}
|
233
arduino-0022-linux-x64/libraries/SD/utility/Sd2Card.h
Normal file
233
arduino-0022-linux-x64/libraries/SD/utility/Sd2Card.h
Normal file
|
@ -0,0 +1,233 @@
|
|||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef Sd2Card_h
|
||||
#define Sd2Card_h
|
||||
/**
|
||||
* \file
|
||||
* Sd2Card class
|
||||
*/
|
||||
#include "Sd2PinMap.h"
|
||||
#include "SdInfo.h"
|
||||
/** Set SCK to max rate of F_CPU/2. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_FULL_SPEED = 0;
|
||||
/** Set SCK rate to F_CPU/4. See Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_HALF_SPEED = 1;
|
||||
/** Set SCK rate to F_CPU/8. Sd2Card::setSckRate(). */
|
||||
uint8_t const SPI_QUARTER_SPEED = 2;
|
||||
/**
|
||||
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
|
||||
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
|
||||
*
|
||||
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
|
||||
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
|
||||
* but many SD cards will fail with GPS Shield V1.0.
|
||||
*/
|
||||
#define MEGA_SOFT_SPI 0
|
||||
//------------------------------------------------------------------------------
|
||||
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
|
||||
#define SOFTWARE_SPI
|
||||
#endif // MEGA_SOFT_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
// SPI pin definitions
|
||||
//
|
||||
#ifndef SOFTWARE_SPI
|
||||
// hardware pin defs
|
||||
/**
|
||||
* SD Chip Select pin
|
||||
*
|
||||
* Warning if this pin is redefined the hardware SS will pin will be enabled
|
||||
* as an output by init(). An avr processor will not function as an SPI
|
||||
* master unless SS is set to output mode.
|
||||
*/
|
||||
/** The default chip select pin for the SD card is SS. */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = SS_PIN;
|
||||
// The following three pins must not be redefined for hardware SPI.
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = MOSI_PIN;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = MISO_PIN;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = SCK_PIN;
|
||||
/** optimize loops for hardware SPI */
|
||||
#define OPTIMIZE_HARDWARE_SPI
|
||||
|
||||
#else // SOFTWARE_SPI
|
||||
// define software SPI pins so Mega can use unmodified GPS Shield
|
||||
/** SPI chip select pin */
|
||||
uint8_t const SD_CHIP_SELECT_PIN = 10;
|
||||
/** SPI Master Out Slave In pin */
|
||||
uint8_t const SPI_MOSI_PIN = 11;
|
||||
/** SPI Master In Slave Out pin */
|
||||
uint8_t const SPI_MISO_PIN = 12;
|
||||
/** SPI Clock pin */
|
||||
uint8_t const SPI_SCK_PIN = 13;
|
||||
#endif // SOFTWARE_SPI
|
||||
//------------------------------------------------------------------------------
|
||||
/** Protect block zero from write if nonzero */
|
||||
#define SD_PROTECT_BLOCK_ZERO 1
|
||||
/** init timeout ms */
|
||||
uint16_t const SD_INIT_TIMEOUT = 2000;
|
||||
/** erase timeout ms */
|
||||
uint16_t const SD_ERASE_TIMEOUT = 10000;
|
||||
/** read timeout ms */
|
||||
uint16_t const SD_READ_TIMEOUT = 300;
|
||||
/** write time out ms */
|
||||
uint16_t const SD_WRITE_TIMEOUT = 600;
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card errors
|
||||
/** timeout error for command CMD0 */
|
||||
uint8_t const SD_CARD_ERROR_CMD0 = 0X1;
|
||||
/** CMD8 was not accepted - not a valid SD card*/
|
||||
uint8_t const SD_CARD_ERROR_CMD8 = 0X2;
|
||||
/** card returned an error response for CMD17 (read block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD17 = 0X3;
|
||||
/** card returned an error response for CMD24 (write block) */
|
||||
uint8_t const SD_CARD_ERROR_CMD24 = 0X4;
|
||||
/** WRITE_MULTIPLE_BLOCKS command failed */
|
||||
uint8_t const SD_CARD_ERROR_CMD25 = 0X05;
|
||||
/** card returned an error response for CMD58 (read OCR) */
|
||||
uint8_t const SD_CARD_ERROR_CMD58 = 0X06;
|
||||
/** SET_WR_BLK_ERASE_COUNT failed */
|
||||
uint8_t const SD_CARD_ERROR_ACMD23 = 0X07;
|
||||
/** card's ACMD41 initialization process timeout */
|
||||
uint8_t const SD_CARD_ERROR_ACMD41 = 0X08;
|
||||
/** card returned a bad CSR version field */
|
||||
uint8_t const SD_CARD_ERROR_BAD_CSD = 0X09;
|
||||
/** erase block group command failed */
|
||||
uint8_t const SD_CARD_ERROR_ERASE = 0X0A;
|
||||
/** card not capable of single block erase */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0X0B;
|
||||
/** Erase sequence timed out */
|
||||
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0X0C;
|
||||
/** card returned an error token instead of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ = 0X0D;
|
||||
/** read CID or CSD failed */
|
||||
uint8_t const SD_CARD_ERROR_READ_REG = 0X0E;
|
||||
/** timeout while waiting for start of read data */
|
||||
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X0F;
|
||||
/** card did not accept STOP_TRAN_TOKEN */
|
||||
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X10;
|
||||
/** card returned an error token as a response to a write operation */
|
||||
uint8_t const SD_CARD_ERROR_WRITE = 0X11;
|
||||
/** attempt to write protected block zero */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X12;
|
||||
/** card did not go ready for a multiple block write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X13;
|
||||
/** card returned an error to a CMD13 status check after a write */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X14;
|
||||
/** timeout occurred during write programming */
|
||||
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X15;
|
||||
/** incorrect rate selected */
|
||||
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X16;
|
||||
//------------------------------------------------------------------------------
|
||||
// card types
|
||||
/** Standard capacity V1 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD1 = 1;
|
||||
/** Standard capacity V2 SD card */
|
||||
uint8_t const SD_CARD_TYPE_SD2 = 2;
|
||||
/** High Capacity SD card */
|
||||
uint8_t const SD_CARD_TYPE_SDHC = 3;
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class Sd2Card
|
||||
* \brief Raw access to SD and SDHC flash memory cards.
|
||||
*/
|
||||
class Sd2Card {
|
||||
public:
|
||||
/** Construct an instance of Sd2Card. */
|
||||
Sd2Card(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {}
|
||||
uint32_t cardSize(void);
|
||||
uint8_t erase(uint32_t firstBlock, uint32_t lastBlock);
|
||||
uint8_t eraseSingleBlockEnable(void);
|
||||
/**
|
||||
* \return error code for last error. See Sd2Card.h for a list of error codes.
|
||||
*/
|
||||
uint8_t errorCode(void) const {return errorCode_;}
|
||||
/** \return error data for last error. */
|
||||
uint8_t errorData(void) const {return status_;}
|
||||
/**
|
||||
* Initialize an SD flash memory card with default clock rate and chip
|
||||
* select pin. See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*/
|
||||
uint8_t init(void) {
|
||||
return init(SPI_FULL_SPEED, SD_CHIP_SELECT_PIN);
|
||||
}
|
||||
/**
|
||||
* Initialize an SD flash memory card with the selected SPI clock rate
|
||||
* and the default SD chip select pin.
|
||||
* See sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin).
|
||||
*/
|
||||
uint8_t init(uint8_t sckRateID) {
|
||||
return init(sckRateID, SD_CHIP_SELECT_PIN);
|
||||
}
|
||||
uint8_t init(uint8_t sckRateID, uint8_t chipSelectPin);
|
||||
void partialBlockRead(uint8_t value);
|
||||
/** Returns the current value, true or false, for partial block read. */
|
||||
uint8_t partialBlockRead(void) const {return partialBlockRead_;}
|
||||
uint8_t readBlock(uint32_t block, uint8_t* dst);
|
||||
uint8_t readData(uint32_t block,
|
||||
uint16_t offset, uint16_t count, uint8_t* dst);
|
||||
/**
|
||||
* Read a cards CID register. The CID contains card identification
|
||||
* information such as Manufacturer ID, Product name, Product serial
|
||||
* number and Manufacturing date. */
|
||||
uint8_t readCID(cid_t* cid) {
|
||||
return readRegister(CMD10, cid);
|
||||
}
|
||||
/**
|
||||
* Read a cards CSD register. The CSD contains Card-Specific Data that
|
||||
* provides information regarding access to the card's contents. */
|
||||
uint8_t readCSD(csd_t* csd) {
|
||||
return readRegister(CMD9, csd);
|
||||
}
|
||||
void readEnd(void);
|
||||
uint8_t setSckRate(uint8_t sckRateID);
|
||||
/** Return the card type: SD V1, SD V2 or SDHC */
|
||||
uint8_t type(void) const {return type_;}
|
||||
uint8_t writeBlock(uint32_t blockNumber, const uint8_t* src);
|
||||
uint8_t writeData(const uint8_t* src);
|
||||
uint8_t writeStart(uint32_t blockNumber, uint32_t eraseCount);
|
||||
uint8_t writeStop(void);
|
||||
private:
|
||||
uint32_t block_;
|
||||
uint8_t chipSelectPin_;
|
||||
uint8_t errorCode_;
|
||||
uint8_t inBlock_;
|
||||
uint16_t offset_;
|
||||
uint8_t partialBlockRead_;
|
||||
uint8_t status_;
|
||||
uint8_t type_;
|
||||
// private functions
|
||||
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
|
||||
cardCommand(CMD55, 0);
|
||||
return cardCommand(cmd, arg);
|
||||
}
|
||||
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
|
||||
void error(uint8_t code) {errorCode_ = code;}
|
||||
uint8_t readRegister(uint8_t cmd, void* buf);
|
||||
uint8_t sendWriteCommand(uint32_t blockNumber, uint32_t eraseCount);
|
||||
void chipSelectHigh(void);
|
||||
void chipSelectLow(void);
|
||||
void type(uint8_t value) {type_ = value;}
|
||||
uint8_t waitNotBusy(uint16_t timeoutMillis);
|
||||
uint8_t writeData(uint8_t token, const uint8_t* src);
|
||||
uint8_t waitStartBlock(void);
|
||||
};
|
||||
#endif // Sd2Card_h
|
353
arduino-0022-linux-x64/libraries/SD/utility/Sd2PinMap.h
Normal file
353
arduino-0022-linux-x64/libraries/SD/utility/Sd2PinMap.h
Normal file
|
@ -0,0 +1,353 @@
|
|||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2010 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Warning this file was generated by a program.
|
||||
#ifndef Sd2PinMap_h
|
||||
#define Sd2PinMap_h
|
||||
#include <avr/io.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/** struct for mapping digital pins */
|
||||
struct pin_map_t {
|
||||
volatile uint8_t* ddr;
|
||||
volatile uint8_t* pin;
|
||||
volatile uint8_t* port;
|
||||
uint8_t bit;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Mega
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 20;
|
||||
uint8_t const SCL_PIN = 21;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 53;
|
||||
uint8_t const MOSI_PIN = 51;
|
||||
uint8_t const MISO_PIN = 50;
|
||||
uint8_t const SCK_PIN = 52;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 0
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 1
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 2
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 3
|
||||
{&DDRG, &PING, &PORTG, 5}, // G5 4
|
||||
{&DDRE, &PINE, &PORTE, 3}, // E3 5
|
||||
{&DDRH, &PINH, &PORTH, 3}, // H3 6
|
||||
{&DDRH, &PINH, &PORTH, 4}, // H4 7
|
||||
{&DDRH, &PINH, &PORTH, 5}, // H5 8
|
||||
{&DDRH, &PINH, &PORTH, 6}, // H6 9
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 10
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 11
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 12
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 13
|
||||
{&DDRJ, &PINJ, &PORTJ, 1}, // J1 14
|
||||
{&DDRJ, &PINJ, &PORTJ, 0}, // J0 15
|
||||
{&DDRH, &PINH, &PORTH, 1}, // H1 16
|
||||
{&DDRH, &PINH, &PORTH, 0}, // H0 17
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 18
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 19
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 20
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 21
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 22
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 23
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 24
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 25
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 26
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 27
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 28
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 29
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 30
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 31
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 32
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 33
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 34
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 35
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 36
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 37
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 38
|
||||
{&DDRG, &PING, &PORTG, 2}, // G2 39
|
||||
{&DDRG, &PING, &PORTG, 1}, // G1 40
|
||||
{&DDRG, &PING, &PORTG, 0}, // G0 41
|
||||
{&DDRL, &PINL, &PORTL, 7}, // L7 42
|
||||
{&DDRL, &PINL, &PORTL, 6}, // L6 43
|
||||
{&DDRL, &PINL, &PORTL, 5}, // L5 44
|
||||
{&DDRL, &PINL, &PORTL, 4}, // L4 45
|
||||
{&DDRL, &PINL, &PORTL, 3}, // L3 46
|
||||
{&DDRL, &PINL, &PORTL, 2}, // L2 47
|
||||
{&DDRL, &PINL, &PORTL, 1}, // L1 48
|
||||
{&DDRL, &PINL, &PORTL, 0}, // L0 49
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 50
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 51
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 52
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 53
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 54
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 55
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 56
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 57
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 58
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 59
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 60
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 61
|
||||
{&DDRK, &PINK, &PORTK, 0}, // K0 62
|
||||
{&DDRK, &PINK, &PORTK, 1}, // K1 63
|
||||
{&DDRK, &PINK, &PORTK, 2}, // K2 64
|
||||
{&DDRK, &PINK, &PORTK, 3}, // K3 65
|
||||
{&DDRK, &PINK, &PORTK, 4}, // K4 66
|
||||
{&DDRK, &PINK, &PORTK, 5}, // K5 67
|
||||
{&DDRK, &PINK, &PORTK, 6}, // K6 68
|
||||
{&DDRK, &PINK, &PORTK, 7} // K7 69
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
|
||||
// Sanguino
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 17;
|
||||
uint8_t const SCL_PIN = 18;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 4;
|
||||
uint8_t const MOSI_PIN = 5;
|
||||
uint8_t const MISO_PIN = 6;
|
||||
uint8_t const SCK_PIN = 7;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 4
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 5
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 6
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 7
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 8
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 9
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 10
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 11
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 12
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 13
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 14
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 15
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 16
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 17
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 18
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 19
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 20
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 21
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 22
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 23
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 24
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 25
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 26
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 27
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 28
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 29
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 30
|
||||
{&DDRA, &PINA, &PORTA, 0} // A0 31
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
// Teensy 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 6;
|
||||
uint8_t const SCL_PIN = 5;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 0;
|
||||
uint8_t const MOSI_PIN = 2;
|
||||
uint8_t const MISO_PIN = 3;
|
||||
uint8_t const SCK_PIN = 1;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 0
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 1
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 2
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 3
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 4
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 5
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 6
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 7
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 8
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 9
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 10
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 11
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 12
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 13
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 14
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 15
|
||||
{&DDRF, &PINF, &PORTF, 7}, // F7 16
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 17
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 18
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 19
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 20
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 21
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 22
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 23
|
||||
{&DDRE, &PINE, &PORTE, 6} // E6 24
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
// Teensy++ 1.0 & 2.0
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 1;
|
||||
uint8_t const SCL_PIN = 0;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 20;
|
||||
uint8_t const MOSI_PIN = 22;
|
||||
uint8_t const MISO_PIN = 23;
|
||||
uint8_t const SCK_PIN = 21;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRE, &PINE, &PORTE, 0}, // E0 8
|
||||
{&DDRE, &PINE, &PORTE, 1}, // E1 9
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 10
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 11
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 12
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 13
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 14
|
||||
{&DDRC, &PINC, &PORTC, 5}, // C5 15
|
||||
{&DDRC, &PINC, &PORTC, 6}, // C6 16
|
||||
{&DDRC, &PINC, &PORTC, 7}, // C7 17
|
||||
{&DDRE, &PINE, &PORTE, 6}, // E6 18
|
||||
{&DDRE, &PINE, &PORTE, 7}, // E7 19
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 20
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 21
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 22
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 23
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 24
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 25
|
||||
{&DDRB, &PINB, &PORTB, 6}, // B6 26
|
||||
{&DDRB, &PINB, &PORTB, 7}, // B7 27
|
||||
{&DDRA, &PINA, &PORTA, 0}, // A0 28
|
||||
{&DDRA, &PINA, &PORTA, 1}, // A1 29
|
||||
{&DDRA, &PINA, &PORTA, 2}, // A2 30
|
||||
{&DDRA, &PINA, &PORTA, 3}, // A3 31
|
||||
{&DDRA, &PINA, &PORTA, 4}, // A4 32
|
||||
{&DDRA, &PINA, &PORTA, 5}, // A5 33
|
||||
{&DDRA, &PINA, &PORTA, 6}, // A6 34
|
||||
{&DDRA, &PINA, &PORTA, 7}, // A7 35
|
||||
{&DDRE, &PINE, &PORTE, 4}, // E4 36
|
||||
{&DDRE, &PINE, &PORTE, 5}, // E5 37
|
||||
{&DDRF, &PINF, &PORTF, 0}, // F0 38
|
||||
{&DDRF, &PINF, &PORTF, 1}, // F1 39
|
||||
{&DDRF, &PINF, &PORTF, 2}, // F2 40
|
||||
{&DDRF, &PINF, &PORTF, 3}, // F3 41
|
||||
{&DDRF, &PINF, &PORTF, 4}, // F4 42
|
||||
{&DDRF, &PINF, &PORTF, 5}, // F5 43
|
||||
{&DDRF, &PINF, &PORTF, 6}, // F6 44
|
||||
{&DDRF, &PINF, &PORTF, 7} // F7 45
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// 168 and 328 Arduinos
|
||||
|
||||
// Two Wire (aka I2C) ports
|
||||
uint8_t const SDA_PIN = 18;
|
||||
uint8_t const SCL_PIN = 19;
|
||||
|
||||
// SPI port
|
||||
uint8_t const SS_PIN = 10;
|
||||
uint8_t const MOSI_PIN = 11;
|
||||
uint8_t const MISO_PIN = 12;
|
||||
uint8_t const SCK_PIN = 13;
|
||||
|
||||
static const pin_map_t digitalPinMap[] = {
|
||||
{&DDRD, &PIND, &PORTD, 0}, // D0 0
|
||||
{&DDRD, &PIND, &PORTD, 1}, // D1 1
|
||||
{&DDRD, &PIND, &PORTD, 2}, // D2 2
|
||||
{&DDRD, &PIND, &PORTD, 3}, // D3 3
|
||||
{&DDRD, &PIND, &PORTD, 4}, // D4 4
|
||||
{&DDRD, &PIND, &PORTD, 5}, // D5 5
|
||||
{&DDRD, &PIND, &PORTD, 6}, // D6 6
|
||||
{&DDRD, &PIND, &PORTD, 7}, // D7 7
|
||||
{&DDRB, &PINB, &PORTB, 0}, // B0 8
|
||||
{&DDRB, &PINB, &PORTB, 1}, // B1 9
|
||||
{&DDRB, &PINB, &PORTB, 2}, // B2 10
|
||||
{&DDRB, &PINB, &PORTB, 3}, // B3 11
|
||||
{&DDRB, &PINB, &PORTB, 4}, // B4 12
|
||||
{&DDRB, &PINB, &PORTB, 5}, // B5 13
|
||||
{&DDRC, &PINC, &PORTC, 0}, // C0 14
|
||||
{&DDRC, &PINC, &PORTC, 1}, // C1 15
|
||||
{&DDRC, &PINC, &PORTC, 2}, // C2 16
|
||||
{&DDRC, &PINC, &PORTC, 3}, // C3 17
|
||||
{&DDRC, &PINC, &PORTC, 4}, // C4 18
|
||||
{&DDRC, &PINC, &PORTC, 5} // C5 19
|
||||
};
|
||||
#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
//------------------------------------------------------------------------------
|
||||
static const uint8_t digitalPinCount = sizeof(digitalPinMap)/sizeof(pin_map_t);
|
||||
|
||||
uint8_t badPinNumber(void)
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
|
||||
static inline __attribute__((always_inline))
|
||||
uint8_t getPinMode(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].ddr >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void setPinMode(uint8_t pin, uint8_t mode) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (mode) {
|
||||
*digitalPinMap[pin].ddr |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].ddr &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
uint8_t fastDigitalRead(uint8_t pin) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
return (*digitalPinMap[pin].pin >> digitalPinMap[pin].bit) & 1;
|
||||
} else {
|
||||
return badPinNumber();
|
||||
}
|
||||
}
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, uint8_t value) {
|
||||
if (__builtin_constant_p(pin) && pin < digitalPinCount) {
|
||||
if (value) {
|
||||
*digitalPinMap[pin].port |= 1 << digitalPinMap[pin].bit;
|
||||
} else {
|
||||
*digitalPinMap[pin].port &= ~(1 << digitalPinMap[pin].bit);
|
||||
}
|
||||
} else {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
#endif // Sd2PinMap_h
|
547
arduino-0022-linux-x64/libraries/SD/utility/SdFat.h
Normal file
547
arduino-0022-linux-x64/libraries/SD/utility/SdFat.h
Normal file
|
@ -0,0 +1,547 @@
|
|||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdFat_h
|
||||
#define SdFat_h
|
||||
/**
|
||||
* \file
|
||||
* SdFile and SdVolume classes
|
||||
*/
|
||||
#include <avr/pgmspace.h>
|
||||
#include "Sd2Card.h"
|
||||
#include "FatStructs.h"
|
||||
#include "Print.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Allow use of deprecated functions if non-zero
|
||||
*/
|
||||
#define ALLOW_DEPRECATED_FUNCTIONS 1
|
||||
//------------------------------------------------------------------------------
|
||||
// forward declaration since SdVolume is used in SdFile
|
||||
class SdVolume;
|
||||
//==============================================================================
|
||||
// SdFile class
|
||||
|
||||
// flags for ls()
|
||||
/** ls() flag to print modify date */
|
||||
uint8_t const LS_DATE = 1;
|
||||
/** ls() flag to print file size */
|
||||
uint8_t const LS_SIZE = 2;
|
||||
/** ls() flag for recursive list of subdirectories */
|
||||
uint8_t const LS_R = 4;
|
||||
|
||||
// use the gnu style oflag in open()
|
||||
/** open() oflag for reading */
|
||||
uint8_t const O_READ = 0X01;
|
||||
/** open() oflag - same as O_READ */
|
||||
uint8_t const O_RDONLY = O_READ;
|
||||
/** open() oflag for write */
|
||||
uint8_t const O_WRITE = 0X02;
|
||||
/** open() oflag - same as O_WRITE */
|
||||
uint8_t const O_WRONLY = O_WRITE;
|
||||
/** open() oflag for reading and writing */
|
||||
uint8_t const O_RDWR = (O_READ | O_WRITE);
|
||||
/** open() oflag mask for access modes */
|
||||
uint8_t const O_ACCMODE = (O_READ | O_WRITE);
|
||||
/** The file offset shall be set to the end of the file prior to each write. */
|
||||
uint8_t const O_APPEND = 0X04;
|
||||
/** synchronous writes - call sync() after each write */
|
||||
uint8_t const O_SYNC = 0X08;
|
||||
/** create the file if nonexistent */
|
||||
uint8_t const O_CREAT = 0X10;
|
||||
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
|
||||
uint8_t const O_EXCL = 0X20;
|
||||
/** truncate the file to zero length */
|
||||
uint8_t const O_TRUNC = 0X40;
|
||||
|
||||
// flags for timestamp
|
||||
/** set the file's last access date */
|
||||
uint8_t const T_ACCESS = 1;
|
||||
/** set the file's creation date and time */
|
||||
uint8_t const T_CREATE = 2;
|
||||
/** Set the file's write date and time */
|
||||
uint8_t const T_WRITE = 4;
|
||||
// values for type_
|
||||
/** This SdFile has not been opened. */
|
||||
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
|
||||
/** SdFile for a file */
|
||||
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
|
||||
/** SdFile for a FAT16 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT16 = 2;
|
||||
/** SdFile for a FAT32 root directory */
|
||||
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
|
||||
/** SdFile for a subdirectory */
|
||||
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
|
||||
/** Test value for directory type */
|
||||
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT16;
|
||||
|
||||
/** date field for FAT directory entry */
|
||||
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
|
||||
return (year - 1980) << 9 | month << 5 | day;
|
||||
}
|
||||
/** year part of FAT directory date field */
|
||||
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
|
||||
return 1980 + (fatDate >> 9);
|
||||
}
|
||||
/** month part of FAT directory date field */
|
||||
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
|
||||
return (fatDate >> 5) & 0XF;
|
||||
}
|
||||
/** day part of FAT directory date field */
|
||||
static inline uint8_t FAT_DAY(uint16_t fatDate) {
|
||||
return fatDate & 0X1F;
|
||||
}
|
||||
/** time field for FAT directory entry */
|
||||
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
|
||||
return hour << 11 | minute << 5 | second >> 1;
|
||||
}
|
||||
/** hour part of FAT directory time field */
|
||||
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
|
||||
return fatTime >> 11;
|
||||
}
|
||||
/** minute part of FAT directory time field */
|
||||
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
|
||||
return(fatTime >> 5) & 0X3F;
|
||||
}
|
||||
/** second part of FAT directory time field */
|
||||
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
|
||||
return 2*(fatTime & 0X1F);
|
||||
}
|
||||
/** Default date for file timestamps is 1 Jan 2000 */
|
||||
uint16_t const FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
|
||||
/** Default time for file timestamp is 1 am */
|
||||
uint16_t const FAT_DEFAULT_TIME = (1 << 11);
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdFile
|
||||
* \brief Access FAT16 and FAT32 files on SD and SDHC cards.
|
||||
*/
|
||||
class SdFile : public Print {
|
||||
public:
|
||||
/** Create an instance of SdFile. */
|
||||
SdFile(void) : type_(FAT_FILE_TYPE_CLOSED) {}
|
||||
/**
|
||||
* writeError is set to true if an error occurs during a write().
|
||||
* Set writeError to false before calling print() and/or write() and check
|
||||
* for true after calls to print() and/or write().
|
||||
*/
|
||||
bool writeError;
|
||||
/**
|
||||
* Cancel unbuffered reads for this file.
|
||||
* See setUnbufferedRead()
|
||||
*/
|
||||
void clearUnbufferedRead(void) {
|
||||
flags_ &= ~F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
uint8_t close(void);
|
||||
uint8_t contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
uint8_t createContiguous(SdFile* dirFile,
|
||||
const char* fileName, uint32_t size);
|
||||
/** \return The current cluster number for a file or directory. */
|
||||
uint32_t curCluster(void) const {return curCluster_;}
|
||||
/** \return The current position for a file or directory. */
|
||||
uint32_t curPosition(void) const {return curPosition_;}
|
||||
/**
|
||||
* Set the date/time callback function
|
||||
*
|
||||
* \param[in] dateTime The user's call back function. The callback
|
||||
* function is of the form:
|
||||
*
|
||||
* \code
|
||||
* void dateTime(uint16_t* date, uint16_t* time) {
|
||||
* uint16_t year;
|
||||
* uint8_t month, day, hour, minute, second;
|
||||
*
|
||||
* // User gets date and time from GPS or real-time clock here
|
||||
*
|
||||
* // return date using FAT_DATE macro to format fields
|
||||
* *date = FAT_DATE(year, month, day);
|
||||
*
|
||||
* // return time using FAT_TIME macro to format fields
|
||||
* *time = FAT_TIME(hour, minute, second);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* Sets the function that is called when a file is created or when
|
||||
* a file's directory entry is modified by sync(). All timestamps,
|
||||
* access, creation, and modify, are set when a file is created.
|
||||
* sync() maintains the last access date and last modify date/time.
|
||||
*
|
||||
* See the timestamp() function.
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t* date, uint16_t* time)) {
|
||||
dateTime_ = dateTime;
|
||||
}
|
||||
/**
|
||||
* Cancel the date/time callback function.
|
||||
*/
|
||||
static void dateTimeCallbackCancel(void) {
|
||||
// use explicit zero since NULL is not defined for Sanguino
|
||||
dateTime_ = 0;
|
||||
}
|
||||
/** \return Address of the block that contains this file's directory. */
|
||||
uint32_t dirBlock(void) const {return dirBlock_;}
|
||||
uint8_t dirEntry(dir_t* dir);
|
||||
/** \return Index of this file's directory in the block dirBlock. */
|
||||
uint8_t dirIndex(void) const {return dirIndex_;}
|
||||
static void dirName(const dir_t& dir, char* name);
|
||||
/** \return The total number of bytes in a file or directory. */
|
||||
uint32_t fileSize(void) const {return fileSize_;}
|
||||
/** \return The first cluster number for a file or directory. */
|
||||
uint32_t firstCluster(void) const {return firstCluster_;}
|
||||
/** \return True if this is a SdFile for a directory else false. */
|
||||
uint8_t isDir(void) const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
|
||||
/** \return True if this is a SdFile for a file else false. */
|
||||
uint8_t isFile(void) const {return type_ == FAT_FILE_TYPE_NORMAL;}
|
||||
/** \return True if this is a SdFile for an open file/directory else false. */
|
||||
uint8_t isOpen(void) const {return type_ != FAT_FILE_TYPE_CLOSED;}
|
||||
/** \return True if this is a SdFile for a subdirectory else false. */
|
||||
uint8_t isSubDir(void) const {return type_ == FAT_FILE_TYPE_SUBDIR;}
|
||||
/** \return True if this is a SdFile for the root directory. */
|
||||
uint8_t isRoot(void) const {
|
||||
return type_ == FAT_FILE_TYPE_ROOT16 || type_ == FAT_FILE_TYPE_ROOT32;
|
||||
}
|
||||
void ls(uint8_t flags = 0, uint8_t indent = 0);
|
||||
uint8_t makeDir(SdFile* dir, const char* dirName);
|
||||
uint8_t open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
uint8_t open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||
|
||||
uint8_t openRoot(SdVolume* vol);
|
||||
static void printDirName(const dir_t& dir, uint8_t width);
|
||||
static void printFatDate(uint16_t fatDate);
|
||||
static void printFatTime(uint16_t fatTime);
|
||||
static void printTwoDigits(uint8_t v);
|
||||
/**
|
||||
* Read the next byte from a file.
|
||||
*
|
||||
* \return For success read returns the next byte in the file as an int.
|
||||
* If an error occurs or end of file is reached -1 is returned.
|
||||
*/
|
||||
int16_t read(void) {
|
||||
uint8_t b;
|
||||
return read(&b, 1) == 1 ? b : -1;
|
||||
}
|
||||
int16_t read(void* buf, uint16_t nbyte);
|
||||
int8_t readDir(dir_t* dir);
|
||||
static uint8_t remove(SdFile* dirFile, const char* fileName);
|
||||
uint8_t remove(void);
|
||||
/** Set the file's current position to zero. */
|
||||
void rewind(void) {
|
||||
curPosition_ = curCluster_ = 0;
|
||||
}
|
||||
uint8_t rmDir(void);
|
||||
uint8_t rmRfStar(void);
|
||||
/** Set the files position to current position + \a pos. See seekSet(). */
|
||||
uint8_t seekCur(uint32_t pos) {
|
||||
return seekSet(curPosition_ + pos);
|
||||
}
|
||||
/**
|
||||
* Set the files current position to end of file. Useful to position
|
||||
* a file for append. See seekSet().
|
||||
*/
|
||||
uint8_t seekEnd(void) {return seekSet(fileSize_);}
|
||||
uint8_t seekSet(uint32_t pos);
|
||||
/**
|
||||
* Use unbuffered reads to access this file. Used with Wave
|
||||
* Shield ISR. Used with Sd2Card::partialBlockRead() in WaveRP.
|
||||
*
|
||||
* Not recommended for normal applications.
|
||||
*/
|
||||
void setUnbufferedRead(void) {
|
||||
if (isFile()) flags_ |= F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
uint8_t timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
|
||||
uint8_t hour, uint8_t minute, uint8_t second);
|
||||
uint8_t sync(void);
|
||||
/** Type of this SdFile. You should use isFile() or isDir() instead of type()
|
||||
* if possible.
|
||||
*
|
||||
* \return The file or directory type.
|
||||
*/
|
||||
uint8_t type(void) const {return type_;}
|
||||
uint8_t truncate(uint32_t size);
|
||||
/** \return Unbuffered read flag. */
|
||||
uint8_t unbufferedRead(void) const {
|
||||
return flags_ & F_FILE_UNBUFFERED_READ;
|
||||
}
|
||||
/** \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);
|
||||
void write_P(PGM_P str);
|
||||
void writeln_P(PGM_P str);
|
||||
//------------------------------------------------------------------------------
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
|
||||
*/
|
||||
uint8_t contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
|
||||
return contiguousRange(&bgnBlock, &endBlock);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::createContiguous(SdFile* dirFile,
|
||||
* const char* fileName, uint32_t size)
|
||||
*/
|
||||
uint8_t createContiguous(SdFile& dirFile, // NOLINT
|
||||
const char* fileName, uint32_t size) {
|
||||
return createContiguous(&dirFile, fileName, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* \deprecated Use:
|
||||
* static void SdFile::dateTimeCallback(
|
||||
* void (*dateTime)(uint16_t* date, uint16_t* time));
|
||||
*/
|
||||
static void dateTimeCallback(
|
||||
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
|
||||
oldDateTime_ = dateTime;
|
||||
dateTime_ = dateTime ? oldToNew : 0;
|
||||
}
|
||||
/** \deprecated Use: uint8_t SdFile::dirEntry(dir_t* dir); */
|
||||
uint8_t dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::makeDir(SdFile* dir, const char* dirName);
|
||||
*/
|
||||
uint8_t makeDir(SdFile& dir, const char* dirName) { // NOLINT
|
||||
return makeDir(&dir, dirName);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::open(SdFile* dirFile, const char* fileName, uint8_t oflag);
|
||||
*/
|
||||
uint8_t open(SdFile& dirFile, // NOLINT
|
||||
const char* fileName, uint8_t oflag) {
|
||||
return open(&dirFile, fileName, oflag);
|
||||
}
|
||||
/** \deprecated Do not use in new apps */
|
||||
uint8_t open(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||
return open(dirFile, fileName, O_RDWR);
|
||||
}
|
||||
/** \deprecated Use:
|
||||
* uint8_t SdFile::open(SdFile* dirFile, uint16_t index, uint8_t oflag);
|
||||
*/
|
||||
uint8_t open(SdFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
|
||||
return open(&dirFile, index, oflag);
|
||||
}
|
||||
/** \deprecated Use: uint8_t SdFile::openRoot(SdVolume* vol); */
|
||||
uint8_t openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
|
||||
|
||||
/** \deprecated Use: int8_t SdFile::readDir(dir_t* dir); */
|
||||
int8_t readDir(dir_t& dir) {return readDir(&dir);} // NOLINT
|
||||
/** \deprecated Use:
|
||||
* static uint8_t SdFile::remove(SdFile* dirFile, const char* fileName);
|
||||
*/
|
||||
static uint8_t remove(SdFile& dirFile, const char* fileName) { // NOLINT
|
||||
return remove(&dirFile, fileName);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// rest are private
|
||||
private:
|
||||
static void (*oldDateTime_)(uint16_t& date, uint16_t& time); // NOLINT
|
||||
static void oldToNew(uint16_t* date, uint16_t* time) {
|
||||
uint16_t d;
|
||||
uint16_t t;
|
||||
oldDateTime_(d, t);
|
||||
*date = d;
|
||||
*time = t;
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
private:
|
||||
// bits defined in flags_
|
||||
// should be 0XF
|
||||
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
|
||||
// available bits
|
||||
static uint8_t const F_UNUSED = 0X30;
|
||||
// use unbuffered SD read
|
||||
static uint8_t const F_FILE_UNBUFFERED_READ = 0X40;
|
||||
// sync of directory entry required
|
||||
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
|
||||
|
||||
// make sure F_OFLAG is ok
|
||||
#if ((F_UNUSED | F_FILE_UNBUFFERED_READ | F_FILE_DIR_DIRTY) & F_OFLAG)
|
||||
#error flags_ bits conflict
|
||||
#endif // flags_ bits
|
||||
|
||||
// private data
|
||||
uint8_t flags_; // See above for definition of flags_ bits
|
||||
uint8_t type_; // type of file see above for values
|
||||
uint32_t curCluster_; // cluster for current file position
|
||||
uint32_t curPosition_; // current file position in bytes from beginning
|
||||
uint32_t dirBlock_; // SD block that contains directory entry for file
|
||||
uint8_t dirIndex_; // index of entry in dirBlock 0 <= dirIndex_ <= 0XF
|
||||
uint32_t fileSize_; // file size in bytes
|
||||
uint32_t firstCluster_; // first cluster of file
|
||||
SdVolume* vol_; // volume where file is located
|
||||
|
||||
// private functions
|
||||
uint8_t addCluster(void);
|
||||
uint8_t addDirCluster(void);
|
||||
dir_t* cacheDirEntry(uint8_t action);
|
||||
static void (*dateTime_)(uint16_t* date, uint16_t* time);
|
||||
static uint8_t make83Name(const char* str, uint8_t* name);
|
||||
uint8_t openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
|
||||
dir_t* readDirCache(void);
|
||||
};
|
||||
//==============================================================================
|
||||
// SdVolume class
|
||||
/**
|
||||
* \brief Cache for an SD data block
|
||||
*/
|
||||
union cache_t {
|
||||
/** Used to access cached file data blocks. */
|
||||
uint8_t data[512];
|
||||
/** Used to access cached FAT16 entries. */
|
||||
uint16_t fat16[256];
|
||||
/** Used to access cached FAT32 entries. */
|
||||
uint32_t fat32[128];
|
||||
/** Used to access cached directory entries. */
|
||||
dir_t dir[16];
|
||||
/** Used to access a cached MasterBoot Record. */
|
||||
mbr_t mbr;
|
||||
/** Used to access to a cached FAT boot sector. */
|
||||
fbs_t fbs;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* \class SdVolume
|
||||
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
|
||||
*/
|
||||
class SdVolume {
|
||||
public:
|
||||
/** Create an instance of SdVolume */
|
||||
SdVolume(void) :allocSearchStart_(2), fatType_(0) {}
|
||||
/** Clear the cache and returns a pointer to the cache. Used by the WaveRP
|
||||
* recorder to do raw write to the SD card. Not for normal apps.
|
||||
*/
|
||||
static uint8_t* cacheClear(void) {
|
||||
cacheFlush();
|
||||
cacheBlockNumber_ = 0XFFFFFFFF;
|
||||
return cacheBuffer_.data;
|
||||
}
|
||||
/**
|
||||
* Initialize a FAT volume. Try partition one first then try super
|
||||
* floppy format.
|
||||
*
|
||||
* \param[in] dev The Sd2Card where the volume is located.
|
||||
*
|
||||
* \return The value one, true, is returned for success and
|
||||
* the value zero, false, is returned for failure. Reasons for
|
||||
* failure include not finding a valid partition, not finding a valid
|
||||
* FAT file system or an I/O error.
|
||||
*/
|
||||
uint8_t init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
|
||||
uint8_t init(Sd2Card* dev, uint8_t part);
|
||||
|
||||
// inline functions that return volume info
|
||||
/** \return The volume's cluster size in blocks. */
|
||||
uint8_t blocksPerCluster(void) const {return blocksPerCluster_;}
|
||||
/** \return The number of blocks in one FAT. */
|
||||
uint32_t blocksPerFat(void) const {return blocksPerFat_;}
|
||||
/** \return The total number of clusters in the volume. */
|
||||
uint32_t clusterCount(void) const {return clusterCount_;}
|
||||
/** \return The shift count required to multiply by blocksPerCluster. */
|
||||
uint8_t clusterSizeShift(void) const {return clusterSizeShift_;}
|
||||
/** \return The logical block number for the start of file data. */
|
||||
uint32_t dataStartBlock(void) const {return dataStartBlock_;}
|
||||
/** \return The number of FAT structures on the volume. */
|
||||
uint8_t fatCount(void) const {return fatCount_;}
|
||||
/** \return The logical block number for the start of the first FAT. */
|
||||
uint32_t fatStartBlock(void) const {return fatStartBlock_;}
|
||||
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
|
||||
uint8_t fatType(void) const {return fatType_;}
|
||||
/** \return The number of entries in the root directory for FAT16 volumes. */
|
||||
uint32_t rootDirEntryCount(void) const {return rootDirEntryCount_;}
|
||||
/** \return The logical block number for the start of the root directory
|
||||
on FAT16 volumes or the first cluster number on FAT32 volumes. */
|
||||
uint32_t rootDirStart(void) const {return rootDirStart_;}
|
||||
/** return a pointer to the Sd2Card object for this volume */
|
||||
static Sd2Card* sdCard(void) {return sdCard_;}
|
||||
//------------------------------------------------------------------------------
|
||||
#if ALLOW_DEPRECATED_FUNCTIONS
|
||||
// Deprecated functions - suppress cpplint warnings with NOLINT comment
|
||||
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev); */
|
||||
uint8_t init(Sd2Card& dev) {return init(&dev);} // NOLINT
|
||||
|
||||
/** \deprecated Use: uint8_t SdVolume::init(Sd2Card* dev, uint8_t vol); */
|
||||
uint8_t init(Sd2Card& dev, uint8_t part) { // NOLINT
|
||||
return init(&dev, part);
|
||||
}
|
||||
#endif // ALLOW_DEPRECATED_FUNCTIONS
|
||||
//------------------------------------------------------------------------------
|
||||
private:
|
||||
// Allow SdFile access to SdVolume private data.
|
||||
friend class SdFile;
|
||||
|
||||
// value for action argument in cacheRawBlock to indicate read from cache
|
||||
static uint8_t const CACHE_FOR_READ = 0;
|
||||
// value for action argument in cacheRawBlock to indicate cache dirty
|
||||
static uint8_t const CACHE_FOR_WRITE = 1;
|
||||
|
||||
static cache_t cacheBuffer_; // 512 byte cache for device blocks
|
||||
static uint32_t cacheBlockNumber_; // Logical number of block in the cache
|
||||
static Sd2Card* sdCard_; // Sd2Card object for cache
|
||||
static uint8_t cacheDirty_; // cacheFlush() will write block if true
|
||||
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
|
||||
//
|
||||
uint32_t allocSearchStart_; // start cluster for alloc search
|
||||
uint8_t blocksPerCluster_; // cluster size in blocks
|
||||
uint32_t blocksPerFat_; // FAT size in blocks
|
||||
uint32_t clusterCount_; // clusters in one FAT
|
||||
uint8_t clusterSizeShift_; // shift to convert cluster count to block count
|
||||
uint32_t dataStartBlock_; // first data block number
|
||||
uint8_t fatCount_; // number of FATs on volume
|
||||
uint32_t fatStartBlock_; // start block for first FAT
|
||||
uint8_t fatType_; // volume type (12, 16, OR 32)
|
||||
uint16_t rootDirEntryCount_; // number of entries in FAT16 root dir
|
||||
uint32_t rootDirStart_; // root start block for FAT16, cluster for FAT32
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t allocContiguous(uint32_t count, uint32_t* curCluster);
|
||||
uint8_t blockOfCluster(uint32_t position) const {
|
||||
return (position >> 9) & (blocksPerCluster_ - 1);}
|
||||
uint32_t clusterStartBlock(uint32_t cluster) const {
|
||||
return dataStartBlock_ + ((cluster - 2) << clusterSizeShift_);}
|
||||
uint32_t blockNumber(uint32_t cluster, uint32_t position) const {
|
||||
return clusterStartBlock(cluster) + blockOfCluster(position);}
|
||||
static uint8_t cacheFlush(void);
|
||||
static uint8_t cacheRawBlock(uint32_t blockNumber, uint8_t action);
|
||||
static void cacheSetDirty(void) {cacheDirty_ |= CACHE_FOR_WRITE;}
|
||||
static uint8_t cacheZeroBlock(uint32_t blockNumber);
|
||||
uint8_t chainSize(uint32_t beginCluster, uint32_t* size) const;
|
||||
uint8_t fatGet(uint32_t cluster, uint32_t* value) const;
|
||||
uint8_t fatPut(uint32_t cluster, uint32_t value);
|
||||
uint8_t fatPutEOC(uint32_t cluster) {
|
||||
return fatPut(cluster, 0x0FFFFFFF);
|
||||
}
|
||||
uint8_t freeChain(uint32_t cluster);
|
||||
uint8_t isEOC(uint32_t cluster) const {
|
||||
return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);
|
||||
}
|
||||
uint8_t readBlock(uint32_t block, uint8_t* dst) {
|
||||
return sdCard_->readBlock(block, dst);}
|
||||
uint8_t readData(uint32_t block, uint16_t offset,
|
||||
uint16_t count, uint8_t* dst) {
|
||||
return sdCard_->readData(block, offset, count, dst);
|
||||
}
|
||||
uint8_t writeBlock(uint32_t block, const uint8_t* dst) {
|
||||
return sdCard_->writeBlock(block, dst);
|
||||
}
|
||||
};
|
||||
#endif // SdFat_h
|
70
arduino-0022-linux-x64/libraries/SD/utility/SdFatUtil.h
Normal file
70
arduino-0022-linux-x64/libraries/SD/utility/SdFatUtil.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2008 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdFatUtil_h
|
||||
#define SdFatUtil_h
|
||||
/**
|
||||
* \file
|
||||
* Useful utility functions.
|
||||
*/
|
||||
#include <WProgram.h>
|
||||
#include <avr/pgmspace.h>
|
||||
/** Store and print a string in flash memory.*/
|
||||
#define PgmPrint(x) SerialPrint_P(PSTR(x))
|
||||
/** Store and print a string in flash memory followed by a CR/LF.*/
|
||||
#define PgmPrintln(x) SerialPrintln_P(PSTR(x))
|
||||
/** Defined so doxygen works for function definitions. */
|
||||
#define NOINLINE __attribute__((noinline))
|
||||
//------------------------------------------------------------------------------
|
||||
/** Return the number of bytes currently free in RAM. */
|
||||
static int FreeRam(void) {
|
||||
extern int __bss_end;
|
||||
extern int* __brkval;
|
||||
int free_memory;
|
||||
if (reinterpret_cast<int>(__brkval) == 0) {
|
||||
// if no heap use from end of bss section
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(&__bss_end);
|
||||
} else {
|
||||
// use from top of stack to heap
|
||||
free_memory = reinterpret_cast<int>(&free_memory)
|
||||
- reinterpret_cast<int>(__brkval);
|
||||
}
|
||||
return free_memory;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* %Print a string in flash memory to the serial port.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
static NOINLINE void SerialPrint_P(PGM_P str) {
|
||||
for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.print(c);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* %Print a string in flash memory followed by a CR/LF.
|
||||
*
|
||||
* \param[in] str Pointer to string stored in flash memory.
|
||||
*/
|
||||
static NOINLINE void SerialPrintln_P(PGM_P str) {
|
||||
SerialPrint_P(str);
|
||||
Serial.println();
|
||||
}
|
||||
#endif // #define SdFatUtil_h
|
202
arduino-0022-linux-x64/libraries/SD/utility/SdFatmainpage.h
Normal file
202
arduino-0022-linux-x64/libraries/SD/utility/SdFatmainpage.h
Normal file
|
@ -0,0 +1,202 @@
|
|||
/* Arduino SdFat Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino SdFat Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino SdFat Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
\mainpage Arduino SdFat Library
|
||||
<CENTER>Copyright © 2009 by William Greiman
|
||||
</CENTER>
|
||||
|
||||
\section Intro Introduction
|
||||
The Arduino SdFat Library is a minimal implementation of FAT16 and FAT32
|
||||
file systems on SD flash memory cards. Standard SD and high capacity
|
||||
SDHC cards are supported.
|
||||
|
||||
The SdFat only supports short 8.3 names.
|
||||
|
||||
The main classes in SdFat are Sd2Card, SdVolume, and SdFile.
|
||||
|
||||
The Sd2Card class supports access to standard SD cards and SDHC cards. Most
|
||||
applications will only need to call the Sd2Card::init() member function.
|
||||
|
||||
The SdVolume class supports FAT16 and FAT32 partitions. Most applications
|
||||
will only need to call the SdVolume::init() member function.
|
||||
|
||||
The SdFile class provides file access functions such as open(), read(),
|
||||
remove(), write(), close() and sync(). This class supports access to the root
|
||||
directory and subdirectories.
|
||||
|
||||
A number of example are provided in the SdFat/examples folder. These were
|
||||
developed to test SdFat and illustrate its use.
|
||||
|
||||
SdFat was developed for high speed data recording. SdFat was used to implement
|
||||
an audio record/play class, WaveRP, for the Adafruit Wave Shield. This
|
||||
application uses special Sd2Card calls to write to contiguous files in raw mode.
|
||||
These functions reduce write latency so that audio can be recorded with the
|
||||
small amount of RAM in the Arduino.
|
||||
|
||||
\section SDcard SD\SDHC Cards
|
||||
|
||||
Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
|
||||
most consumer devices use the 4-bit parallel SD protocol. A card that
|
||||
functions well on A PC or Mac may not work well on the Arduino.
|
||||
|
||||
Most cards have good SPI read performance but cards vary widely in SPI
|
||||
write performance. Write performance is limited by how efficiently the
|
||||
card manages internal erase/remapping operations. The Arduino cannot
|
||||
optimize writes to reduce erase operations because of its limit RAM.
|
||||
|
||||
SanDisk cards generally have good write performance. They seem to have
|
||||
more internal RAM buffering than other cards and therefore can limit
|
||||
the number of flash erase operations that the Arduino forces due to its
|
||||
limited RAM.
|
||||
|
||||
\section Hardware Hardware Configuration
|
||||
|
||||
SdFat was developed using an
|
||||
<A HREF = "http://www.adafruit.com/"> Adafruit Industries</A>
|
||||
<A HREF = "http://www.ladyada.net/make/waveshield/"> Wave Shield</A>.
|
||||
|
||||
The hardware interface to the SD card should not use a resistor based level
|
||||
shifter. SdFat sets the SPI bus frequency to 8 MHz which results in signal
|
||||
rise times that are too slow for the edge detectors in many newer SD card
|
||||
controllers when resistor voltage dividers are used.
|
||||
|
||||
The 5 to 3.3 V level shifter for 5 V Arduinos should be IC based like the
|
||||
74HC4050N based circuit shown in the file SdLevel.png. The Adafruit Wave Shield
|
||||
uses a 74AHC125N. Gravitech sells SD and MicroSD Card Adapters based on the
|
||||
74LCX245.
|
||||
|
||||
If you are using a resistor based level shifter and are having problems try
|
||||
setting the SPI bus frequency to 4 MHz. This can be done by using
|
||||
card.init(SPI_HALF_SPEED) to initialize the SD card.
|
||||
|
||||
\section comment Bugs and Comments
|
||||
|
||||
If you wish to report bugs or have comments, send email to fat16lib@sbcglobal.net.
|
||||
|
||||
\section SdFatClass SdFat Usage
|
||||
|
||||
SdFat uses a slightly restricted form of short names.
|
||||
Only printable ASCII characters are supported. No characters with code point
|
||||
values greater than 127 are allowed. Space is not allowed even though space
|
||||
was allowed in the API of early versions of DOS.
|
||||
|
||||
Short names are limited to 8 characters followed by an optional period (.)
|
||||
and extension of up to 3 characters. The characters may be any combination
|
||||
of letters and digits. The following special characters are also allowed:
|
||||
|
||||
$ % ' - _ @ ~ ` ! ( ) { } ^ # &
|
||||
|
||||
Short names are always converted to upper case and their original case
|
||||
value is lost.
|
||||
|
||||
\note
|
||||
The Arduino Print class uses character
|
||||
at a time writes so it was necessary to use a \link SdFile::sync() sync() \endlink
|
||||
function to control when data is written to the SD card.
|
||||
|
||||
\par
|
||||
An application which writes to a file using \link Print::print() print()\endlink,
|
||||
\link Print::println() println() \endlink
|
||||
or \link SdFile::write write() \endlink must call \link SdFile::sync() sync() \endlink
|
||||
at the appropriate time to force data and directory information to be written
|
||||
to the SD Card. Data and directory information are also written to the SD card
|
||||
when \link SdFile::close() close() \endlink is called.
|
||||
|
||||
\par
|
||||
Applications must use care calling \link SdFile::sync() sync() \endlink
|
||||
since 2048 bytes of I/O is required to update file and
|
||||
directory information. This includes writing the current data block, reading
|
||||
the block that contains the directory entry for update, writing the directory
|
||||
block back and reading back the current data block.
|
||||
|
||||
It is possible to open a file with two or more instances of SdFile. A file may
|
||||
be corrupted if data is written to the file by more than one instance of SdFile.
|
||||
|
||||
\section HowTo How to format SD Cards as FAT Volumes
|
||||
|
||||
You should use a freshly formatted SD card for best performance. FAT
|
||||
file systems become slower if many files have been created and deleted.
|
||||
This is because the directory entry for a deleted file is marked as deleted,
|
||||
but is not deleted. When a new file is created, these entries must be scanned
|
||||
before creating the file, a flaw in the FAT design. Also files can become
|
||||
fragmented which causes reads and writes to be slower.
|
||||
|
||||
Microsoft operating systems support removable media formatted with a
|
||||
Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
|
||||
in block zero.
|
||||
|
||||
Microsoft operating systems expect MBR formatted removable media
|
||||
to have only one partition. The first partition should be used.
|
||||
|
||||
Microsoft operating systems do not support partitioning SD flash cards.
|
||||
If you erase an SD card with a program like KillDisk, Most versions of
|
||||
Windows will format the card as a super floppy.
|
||||
|
||||
The best way to restore an SD card's format is to use SDFormatter
|
||||
which can be downloaded from:
|
||||
|
||||
http://www.sdcard.org/consumers/formatter/
|
||||
|
||||
SDFormatter aligns flash erase boundaries with file
|
||||
system structures which reduces write latency and file system overhead.
|
||||
|
||||
SDFormatter does not have an option for FAT type so it may format
|
||||
small cards as FAT12.
|
||||
|
||||
After the MBR is restored by SDFormatter you may need to reformat small
|
||||
cards that have been formatted FAT12 to force the volume type to be FAT16.
|
||||
|
||||
If you reformat the SD card with an OS utility, choose a cluster size that
|
||||
will result in:
|
||||
|
||||
4084 < CountOfClusters && CountOfClusters < 65525
|
||||
|
||||
The volume will then be FAT16.
|
||||
|
||||
If you are formatting an SD card on OS X or Linux, be sure to use the first
|
||||
partition. Format this partition with a cluster count in above range.
|
||||
|
||||
\section References References
|
||||
|
||||
Adafruit Industries:
|
||||
|
||||
http://www.adafruit.com/
|
||||
|
||||
http://www.ladyada.net/make/waveshield/
|
||||
|
||||
The Arduino site:
|
||||
|
||||
http://www.arduino.cc/
|
||||
|
||||
For more information about FAT file systems see:
|
||||
|
||||
http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
|
||||
For information about using SD cards as SPI devices see:
|
||||
|
||||
http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
|
||||
The ATmega328 datasheet:
|
||||
|
||||
http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
|
||||
|
||||
|
||||
*/
|
1252
arduino-0022-linux-x64/libraries/SD/utility/SdFile.cpp
Normal file
1252
arduino-0022-linux-x64/libraries/SD/utility/SdFile.cpp
Normal file
File diff suppressed because it is too large
Load diff
232
arduino-0022-linux-x64/libraries/SD/utility/SdInfo.h
Normal file
232
arduino-0022-linux-x64/libraries/SD/utility/SdInfo.h
Normal file
|
@ -0,0 +1,232 @@
|
|||
/* Arduino Sd2Card Library
|
||||
* Copyright (C) 2009 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino Sd2Card Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino Sd2Card Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SdInfo_h
|
||||
#define SdInfo_h
|
||||
#include <stdint.h>
|
||||
// Based on the document:
|
||||
//
|
||||
// SD Specifications
|
||||
// Part 1
|
||||
// Physical Layer
|
||||
// Simplified Specification
|
||||
// Version 2.00
|
||||
// September 25, 2006
|
||||
//
|
||||
// www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
|
||||
//------------------------------------------------------------------------------
|
||||
// SD card commands
|
||||
/** GO_IDLE_STATE - init card in spi mode if CS low */
|
||||
uint8_t const CMD0 = 0X00;
|
||||
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
|
||||
uint8_t const CMD8 = 0X08;
|
||||
/** SEND_CSD - read the Card Specific Data (CSD register) */
|
||||
uint8_t const CMD9 = 0X09;
|
||||
/** SEND_CID - read the card identification information (CID register) */
|
||||
uint8_t const CMD10 = 0X0A;
|
||||
/** SEND_STATUS - read the card status register */
|
||||
uint8_t const CMD13 = 0X0D;
|
||||
/** READ_BLOCK - read a single data block from the card */
|
||||
uint8_t const CMD17 = 0X11;
|
||||
/** WRITE_BLOCK - write a single data block to the card */
|
||||
uint8_t const CMD24 = 0X18;
|
||||
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
|
||||
uint8_t const CMD25 = 0X19;
|
||||
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
|
||||
uint8_t const CMD32 = 0X20;
|
||||
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
|
||||
range to be erased*/
|
||||
uint8_t const CMD33 = 0X21;
|
||||
/** ERASE - erase all previously selected blocks */
|
||||
uint8_t const CMD38 = 0X26;
|
||||
/** APP_CMD - escape for application specific command */
|
||||
uint8_t const CMD55 = 0X37;
|
||||
/** READ_OCR - read the OCR register of a card */
|
||||
uint8_t const CMD58 = 0X3A;
|
||||
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
|
||||
pre-erased before writing */
|
||||
uint8_t const ACMD23 = 0X17;
|
||||
/** SD_SEND_OP_COMD - Sends host capacity support information and
|
||||
activates the card's initialization process */
|
||||
uint8_t const ACMD41 = 0X29;
|
||||
//------------------------------------------------------------------------------
|
||||
/** status for card in the ready state */
|
||||
uint8_t const R1_READY_STATE = 0X00;
|
||||
/** status for card in the idle state */
|
||||
uint8_t const R1_IDLE_STATE = 0X01;
|
||||
/** status bit for illegal command */
|
||||
uint8_t const R1_ILLEGAL_COMMAND = 0X04;
|
||||
/** start data token for read or write single block*/
|
||||
uint8_t const DATA_START_BLOCK = 0XFE;
|
||||
/** stop token for write multiple blocks*/
|
||||
uint8_t const STOP_TRAN_TOKEN = 0XFD;
|
||||
/** start data token for write multiple blocks*/
|
||||
uint8_t const WRITE_MULTIPLE_TOKEN = 0XFC;
|
||||
/** mask for data response tokens after a write block operation */
|
||||
uint8_t const DATA_RES_MASK = 0X1F;
|
||||
/** write data accepted token */
|
||||
uint8_t const DATA_RES_ACCEPTED = 0X05;
|
||||
//------------------------------------------------------------------------------
|
||||
typedef struct CID {
|
||||
// byte 0
|
||||
uint8_t mid; // Manufacturer ID
|
||||
// byte 1-2
|
||||
char oid[2]; // OEM/Application ID
|
||||
// byte 3-7
|
||||
char pnm[5]; // Product name
|
||||
// byte 8
|
||||
unsigned prv_m : 4; // Product revision n.m
|
||||
unsigned prv_n : 4;
|
||||
// byte 9-12
|
||||
uint32_t psn; // Product serial number
|
||||
// byte 13
|
||||
unsigned mdt_year_high : 4; // Manufacturing date
|
||||
unsigned reserved : 4;
|
||||
// byte 14
|
||||
unsigned mdt_month : 4;
|
||||
unsigned mdt_year_low :4;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}cid_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// CSD for version 1.00 cards
|
||||
typedef struct CSDV1 {
|
||||
// byte 0
|
||||
unsigned reserved1 : 6;
|
||||
unsigned csd_ver : 2;
|
||||
// byte 1
|
||||
uint8_t taac;
|
||||
// byte 2
|
||||
uint8_t nsac;
|
||||
// byte 3
|
||||
uint8_t tran_speed;
|
||||
// byte 4
|
||||
uint8_t ccc_high;
|
||||
// byte 5
|
||||
unsigned read_bl_len : 4;
|
||||
unsigned ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned c_size_high : 2;
|
||||
unsigned reserved2 : 2;
|
||||
unsigned dsr_imp : 1;
|
||||
unsigned read_blk_misalign :1;
|
||||
unsigned write_blk_misalign : 1;
|
||||
unsigned read_bl_partial : 1;
|
||||
// byte 7
|
||||
uint8_t c_size_mid;
|
||||
// byte 8
|
||||
unsigned vdd_r_curr_max : 3;
|
||||
unsigned vdd_r_curr_min : 3;
|
||||
unsigned c_size_low :2;
|
||||
// byte 9
|
||||
unsigned c_size_mult_high : 2;
|
||||
unsigned vdd_w_cur_max : 3;
|
||||
unsigned vdd_w_curr_min : 3;
|
||||
// byte 10
|
||||
unsigned sector_size_high : 6;
|
||||
unsigned erase_blk_en : 1;
|
||||
unsigned c_size_mult_low : 1;
|
||||
// byte 11
|
||||
unsigned wp_grp_size : 7;
|
||||
unsigned sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned write_bl_len_high : 2;
|
||||
unsigned r2w_factor : 3;
|
||||
unsigned reserved3 : 2;
|
||||
unsigned wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned reserved4 : 5;
|
||||
unsigned write_partial : 1;
|
||||
unsigned write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned reserved5: 2;
|
||||
unsigned file_format : 2;
|
||||
unsigned tmp_write_protect : 1;
|
||||
unsigned perm_write_protect : 1;
|
||||
unsigned copy : 1;
|
||||
unsigned file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}csd1_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// CSD for version 2.00 cards
|
||||
typedef struct CSDV2 {
|
||||
// byte 0
|
||||
unsigned reserved1 : 6;
|
||||
unsigned csd_ver : 2;
|
||||
// byte 1
|
||||
uint8_t taac;
|
||||
// byte 2
|
||||
uint8_t nsac;
|
||||
// byte 3
|
||||
uint8_t tran_speed;
|
||||
// byte 4
|
||||
uint8_t ccc_high;
|
||||
// byte 5
|
||||
unsigned read_bl_len : 4;
|
||||
unsigned ccc_low : 4;
|
||||
// byte 6
|
||||
unsigned reserved2 : 4;
|
||||
unsigned dsr_imp : 1;
|
||||
unsigned read_blk_misalign :1;
|
||||
unsigned write_blk_misalign : 1;
|
||||
unsigned read_bl_partial : 1;
|
||||
// byte 7
|
||||
unsigned reserved3 : 2;
|
||||
unsigned c_size_high : 6;
|
||||
// byte 8
|
||||
uint8_t c_size_mid;
|
||||
// byte 9
|
||||
uint8_t c_size_low;
|
||||
// byte 10
|
||||
unsigned sector_size_high : 6;
|
||||
unsigned erase_blk_en : 1;
|
||||
unsigned reserved4 : 1;
|
||||
// byte 11
|
||||
unsigned wp_grp_size : 7;
|
||||
unsigned sector_size_low : 1;
|
||||
// byte 12
|
||||
unsigned write_bl_len_high : 2;
|
||||
unsigned r2w_factor : 3;
|
||||
unsigned reserved5 : 2;
|
||||
unsigned wp_grp_enable : 1;
|
||||
// byte 13
|
||||
unsigned reserved6 : 5;
|
||||
unsigned write_partial : 1;
|
||||
unsigned write_bl_len_low : 2;
|
||||
// byte 14
|
||||
unsigned reserved7: 2;
|
||||
unsigned file_format : 2;
|
||||
unsigned tmp_write_protect : 1;
|
||||
unsigned perm_write_protect : 1;
|
||||
unsigned copy : 1;
|
||||
unsigned file_format_grp : 1;
|
||||
// byte 15
|
||||
unsigned always1 : 1;
|
||||
unsigned crc : 7;
|
||||
}csd2_t;
|
||||
//------------------------------------------------------------------------------
|
||||
// union of old and new style CSD register
|
||||
union csd_t {
|
||||
csd1_t v1;
|
||||
csd2_t v2;
|
||||
};
|
||||
#endif // SdInfo_h
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue