first commit

master
drake 12 years ago
commit fc32e20881

5
Marlin/.gitignore vendored

@ -0,0 +1,5 @@
*.o
applet/
*~
*.orig
*.rej

@ -0,0 +1,35 @@
##############################################################
Generation_Series.name=Gen6 & Gen6 Deluxe
Generation_Series.upload.protocol=stk500
Generation_Series.upload.maximum_size=63488
Generation_Series.upload.speed=38400
Generation_Series.bootloader.low_fuses=0xFF
Generation_Series.bootloader.high_fuses=0xDC
Generation_Series.bootloader.extended_fuses=0xFD
Generation_Series.bootloader.path=atmega644p
Generation_Series.bootloader.file=ATmegaBOOT_644P.hex
Generation_Series.bootloader.unlock_bits=0x3F
Generation_Series.bootloader.lock_bits=0x0F
Generation_Series.build.mcu=atmega644p
Generation_Series.build.f_cpu=16000000L
Generation_Series.build.core=arduino
##############################################################
Sanguinololu.name=Sanguinololu 1.2 and above
Sanguinololu.upload.protocol=stk500
Sanguinololu.upload.maximum_size=63488
Sanguinololu.upload.speed=38400
Sanguinololu.bootloader.low_fuses=0xFF
Sanguinololu.bootloader.high_fuses=0xDC
Sanguinololu.bootloader.extended_fuses=0xFD
Sanguinololu.bootloader.path=atmega644p
Sanguinololu.bootloader.file=ATmegaBOOT_644P.hex
Sanguinololu.bootloader.unlock_bits=0x3F
Sanguinololu.bootloader.lock_bits=0x0F
Sanguinololu.build.mcu=atmega644p
Sanguinololu.build.f_cpu=16000000L
Sanguinololu.build.core=arduino

@ -0,0 +1,713 @@
/**********************************************************/
/* Serial Bootloader for Atmel megaAVR Controllers */
/* */
/* tested with ATmega644 and ATmega644P */
/* should work with other mega's, see code for details */
/* */
/* ATmegaBOOT.c */
/* */
/* 20090131: Added 324P support from Alex Leone */
/* Marius Kintel */
/* 20080915: applied ADABoot mods for Sanguino 644P */
/* Brian Riley */
/* 20080711: hacked for Sanguino by Zach Smith */
/* and Justin Day */
/* 20070626: hacked for Arduino Diecimila (which auto- */
/* resets when a USB connection is made to it) */
/* by D. Mellis */
/* 20060802: hacked for Arduino by D. Cuartielles */
/* based on a previous hack by D. Mellis */
/* and D. Cuartielles */
/* */
/* Monitor and debug functions were added to the original */
/* code by Dr. Erik Lins, chip45.com. (See below) */
/* */
/* Thanks to Karl Pitrich for fixing a bootloader pin */
/* problem and more informative LED blinking! */
/* */
/* For the latest version see: */
/* http://www.chip45.com/ */
/* */
/* ------------------------------------------------------ */
/* */
/* based on stk500boot.c */
/* Copyright (c) 2003, Jason P. Kyle */
/* All rights reserved. */
/* see avr1.org for original file and information */
/* */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will */
/* be useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with this program; if not, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
/* m8515,m8535. ATmega161 has a very small boot block so */
/* isn't supported. */
/* */
/* Tested with m168 */
/**********************************************************/
/* $Id$ */
/* some includes */
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/boot.h>
#ifdef ADABOOT
#define NUM_LED_FLASHES 3
#define ADABOOT_VER 1
#endif
/* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */
#define MAX_ERROR_COUNT 5
/* set the UART baud rate */
/* 20080711: hack by Zach Hoeken */
#define BAUD_RATE 38400
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
/* never allow AVR Studio to do an update !!!! */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x10
/* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */
/* if monitor functions are included, LED goes on after monitor was entered */
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED PINB0
/* define various device id's */
/* manufacturer byte is always the same */
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#if defined(__AVR_ATmega644P__)
#define SIG2 0x96
#define SIG3 0x0A
#elif defined(__AVR_ATmega644__)
#define SIG2 0x96
#define SIG3 0x09
#elif defined(__AVR_ATmega324P__)
#define SIG2 0x95
#define SIG3 0x08
#endif
#define PAGE_SIZE 0x080U //128 words
#define PAGE_SIZE_BYTES 0x100U //256 bytes
/* function prototypes */
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
char gethex(void);
void puthex(char);
void flash_led(uint8_t);
/* some variables */
union address_union
{
uint16_t word;
uint8_t byte[2];
} address;
union length_union
{
uint16_t word;
uint8_t byte[2];
} length;
struct flags_struct
{
unsigned eeprom : 1;
unsigned rampz : 1;
} flags;
uint8_t buff[256];
uint8_t error_count = 0;
uint8_t sreg;
void (*app_start)(void) = 0x0000;
/* main program starts here */
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
uint16_t i;
asm volatile("nop\n\t");
#ifdef ADABOOT // BBR/LF 10/8/2007 & 9/13/2008
ch = MCUSR;
MCUSR = 0;
WDTCSR |= _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
// Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.
if (! (ch & _BV(EXTRF))) // if its a not an external reset...
app_start(); // skip bootloader
#endif
//initialize our serial port.
UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
/* Enable internal pull-up resistor on pin D0 (RX), in order
to supress line noise that prevents the bootloader from
timing out (DAM: 20070509) */
DDRD &= ~_BV(PIND0);
PORTD |= _BV(PIND0);
/* set LED pin as output */
LED_DDR |= _BV(LED);
/* flash onboard LED to signal entering of bootloader */
/* ADABOOT will do two series of flashes. first 4 - signifying ADABOOT */
/* then a pause and another flash series signifying ADABOOT sub-version */
flash_led(NUM_LED_FLASHES);
#ifdef ADABOOT
flash_led(ADABOOT_VER); // BBR 9/13/2008
#endif
/* forever loop */
for (;;)
{
/* get character from UART */
ch = getch();
/* A bunch of if...else if... gives smaller code than switch...case ! */
/* Hello is anyone home ? */
if(ch=='0')
nothing_response();
/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else if(ch=='1')
{
if (getch() == ' ')
{
putch(0x14);
putch('A');
putch('V');
putch('R');
putch(' ');
putch('I');
putch('S');
putch('P');
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else if(ch=='@')
{
ch2 = getch();
if (ch2 > 0x85)
getch();
nothing_response();
}
/* AVR ISP/STK500 board requests */
else if(ch=='A')
{
ch2 = getch();
if(ch2 == 0x80)
byte_response(HW_VER); // Hardware version
else if(ch2==0x81)
byte_response(SW_MAJOR); // Software major version
else if(ch2==0x82)
byte_response(SW_MINOR); // Software minor version
else if(ch2==0x98)
byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
else
byte_response(0x00); // Covers various unnecessary responses we don't care about
}
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
else if(ch=='B')
{
getNch(20);
nothing_response();
}
/* Parallel programming stuff DON'T CARE */
else if(ch=='E')
{
getNch(5);
nothing_response();
}
/* Enter programming mode */
else if(ch=='P')
{
nothing_response();
}
/* Leave programming mode */
else if(ch=='Q')
{
nothing_response();
#ifdef ADABOOT
// autoreset via watchdog (sneaky!) BBR/LF 9/13/2008
WDTCSR = _BV(WDE);
while (1); // 16 ms
#endif
}
/* Erase device, don't care as we will erase one page at a time anyway. */
else if(ch=='R')
{
nothing_response();
}
/* Set address, little endian. EEPROM in bytes, FLASH in words */
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
/* This might explain why little endian was used here, big endian used everywhere else. */
else if(ch=='U')
{
address.byte[0] = getch();
address.byte[1] = getch();
nothing_response();
}
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
else if(ch=='V')
{
getNch(4);
byte_response(0x00);
}
/* Write memory, length is big endian and is in bytes */
else if(ch=='d')
{
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E')
flags.eeprom = 1;
for (i=0; i<PAGE_SIZE; i++)
buff[i] = 0;
for (w = 0; w < length.word; w++)
{
// Store data in buffer, can't keep up with serial data stream whilst programming pages
buff[w] = getch();
}
if (getch() == ' ')
{
if (flags.eeprom)
{
//Write to EEPROM one byte at a time
for(w=0;w<length.word;w++)
{
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EEDR = buff[w];
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
address.word++;
}
}
else
{
//address * 2 -> byte location
address.word = address.word << 1;
//Even up an odd number of bytes
if ((length.byte[0] & 0x01))
length.word++;
// HACKME: EEPE used to be EEWE
//Wait for previous EEPROM writes to complete
//while(bit_is_set(EECR,EEPE));
while(EECR & (1<<EEPE));
asm volatile(
"clr r17 \n\t" //page_word_count
"lds r30,address \n\t" //Address of FLASH location (in bytes)
"lds r31,address+1 \n\t"
"ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
"ldi r29,hi8(buff) \n\t"
"lds r24,length \n\t" //Length of data to be written (in bytes)
"lds r25,length+1 \n\t"
"length_loop: \n\t" //Main loop, repeat for number of words in block
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
"brne no_page_erase \n\t"
"wait_spm1: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm1 \n\t"
"ldi r16,0x03 \n\t" //Erase page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"wait_spm2: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm2 \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"no_page_erase: \n\t"
"ld r0,Y+ \n\t" //Write 2 bytes into page buffer
"ld r1,Y+ \n\t"
"wait_spm3: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm3 \n\t"
"ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
"sts %0,r16 \n\t"
"spm \n\t"
"inc r17 \n\t" //page_word_count++
"cpi r17,%1 \n\t"
"brlo same_page \n\t" //Still same page in FLASH
"write_page: \n\t"
"clr r17 \n\t" //New page, write current one first
"wait_spm4: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm4 \n\t"
"ldi r16,0x05 \n\t" //Write page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"wait_spm5: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm5 \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"same_page: \n\t"
"adiw r30,2 \n\t" //Next word in FLASH
"sbiw r24,2 \n\t" //length-2
"breq final_write \n\t" //Finished
"rjmp length_loop \n\t"
"final_write: \n\t"
"cpi r17,0 \n\t"
"breq block_done \n\t"
"adiw r24,2 \n\t" //length+2, fool above check on length after short page write
"rjmp write_page \n\t"
"block_done: \n\t"
"clr __zero_reg__ \n\t" //restore zero register
: "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"
);
}
putch(0x14);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* Read memory block mode, length is big endian. */
else if(ch=='t')
{
length.byte[1] = getch();
length.byte[0] = getch();
if (getch() == 'E')
flags.eeprom = 1;
else
{
flags.eeprom = 0;
address.word = address.word << 1; // address * 2 -> byte location
}
// Command terminator
if (getch() == ' ')
{
putch(0x14);
for (w=0; w<length.word; w++)
{
// Can handle odd and even lengths okay
if (flags.eeprom)
{
// Byte access EEPROM read
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EECR |= (1<<EERE);
putch(EEDR);
address.word++;
}
else
{
if (!flags.rampz)
putch(pgm_read_byte_near(address.word));
address.word++;
}
}
putch(0x10);
}
}
/* Get device signature bytes */
else if(ch=='u')
{
if (getch() == ' ')
{
putch(0x14);
putch(SIG1);
putch(SIG2);
putch(SIG3);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* Read oscillator calibration byte */
else if(ch=='v')
byte_response(0x00);
else if (++error_count == MAX_ERROR_COUNT)
app_start();
}
/* end of forever loop */
}
char gethex(void)
{
char ah,al;
ah = getch();
putch(ah);
al = getch();
putch(al);
if(ah >= 'a')
ah = ah - 'a' + 0x0a;
else if(ah >= '0')
ah -= '0';
if(al >= 'a')
al = al - 'a' + 0x0a;
else if(al >= '0')
al -= '0';
return (ah << 4) + al;
}
void puthex(char ch)
{
char ah,al;
ah = (ch & 0xf0) >> 4;
if(ah >= 0x0a)
ah = ah - 0x0a + 'a';
else
ah += '0';
al = (ch & 0x0f);
if(al >= 0x0a)
al = al - 0x0a + 'a';
else
al += '0';
putch(ah);
putch(al);
}
void putch(char ch)
{
while (!(UCSR0A & _BV(UDRE0)));
UDR0 = ch;
}
char getch(void)
{
uint32_t count = 0;
#ifdef ADABOOT
LED_PORT &= ~_BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
#endif
while(!(UCSR0A & _BV(RXC0)))
{
/* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/
/* HACKME:: here is a good place to count times*/
count++;
if (count > MAX_TIME_COUNT)
app_start();
}
#ifdef ADABOOT
LED_PORT |= _BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
#endif
return UDR0;
}
void getNch(uint8_t count)
{
uint8_t i;
for(i=0;i<count;i++)
{
while(!(UCSR0A & _BV(RXC0)));
UDR0;
}
}
void byte_response(uint8_t val)
{
if (getch() == ' ')
{
putch(0x14);
putch(val);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
void nothing_response(void)
{
if (getch() == ' ')
{
putch(0x14);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
#ifdef ADABOOT
void flash_led(uint8_t count)
{
/* flash onboard LED count times to signal entering of bootloader */
/* l needs to be volatile or the delay loops below might get */
/* optimized away if compiling with optimizations (DAM). */
volatile uint32_t l;
if (count == 0) {
count = ADABOOT;
}
int8_t i;
for (i = 0; i < count; ++i) {
LED_PORT |= _BV(LED); // LED on
for(l = 0; l < (F_CPU / 1000); ++l); // delay NGvalue was 1000 for both loops - BBR
LED_PORT &= ~_BV(LED); // LED off
for(l = 0; l < (F_CPU / 250); ++l); // delay asymmteric for ADA BOOT BBR
}
for(l = 0; l < (F_CPU / 100); ++l); // pause ADA BOOT BBR
}
#else
void flash_led(uint8_t count)
{
/* flash onboard LED three times to signal entering of bootloader */
/* l needs to be volatile or the delay loops below might get
optimized away if compiling with optimizations (DAM). */
volatile uint32_t l;
if (count == 0) {
count = 3;
}
int8_t i;
for (i = 0; i < count; ++i) {
LED_PORT |= _BV(LED);
for(l = 0; l < (F_CPU / 1000); ++l);
LED_PORT &= ~_BV(LED);
for(l = 0; l < (F_CPU / 1000); ++l);
}
}
#endif
/* end of file ATmegaBOOT.c */

@ -0,0 +1,121 @@
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
:10F88000CFEFD8E0DEBFCDBF11E0A0E0B1E0E6E60B
:10F89000FFEF02C005900D92A030B107D9F712E03A
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
:10F8D00009F481E020E0482F55274115510509F42E
:10F8E0003DC0289A19821A821B821C820BC0898112
:10F8F0009A81AB81BC810196A11DB11D89839A8338
:10F90000AB83BC8389819A81AB81BC8180589E4343
:10F91000A040B04060F3289819821A821B821C8292
:10F920000BC089819A81AB81BC810196A11DB11D5B
:10F9300089839A83AB83BC8389819A81AB81BC81A3
:10F9400080509A4FA040B04060F32F5F822F9927DC
:10F9500087FD9095841795070CF4C3CF19821A82FE
:10F960001B821C8289819A81AB81BC818050914726
:10F97000A240B040A0F489819A81AB81BC810196FC
:10F98000A11DB11D89839A83AB83BC8389819A8130
:10F99000AB81BC8180509147A240B04060F3249677
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
:10F9B000EF92FF920F931F93EE24FF248701289864
:10F9C0008091C00087FD17C00894E11CF11C011D47
:10F9D000111D81E0E81689E0F8068DE3080780E054
:10F9E000180770F3E0910001F091010109958091F1
:10F9F000C00087FFE9CF289A8091C600992787FD2C
:10FA000090951F910F91FF90EF900895982F8091FE
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
:10FA2000803271F0809102018F5F809302018530F6
:10FA300009F00895E0910001F09101010995089500
:10FA400084E10E94067D80E10E94067D0895CF93A7
:10FA5000C82F0E94D87C803241F0809102018F5FD4
:10FA600080930201853081F40AC084E10E94067D02
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
:10FA80000001F09101010995CF910895282F90E090
:10FA900007C08091C0008823E4F78091C6009F5F73
:10FAA0009217B8F30895CFEFD8E0DEBFCDBF0000C6
:10FAB00094B714BE809160008861809360001092BA
:10FAC000600091FF74C189E18093C4001092C50069
:10FAD00088E18093C10086E08093C2005098589AD4
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
:10FAF000D87C8033B9F18133C1F1803409F456C028
:10FB0000813409F45CC0823409F46EC0853409F490
:10FB100071C0803539F1813509F4F3C0823511F1B6
:10FB2000853509F4D3C0863509F4CBC0843609F491
:10FB300065C0843709F4EBC0853709F4D2C0863735
:10FB400009F44AC0809102018F5F809302018530E1
:10FB500071F6E0910001F091010109950E94D87CB5
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
:10FB7000803241F784E10E94067D81E40E94067D87
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
:10FB9000067D89E40E94067D83E50E94067D80E55E
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
:10FBC000D87C803809F407C1813809F400C1823833
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
:10FC0000809306020E94D87C8093050280910802AE
:10FC10008E7F809308020E94D87C853409F44BC003
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
:10FC3000C0E0D0E0809105029091060218161906E6
:10FC400078F405E011E00E94D87CF80181938F01DF
:10FC500021968091050290910602C817D90798F362
:10FC60000E94D87C803209F06DCF8091080280FF1D
:10FC7000B6C0C0E0D0E02091050230910602121615
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
:10FCA00031962196C217D30798F3F0930401E0939D
:10FCB000030184E175CF809108028160809308027E
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
:10FCD000809303010E94D87C809304010E940E7DD2
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
:10FCF000067D8EE10E94067D85E90E94067D88E0F2
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
:10FD1000D87C809306020E94D87C809305020E94C2
:10FD2000D87C853409F449C0809108028E7F809385
:10FD300008028091030190910401880F991F90930C
:10FD40000401809303010E94D87C803209F0CFCE59
:10FD500084E10E94067DC0E0D0E020910502309150
:10FD600006021216130608F01DCFE0910301F09170
:10FD700004018091080280FF96C0F999FECFF2BD80
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
:10FD900004013196F0930401E093030120910502E0
:10FDA000309106022196C217D30718F3FBCEE091DB
:10FDB0000001F0910101099586CE809108028160D1
:10FDC00080930802C0CF80E10E94277D90CE81E021
:10FDD0000E94277D8CCE82E00E94277D88CE809174
:10FDE000030190910401880F991F9093040180935F
:10FDF00003018091050280FF09C080910502909166
:10FE0000060201969093060280930502F999FECFAF
:10FE10001127E0910301F0910401C5E0D1E0809148
:10FE2000050290910602103091F400915700017084
:10FE30000130D9F303E000935700E8950091570093
:10FE400001700130D9F301E100935700E895099062
:10FE500019900091570001700130D9F301E000932F
:10FE60005700E8951395103898F011270091570026
:10FE700001700130D9F305E000935700E895009137
:10FE8000570001700130D9F301E100935700E89564
:10FE90003296029709F0C7CF103011F00296E5CFE5
:10FEA000112484E17DCE869580FF06C03196F093C3
:10FEB0000401E093030176CF84910E94067D209196
:10FEC000050230910602E0910301F0910401EECFAA
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
:10FF000010330CF01053C295C07FC10F8C2F99276E
:10FF100087FD9095CF911F910895CF93282F992712
:10FF200087FD9095807F907095958795959587959D
:10FF300095958795959587958A303CF0895AC22F7B
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
:06FF6000CF910895FFCFD0
:040000030000F80001
:00000001FF

@ -0,0 +1,120 @@
:10F800000C94387C0C94557C0C94557C0C94557C51
:10F810000C94557C0C94557C0C94557C0C94557C24
:10F820000C94557C0C94557C0C94557C0C94557C14
:10F830000C94557C0C94557C0C94557C0C94557C04
:10F840000C94557C0C94557C0C94557C0C94557CF4
:10F850000C94557C0C94557C0C94557C0C94557CE4
:10F860000C94557C0C94557C0C94557C0C94557CD4
:10F8700011241FBECFEFD0E1DEBFCDBF11E0A0E06D
:10F88000B1E0EAE5FFEF02C005900D92A030B107AC
:10F89000D9F712E0A0E0B1E001C01D92A930B10794
:10F8A000E1F70E944D7D0C94AC7F0C94007CCF93CB
:10F8B000DF93CDB7DEB724970FB6F894DEBF0FBE47
:10F8C000CDBF882309F481E020E0482F552741155A
:10F8D000510509F43DC0289A19821A821B821C82A4
:10F8E0000BC089819A81AB81BC810196A11DB11D9C
:10F8F00089839A83AB83BC8389819A81AB81BC81E4
:10F9000080589E43A040B04060F3289819821A8224
:10F910001B821C820BC089819A81AB81BC810196BC
:10F92000A11DB11D89839A83AB83BC8389819A8190
:10F93000AB81BC8180509A4FA040B04060F32F5FF4
:10F94000822F992787FD9095841795070CF4C3CFD4
:10F9500019821A821B821C8289819A81AB81BC81A7
:10F9600080509147A240B040A0F489819A81AB8138
:10F97000BC810196A11DB11D89839A83AB83BC8391
:10F9800089819A81AB81BC8180509147A240B0406F
:10F9900060F324960FB6F894DEBF0FBECDBFDF91A3
:10F9A000CF910895EF92FF920F931F93EE24FF24BF
:10F9B000870128988091C00087FD17C00894E11C3A
:10F9C000F11C011D111D81E0E81689E0F8068DE3A8
:10F9D000080780E0180770F3E0910001F091010141
:10F9E00009958091C00087FFE9CF289A8091C600D1
:10F9F000992787FD90951F910F91FF90EF900895A3
:10FA0000982F8091C00085FFFCCF9093C600089589
:10FA10000E94D27C803271F0809102018F5F8093CE
:10FA20000201853009F00895E0910001F091010193
:10FA30000995089584E10E94007D80E10E94007D87
:10FA40000895CF93C82F0E94D27C803241F08091DC
:10FA500002018F5F80930201853081F40AC084E146
:10FA60000E94007D8C2F0E94007D80E10E94007D1D
:10FA700005C0E0910001F09101010995CF91089531
:10FA8000282F90E007C08091C0008823E4F7809180
:10FA9000C6009F5F9217B8F30895CFEFD0E1DEBFA5
:10FAA000CDBF000094B714BE809160008861809340
:10FAB00060001092600091FF74C189E18093C400DE
:10FAC0001092C50088E18093C10086E08093C20057
:10FAD0005098589A209A83E00E94577C81E00E94B7
:10FAE000577C0E94D27C8033B9F18133C1F18034DC
:10FAF00009F456C0813409F45CC0823409F46EC044
:10FB0000853409F471C0803539F1813509F4F3C0C9
:10FB1000823511F1853509F4D3C0863509F4CBC09F
:10FB2000843609F465C0843709F4EBC0853709F4DD
:10FB3000D2C0863709F44AC0809102018F5F80935A
:10FB40000201853071F6E0910001F0910101099503
:10FB50000E94D27C803349F60E94087DC2CF0E9469
:10FB6000D27CC82F803241F784E10E94007D81E47D
:10FB70000E94007D86E50E94007D82E50E94007D56
:10FB80008C2F0E94007D89E40E94007D83E50E9405
:10FB9000007D80E50E94007D80E10E94007DA1CF74
:10FBA0000E94D27C8638C0F20E94D27C0E94087DDE
:10FBB00098CF0E94D27C803809F407C1813809F4BB
:10FBC00000C1823809F4F9C0883921F080E00E9430
:10FBD000217D87CF83E00E94217D83CF84E10E9435
:10FBE000407D0E94087D7DCF85E00E94407DF9CF59
:10FBF0000E94D27C809306020E94D27C80930502F0
:10FC0000809108028E7F809308020E94D27C853406
:10FC100009F44BC0E5E0F1E0119281E0E438F80727
:10FC2000D9F3D0F3C0E0D0E08091050290910602B4
:10FC30001816190678F405E011E00E94D27CF8014C
:10FC400081938F0121968091050290910602C81739
:10FC5000D90798F30E94D27C803209F06DCF809151
:10FC6000080280FFB6C0C0E0D0E0209105023091CC
:10FC7000060212161306B8F4E0910301F091040194
:10FC8000A5E0B1E0F999FECFF2BDE1BD8D9180BD57
:10FC9000FA9AF99A31962196C217D30798F3F093FE
:10FCA0000401E093030184E175CF80910802816033
:10FCB00080930802AFCF84E00E94407D80E087CF30
:10FCC0000E94D27C809303010E94D27C8093040125
:10FCD0000E94087D06CF0E94D27C803209F02CCF92
:10FCE00084E10E94007D8EE10E94007D86E90E94F1
:10FCF000007D89E04FCF0E94087D88E080936000FE
:10FD0000FFCF0E94D27C809306020E94D27C809317
:10FD100005020E94D27C853409F449C08091080212
:10FD20008E7F809308028091030190910401880FD7
:10FD3000991F90930401809303010E94D27C80322A
:10FD400009F0CFCE84E10E94007DC0E0D0E0209198
:10FD50000502309106021216130608F01DCFE0913D
:10FD60000301F09104018091080280FF96C0F99987
:10FD7000FECFF2BDE1BDF89A80B50E94007DE09112
:10FD80000301F09104013196F0930401E093030123
:10FD900020910502309106022196C217D30718F36D
:10FDA000FBCEE0910001F0910101099586CE809192
:10FDB0000802816080930802C0CF80E10E94217D0B
:10FDC00090CE81E00E94217D8CCE82E00E94217D38
:10FDD00088CE8091030190910401880F991F909320
:10FDE0000401809303018091050280FF09C0809186
:10FDF00005029091060201969093060280930502F7
:10FE0000F999FECF1127E0910301F0910401C5E0BB
:10FE1000D1E08091050290910602103091F400919A
:10FE2000570001700130D9F303E000935700E895C3
:10FE30000091570001700130D9F301E100935700A0
:10FE4000E895099019900091570001700130D9F39D
:10FE500001E000935700E8951395103898F01127AA
:10FE60000091570001700130D9F305E0009357006D
:10FE7000E8950091570001700130D9F301E100933A
:10FE80005700E8953296029709F0C7CF103011F06D
:10FE90000296E5CF112484E17DCE869580FF06C0D1
:10FEA0003196F0930401E093030176CF84910E9490
:10FEB000007D2091050230910602E0910301F0914E
:10FEC0000401EECF1F93CF930E94D27CC82F0E94D3
:10FED000007D0E94D27C182F0E94007DC1362CF03C
:10FEE000C75511363CF0175508C0C033D4F3C05382
:10FEF0001136CCF710330CF01053C295C07FC10FF0
:10FF00008C2F992787FD9095CF911F910895CF93BE
:10FF1000282F992787FD9095807F907095958795DC
:10FF20009595879595958795959587958A303CF019
:10FF3000895AC22FCF70CA303CF0C95A06C0805DC2
:10FF4000C22FCF70CA30CCF7C05D0E94007D8C2FCD
:0AFF50000E94007DCF910895FFCFBD
:040000030000F80001
:00000001FF

@ -0,0 +1,121 @@
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
:10F88000CFEFD0E1DEBFCDBF11E0A0E0B1E0E6E612
:10F89000FFEF02C005900D92A030B107D9F712E03A
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
:10F8D00009F481E020E0482F55274115510509F42E
:10F8E0003DC0289A19821A821B821C820BC0898112
:10F8F0009A81AB81BC810196A11DB11D89839A8338
:10F90000AB83BC8389819A81AB81BC8180589E4343
:10F91000A040B04060F3289819821A821B821C8292
:10F920000BC089819A81AB81BC810196A11DB11D5B
:10F9300089839A83AB83BC8389819A81AB81BC81A3
:10F9400080509A4FA040B04060F32F5F822F9927DC
:10F9500087FD9095841795070CF4C3CF19821A82FE
:10F960001B821C8289819A81AB81BC818050914726
:10F97000A240B040A0F489819A81AB81BC810196FC
:10F98000A11DB11D89839A83AB83BC8389819A8130
:10F99000AB81BC8180509147A240B04060F3249677
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
:10F9B000EF92FF920F931F93EE24FF248701289864
:10F9C0008091C00087FD17C00894E11CF11C011D47
:10F9D000111D81E0E81689E0F8068DE3080780E054
:10F9E000180770F3E0910001F091010109958091F1
:10F9F000C00087FFE9CF289A8091C600992787FD2C
:10FA000090951F910F91FF90EF900895982F8091FE
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
:10FA2000803271F0809102018F5F809302018530F6
:10FA300009F00895E0910001F09101010995089500
:10FA400084E10E94067D80E10E94067D0895CF93A7
:10FA5000C82F0E94D87C803241F0809102018F5FD4
:10FA600080930201853081F40AC084E10E94067D02
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
:10FA80000001F09101010995CF910895282F90E090
:10FA900007C08091C0008823E4F78091C6009F5F73
:10FAA0009217B8F30895CFEFD0E1DEBFCDBF0000CD
:10FAB00094B714BE809160008861809360001092BA
:10FAC000600091FF74C189E18093C4001092C50069
:10FAD00088E18093C10086E08093C2005098589AD4
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
:10FAF000D87C8033B9F18133C1F1803409F456C028
:10FB0000813409F45CC0823409F46EC0853409F490
:10FB100071C0803539F1813509F4F3C0823511F1B6
:10FB2000853509F4D3C0863509F4CBC0843609F491
:10FB300065C0843709F4EBC0853709F4D2C0863735
:10FB400009F44AC0809102018F5F809302018530E1
:10FB500071F6E0910001F091010109950E94D87CB5
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
:10FB7000803241F784E10E94067D81E40E94067D87
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
:10FB9000067D89E40E94067D83E50E94067D80E55E
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
:10FBC000D87C803809F407C1813809F400C1823833
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
:10FC0000809306020E94D87C8093050280910802AE
:10FC10008E7F809308020E94D87C853409F44BC003
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
:10FC3000C0E0D0E0809105029091060218161906E6
:10FC400078F405E011E00E94D87CF80181938F01DF
:10FC500021968091050290910602C817D90798F362
:10FC60000E94D87C803209F06DCF8091080280FF1D
:10FC7000B6C0C0E0D0E02091050230910602121615
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
:10FCA00031962196C217D30798F3F0930401E0939D
:10FCB000030184E175CF809108028160809308027E
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
:10FCD000809303010E94D87C809304010E940E7DD2
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
:10FCF000067D8EE10E94067D86E90E94067D8AE0EF
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
:10FD1000D87C809306020E94D87C809305020E94C2
:10FD2000D87C853409F449C0809108028E7F809385
:10FD300008028091030190910401880F991F90930C
:10FD40000401809303010E94D87C803209F0CFCE59
:10FD500084E10E94067DC0E0D0E020910502309150
:10FD600006021216130608F01DCFE0910301F09170
:10FD700004018091080280FF96C0F999FECFF2BD80
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
:10FD900004013196F0930401E093030120910502E0
:10FDA000309106022196C217D30718F3FBCEE091DB
:10FDB0000001F0910101099586CE809108028160D1
:10FDC00080930802C0CF80E10E94277D90CE81E021
:10FDD0000E94277D8CCE82E00E94277D88CE809174
:10FDE000030190910401880F991F9093040180935F
:10FDF00003018091050280FF09C080910502909166
:10FE0000060201969093060280930502F999FECFAF
:10FE10001127E0910301F0910401C5E0D1E0809148
:10FE2000050290910602103091F400915700017084
:10FE30000130D9F303E000935700E8950091570093
:10FE400001700130D9F301E100935700E895099062
:10FE500019900091570001700130D9F301E000932F
:10FE60005700E8951395103898F011270091570026
:10FE700001700130D9F305E000935700E895009137
:10FE8000570001700130D9F301E100935700E89564
:10FE90003296029709F0C7CF103011F00296E5CFE5
:10FEA000112484E17DCE869580FF06C03196F093C3
:10FEB0000401E093030176CF84910E94067D209196
:10FEC000050230910602E0910301F0910401EECFAA
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
:10FF000010330CF01053C295C07FC10F8C2F99276E
:10FF100087FD9095CF911F910895CF93282F992712
:10FF200087FD9095807F907095958795959587959D
:10FF300095958795959587958A303CF0895AC22F7B
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
:06FF6000CF910895FFCFD0
:040000030000F80001
:00000001FF

@ -0,0 +1,56 @@
# Makefile for ATmegaBOOT
# E.Lins, 18.7.2005
# $Id$
# program name should not be changed...
PROGRAM = ATmegaBOOT_644P
# enter the target CPU frequency
AVR_FREQ = 16000000L
MCU_TARGET = atmega644p
LDSECTION = --section-start=.text=0xF800
OBJ = $(PROGRAM).o
OPTIMIZE = -O2
DEFS =
LIBS =
CC = avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
override LDFLAGS = -Wl,$(LDSECTION)
#override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: CFLAGS += '-DMAX_TIME_COUNT=8000000L>>1' -DADABOOT
all: $(PROGRAM).hex
$(PROGRAM).hex: $(PROGRAM).elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
$(OBJ): ATmegaBOOT.c
avr-gcc $(CFLAGS) $(LDFLAGS) -c -g -O2 -Wall -mmcu=$(MCU_TARGET) ATmegaBOOT.c -o $(PROGRAM).o
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@
clean:
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex

@ -0,0 +1,3 @@
Note: This bootloader support ATmega644, ATmega644P and ATmega324P.
To build, set PROGRAM and MCU_TARGET in the Makefile according to your target device.

@ -0,0 +1,135 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#ifndef Wiring_h
#define Wiring_h
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,202 @@
/*
HardwareSerial.cpp - Hardware serial library for 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
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "wiring.h"
#include "wiring_private.h"
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
#include "HardwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
struct ring_buffer
{
unsigned char buffer[RX_BUFFER_SIZE];
int head;
int tail;
};
ring_buffer rx_buffer = { { 0 }, 0, 0 };
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
int i = (unsigned int)(rx_buffer->head + 1) & (RX_BUFFER_SIZE -1);
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer->tail) {
rx_buffer->buffer[rx_buffer->head] = c;
rx_buffer->head = i;
}
}
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL(USART0_RX_vect)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
// Constructors ////////////////////////////////////////////////////////////////
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
{
_rx_buffer = rx_buffer;
_ubrrh = ubrrh;
_ubrrl = ubrrl;
_ucsra = ucsra;
_ucsrb = ucsrb;
_udr = udr;
_rxen = rxen;
_txen = txen;
_rxcie = rxcie;
_udre = udre;
_u2x = u2x;
}
// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long baud)
{
uint16_t baud_setting;
bool use_u2x = true;
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600) {
use_u2x = false;
}
#endif
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
}
void HardwareSerial::end()
{
cbi(*_ucsrb, _rxen);
cbi(*_ucsrb, _txen);
cbi(*_ucsrb, _rxcie);
}
int HardwareSerial::available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) & (RX_BUFFER_SIZE-1);
}
int HardwareSerial::peek(void)
{
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
return _rx_buffer->buffer[_rx_buffer->tail];
}
}
int HardwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) & (RX_BUFFER_SIZE-1);
return c;
}
}
void HardwareSerial::flush()
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
_rx_buffer->head = _rx_buffer->tail;
}
//
// Drakelive 2012-09-04
//
#if ARDUINO >= 100
size_t HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;
*_udr = c;
}
#else
void HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;
*_udr = c;
}
#endif
// Drakelive 2012-09-04
// Preinstantiate Objects //////////////////////////////////////////////////////
HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#endif // whole file

@ -0,0 +1,87 @@
/*
HardwareSerial.h - Hardware serial library for 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
Modified 28 September 2010 by Mark Sproul
*/
#ifndef HardwareSerial_h
#define HardwareSerial_h
#include <inttypes.h>
#include "Stream.h"
struct ring_buffer;
class HardwareSerial : public Stream
{
private:
ring_buffer *_rx_buffer;
volatile uint8_t *_ubrrh;
volatile uint8_t *_ubrrl;
volatile uint8_t *_ucsra;
volatile uint8_t *_ucsrb;
volatile uint8_t *_udr;
uint8_t _rxen;
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udre;
uint8_t _u2x;
public:
HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
void begin(long);
void end();
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
//
// Drakelive 2012-09-04
//
#if ARDUINO >= 100
virtual size_t write(uint8_t);
#else
virtual void write(uint8_t);
#endif
// Drakelive 2012-09-04
using Print::write; // pull in write(str) and write(buf, size) from Print
};
#if defined(UBRRH) || defined(UBRR0H)
extern HardwareSerial Serial;
#elif defined(USBCON)
#include "usb_api.h"
#endif
#if defined(UBRR1H)
extern HardwareSerial Serial1;
#endif
#if defined(UBRR2H)
extern HardwareSerial Serial2;
#endif
#if defined(UBRR3H)
extern HardwareSerial Serial3;
#endif
#endif

@ -0,0 +1,220 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "wiring.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
/* default implementation: may be overridden */
void Print::write(const char *str)
{
while (*str)
write(*str++);
}
/* default implementation: may be overridden */
void Print::write(const uint8_t *buffer, size_t size)
{
while (size--)
write(*buffer++);
}
void Print::print(const String &s)
{
for (int i = 0; i < s.length(); i++) {
write(s[i]);
}
}
void Print::print(const char str[])
{
write(str);
}
void Print::print(char c, int base)
{
print((long) c, base);
}
void Print::print(unsigned char b, int base)
{
print((unsigned long) b, base);
}
void Print::print(int n, int base)
{
print((long) n, base);
}
void Print::print(unsigned int n, int base)
{
print((unsigned long) n, base);
}
void Print::print(long n, int base)
{
if (base == 0) {
write(n);
} else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
} else {
printNumber(n, base);
}
}
void Print::print(unsigned long n, int base)
{
if (base == 0) write(n);
else printNumber(n, base);
}
void Print::print(double n, int digits)
{
printFloat(n, digits);
}
void Print::println(void)
{
print('\r');
print('\n');
}
void Print::println(const String &s)
{
print(s);
println();
}
void Print::println(const char c[])
{
print(c);
println();
}
void Print::println(char c, int base)
{
print(c, base);
println();
}
void Print::println(unsigned char b, int base)
{
print(b, base);
println();
}
void Print::println(int n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned int n, int base)
{
print(n, base);
println();
}
void Print::println(long n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned long n, int base)
{
print(n, base);
println();
}
void Print::println(double n, int digits)
{
print(n, digits);
println();
}
// Private Methods /////////////////////////////////////////////////////////////
void Print::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
while (n > 0) {
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
print((char) (buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
void Print::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print(".");
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}

@ -0,0 +1,77 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Print_h
#define Print_h
#include <inttypes.h>
#include <stdio.h> // for size_t
#include "WString.h"
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0
class Print
{
private:
void printNumber(unsigned long, uint8_t);
void printFloat(double, uint8_t);
public:
//
// Drakelive 2012-09-04
//
#if ARDUINO >= 100
virtual size_t write(uint8_t) = 0;
#else
virtual void write(uint8_t) = 0;
#endif
// Drakelive 2012-09-04
virtual void write(const char *str);
virtual void write(const uint8_t *buffer, size_t size);
void print(const String &);
void print(const char[]);
void print(char, int = BYTE);
void print(unsigned char, int = BYTE);
void print(int, int = DEC);
void print(unsigned int, int = DEC);
void print(long, int = DEC);
void print(unsigned long, int = DEC);
void print(double, int = 2);
void println(const String &s);
void println(const char[]);
void println(char, int = BYTE);
void println(unsigned char, int = BYTE);
void println(int, int = DEC);
void println(unsigned int, int = DEC);
void println(long, int = DEC);
void println(unsigned long, int = DEC);
void println(double, int = 2);
void println(void);
};
#endif

@ -0,0 +1,35 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 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 Stream_h
#define Stream_h
#include <inttypes.h>
#include "Print.h"
class Stream : public Print
{
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
};
#endif

@ -0,0 +1,601 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
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
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
*************************************************/
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "wiring.h"
#include "pins_arduino.h"
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#endif
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
#if !defined(__AVR_ATmega8__)
volatile long timer0_toggle_count;
volatile uint8_t *timer0_pin_port;
volatile uint8_t timer0_pin_mask;
#endif
volatile long timer1_toggle_count;
volatile uint8_t *timer1_pin_port;
volatile uint8_t timer1_pin_mask;
volatile long timer2_toggle_count;
volatile uint8_t *timer2_pin_port;
volatile uint8_t timer2_pin_mask;
#if defined(TIMSK3)
volatile long timer3_toggle_count;
volatile uint8_t *timer3_pin_port;
volatile uint8_t timer3_pin_mask;
#endif
#if defined(TIMSK4)
volatile long timer4_toggle_count;
volatile uint8_t *timer4_pin_port;
volatile uint8_t timer4_pin_mask;
#endif
#if defined(TIMSK5)
volatile long timer5_toggle_count;
volatile uint8_t *timer5_pin_port;
volatile uint8_t timer5_pin_mask;
#endif
// MLS: This does not make sense, the 3 options are the same
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
#elif defined(__AVR_ATmega8__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
#else
#define AVAILABLE_TONE_PINS 1
// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
#endif
static int8_t toneBegin(uint8_t _pin)
{
int8_t _timer = -1;
// if we're already using the pin, the timer should be configured.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
return pgm_read_byte(tone_pin_to_timer_PGM + i);
}
}
// search for an unused timer.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == 255) {
tone_pins[i] = _pin;
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
break;
}
}
if (_timer != -1)
{
// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch (_timer)
{
#if defined(TCCR0A) && defined(TCCR0B)
case 0:
// 8 bit timer
TCCR0A = 0;
TCCR0B = 0;
bitWrite(TCCR0A, WGM01, 1);
bitWrite(TCCR0B, CS00, 1);
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer0_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
case 1:
// 16 bit timer
TCCR1A = 0;
TCCR1B = 0;
bitWrite(TCCR1B, WGM12, 1);
bitWrite(TCCR1B, CS10, 1);
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer1_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR2A) && defined(TCCR2B)
case 2:
// 8 bit timer
TCCR2A = 0;
TCCR2B = 0;
bitWrite(TCCR2A, WGM21, 1);
bitWrite(TCCR2B, CS20, 1);
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer2_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
case 3:
// 16 bit timer
TCCR3A = 0;
TCCR3B = 0;
bitWrite(TCCR3B, WGM32, 1);
bitWrite(TCCR3B, CS30, 1);
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer3_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
case 4:
// 16 bit timer
TCCR4A = 0;
TCCR4B = 0;
#if defined(WGM42)
bitWrite(TCCR4B, WGM42, 1);
#elif defined(CS43)
#warning this may not be correct
// atmega32u4
bitWrite(TCCR4B, CS43, 1);
#endif
bitWrite(TCCR4B, CS40, 1);
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer4_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
case 5:
// 16 bit timer
TCCR5A = 0;
TCCR5B = 0;
bitWrite(TCCR5B, WGM52, 1);
bitWrite(TCCR5B, CS50, 1);
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer5_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
}
}
return _timer;
}
// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
uint8_t prescalarbits = 0b001;
long toggle_count = 0;
uint32_t ocr = 0;
int8_t _timer;
_timer = toneBegin(_pin);
if (_timer >= 0)
{
// Set the pinMode as OUTPUT
pinMode(_pin, OUTPUT);
// if we are using an 8 bit timer, scan through prescalars to find the best fit
if (_timer == 0 || _timer == 2)
{
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001; // ck/1: same for both timers
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 8 - 1;
prescalarbits = 0b010; // ck/8: same for both timers
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 32 - 1;
prescalarbits = 0b011;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = _timer == 0 ? 0b011 : 0b100;
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 128 - 1;
prescalarbits = 0b101;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 256 - 1;
prescalarbits = _timer == 0 ? 0b100 : 0b110;
if (ocr > 255)
{
// can't do any better than /1024
ocr = F_CPU / frequency / 2 / 1024 - 1;
prescalarbits = _timer == 0 ? 0b101 : 0b111;
}
}
}
}
#if defined(TCCR0B)
if (_timer == 0)
{
TCCR0B = prescalarbits;
}
else
#endif
#if defined(TCCR2B)
{
TCCR2B = prescalarbits;
}
#else
{
// dummy place holder to make the above ifdefs work
}
#endif
}
else
{
// two choices for the 16 bit timers: ck/1 or ck/64
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001;
if (ocr > 0xffff)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = 0b011;
}
if (_timer == 1)
{
#if defined(TCCR1B)
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
#endif
}
#if defined(TCCR3B)
else if (_timer == 3)
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR4B)
else if (_timer == 4)
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR5B)
else if (_timer == 5)
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
#endif
}
// Calculate the toggle count
if (duration > 0)
{
toggle_count = 2 * frequency * duration / 1000;
}
else
{
toggle_count = -1;
}
// Set the OCR for the given timer,
// set the toggle count,
// then turn on the interrupts
switch (_timer)
{
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
case 0:
OCR0A = ocr;
timer0_toggle_count = toggle_count;
bitWrite(TIMSK0, OCIE0A, 1);
break;
#endif
case 1:
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK1, OCIE1A, 1);
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
// this combination is for at least the ATmega32
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK, OCIE1A, 1);
#endif
break;
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
case 2:
OCR2A = ocr;
timer2_toggle_count = toggle_count;
bitWrite(TIMSK2, OCIE2A, 1);
break;
#endif
#if defined(TIMSK3)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
bitWrite(TIMSK3, OCIE3A, 1);
break;
#endif
#if defined(TIMSK4)
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
bitWrite(TIMSK4, OCIE4A, 1);
break;
#endif
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
case 5:
OCR5A = ocr;
timer5_toggle_count = toggle_count;
bitWrite(TIMSK5, OCIE5A, 1);
break;
#endif
}
}
}
// XXX: this function only works properly for timer 2 (the only one we use
// currently). for the others, it should end the tone, but won't restore
// proper PWM functionality for the timer.
void disableTimer(uint8_t _timer)
{
switch (_timer)
{
case 0:
#if defined(TIMSK0)
TIMSK0 = 0;
#elif defined(TIMSK)
TIMSK = 0; // atmega32
#endif
break;
#if defined(TIMSK1) && defined(OCIE1A)
case 1:
bitWrite(TIMSK1, OCIE1A, 0);
break;
#endif
case 2:
#if defined(TIMSK2) && defined(OCIE2A)
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
#endif
#if defined(TCCR2A) && defined(WGM20)
TCCR2A = (1 << WGM20);
#endif
#if defined(TCCR2B) && defined(CS22)
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
#endif
#if defined(OCR2A)
OCR2A = 0;
#endif
break;
#if defined(TIMSK3)
case 3:
TIMSK3 = 0;
break;
#endif
#if defined(TIMSK4)
case 4:
TIMSK4 = 0;
break;
#endif
#if defined(TIMSK5)
case 5:
TIMSK5 = 0;
break;
#endif
}
}
void noTone(uint8_t _pin)
{
int8_t _timer = -1;
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
tone_pins[i] = 255;
}
}
disableTimer(_timer);
digitalWrite(_pin, 0);
}
#if 0
#if !defined(__AVR_ATmega8__)
ISR(TIMER0_COMPA_vect)
{
if (timer0_toggle_count != 0)
{
// toggle the pin
*timer0_pin_port ^= timer0_pin_mask;
if (timer0_toggle_count > 0)
timer0_toggle_count--;
}
else
{
disableTimer(0);
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER1_COMPA_vect)
{
if (timer1_toggle_count != 0)
{
// toggle the pin
*timer1_pin_port ^= timer1_pin_mask;
if (timer1_toggle_count > 0)
timer1_toggle_count--;
}
else
{
disableTimer(1);
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER2_COMPA_vect)
{
if (timer2_toggle_count != 0)
{
// toggle the pin
*timer2_pin_port ^= timer2_pin_mask;
if (timer2_toggle_count > 0)
timer2_toggle_count--;
}
else
{
// need to call noTone() so that the tone_pins[] entry is reset, so the
// timer gets initialized next time we call tone().
// XXX: this assumes timer 2 is always the first one used.
noTone(tone_pins[0]);
// disableTimer(2);
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
}
}
//#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#if 0
ISR(TIMER3_COMPA_vect)
{
if (timer3_toggle_count != 0)
{
// toggle the pin
*timer3_pin_port ^= timer3_pin_mask;
if (timer3_toggle_count > 0)
timer3_toggle_count--;
}
else
{
disableTimer(3);
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
}
}
ISR(TIMER4_COMPA_vect)
{
if (timer4_toggle_count != 0)
{
// toggle the pin
*timer4_pin_port ^= timer4_pin_mask;
if (timer4_toggle_count > 0)
timer4_toggle_count--;
}
else
{
disableTimer(4);
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
}
}
ISR(TIMER5_COMPA_vect)
{
if (timer5_toggle_count != 0)
{
// toggle the pin
*timer5_pin_port ^= timer5_pin_mask;
if (timer5_toggle_count > 0)
timer5_toggle_count--;
}
else
{
disableTimer(5);
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
}
}
#endif

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. 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 Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

@ -0,0 +1,249 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 1 August 2010 by Mark Sproul
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "WConstants.h"
#include "wiring_private.h"
volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
intFunc[interruptNum] = userFunc;
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch (interruptNum) {
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
case 3:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 4:
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 5:
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 0:
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 1:
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
EIMSK |= (1 << INT5);
break;
case 6:
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
EIMSK |= (1 << INT6);
break;
case 7:
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
EIMSK |= (1 << INT7);
break;
#else
case 0:
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GICR |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GIMSK |= (1 << INT0);
#else
#error attachInterrupt not finished for this CPU (case 0)
#endif
break;
case 1:
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GICR |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GIMSK |= (1 << INT1);
#else
#warning attachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum) {
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EIMSK &= ~(1 << INT0);
break;
case 3:
EIMSK &= ~(1 << INT1);
break;
case 4:
EIMSK &= ~(1 << INT2);
break;
case 5:
EIMSK &= ~(1 << INT3);
break;
case 0:
EIMSK &= ~(1 << INT4);
break;
case 1:
EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
#else
case 0:
#if defined(EIMSK) && defined(INT0)
EIMSK &= ~(1 << INT0);
#elif defined(GICR) && defined(ISC00)
GICR &= ~(1 << INT0); // atmega32
#elif defined(GIMSK) && defined(INT0)
GIMSK &= ~(1 << INT0);
#else
#error detachInterrupt not finished for this cpu
#endif
break;
case 1:
#if defined(EIMSK) && defined(INT1)
EIMSK &= ~(1 << INT1);
#elif defined(GICR) && defined(INT1)
GICR &= ~(1 << INT1); // atmega32
#elif defined(GIMSK) && defined(INT1)
GIMSK &= ~(1 << INT1);
#else
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
intFunc[interruptNum] = 0;
}
}
/*
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
*/
#if defined(EICRA) && defined(EICRB)
SIGNAL(INT0_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
SIGNAL(INT1_vect) {
if(intFunc[EXTERNAL_INT_3])
intFunc[EXTERNAL_INT_3]();
}
SIGNAL(INT2_vect) {
if(intFunc[EXTERNAL_INT_4])
intFunc[EXTERNAL_INT_4]();
}
SIGNAL(INT3_vect) {
if(intFunc[EXTERNAL_INT_5])
intFunc[EXTERNAL_INT_5]();
}
SIGNAL(INT4_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
SIGNAL(INT5_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
SIGNAL(INT6_vect) {
if(intFunc[EXTERNAL_INT_6])
intFunc[EXTERNAL_INT_6]();
}
SIGNAL(INT7_vect) {
if(intFunc[EXTERNAL_INT_7])
intFunc[EXTERNAL_INT_7]();
}
#else
SIGNAL(INT0_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
SIGNAL(INT1_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
#endif
/*
SIGNAL(SIG_2WIRE_SERIAL) {
if(twiIntFunc)
twiIntFunc();
}
*/

@ -0,0 +1,60 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.org.co
Copyright (c) 2004-06 Hernando Barragan
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
extern "C" {
#include "stdlib.h"
}
void randomSeed(unsigned int seed)
{
if (seed != 0) {
srandom(seed);
}
}
long random(long howbig)
{
if (howbig == 0) {
return 0;
}
return random() % howbig;
}
long random(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

@ -0,0 +1,63 @@
#ifndef WProgram_h
#define WProgram_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/interrupt.h>
#include "wiring.h"
#ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h"
#include "HardwareSerial.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
// WMath prototypes
long random(long);
long random(long, long);
void randomSeed(unsigned int);
long map(long, long, long, long, long);
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
const static uint8_t A0 = 54;
const static uint8_t A1 = 55;
const static uint8_t A2 = 56;
const static uint8_t A3 = 57;
const static uint8_t A4 = 58;
const static uint8_t A5 = 59;
const static uint8_t A6 = 60;
const static uint8_t A7 = 61;
const static uint8_t A8 = 62;
const static uint8_t A9 = 63;
const static uint8_t A10 = 64;
const static uint8_t A11 = 65;
const static uint8_t A12 = 66;
const static uint8_t A13 = 67;
const static uint8_t A14 = 68;
const static uint8_t A15 = 69;
#else
const static uint8_t A0 = 14;
const static uint8_t A1 = 15;
const static uint8_t A2 = 16;
const static uint8_t A3 = 17;
const static uint8_t A4 = 18;
const static uint8_t A5 = 19;
const static uint8_t A6 = 20;
const static uint8_t A7 = 21;
#endif
#endif
#endif

@ -0,0 +1,443 @@
/*
WString.cpp - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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.
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
*/
#include <stdlib.h>
#include "WProgram.h"
#include "WString.h"
String::String( const char *value )
{
if ( value == NULL )
value = "";
getBuffer( _length = strlen( value ) );
if ( _buffer != NULL )
strcpy( _buffer, value );
}
String::String( const String &value )
{
getBuffer( _length = value._length );
if ( _buffer != NULL )
strcpy( _buffer, value._buffer );
}
String::String( const char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL ) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const unsigned char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const int value, const int base )
{
char buf[33];
itoa((signed long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned int value, const int base )
{
char buf[33];
ultoa((unsigned long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const long value, const int base )
{
char buf[33];
ltoa(value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned long value, const int base )
{
char buf[33];
ultoa(value, buf, 10);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
char String::charAt( unsigned int loc ) const
{
return operator[]( loc );
}
void String::setCharAt( unsigned int loc, const char aChar )
{
if(_buffer == NULL) return;
if(_length > loc) {
_buffer[loc] = aChar;
}
}
int String::compareTo( const String &s2 ) const
{
return strcmp( _buffer, s2._buffer );
}
const String & String::concat( const String &s2 )
{
return (*this) += s2;
}
const String & String::operator=( const String &rhs )
{
if ( this == &rhs )
return *this;
if ( rhs._length > _length )
{
free(_buffer);
getBuffer( rhs._length );
}
if ( _buffer != NULL ) {
_length = rhs._length;
strcpy( _buffer, rhs._buffer );
}
return *this;
}
//const String & String::operator+=( const char aChar )
//{
// if ( _length == _capacity )
// doubleBuffer();
//
// _buffer[ _length++ ] = aChar;
// _buffer[ _length ] = '\0';
// return *this;
//}
const String & String::operator+=( const String &other )
{
_length += other._length;
if ( _length > _capacity )
{
char *temp = (char *)realloc(_buffer, _length + 1);
if ( temp != NULL ) {
_buffer = temp;
_capacity = _length;
} else {
_length -= other._length;
return *this;
}
}
strcat( _buffer, other._buffer );
return *this;
}
int String::operator==( const String &rhs ) const
{
return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 );
}
int String::operator!=( const String &rhs ) const
{
return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 );
}
int String::operator<( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) < 0;
}
int String::operator>( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) > 0;
}
int String::operator<=( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) <= 0;
}
int String::operator>=( const String & rhs ) const
{
return strcmp( _buffer, rhs._buffer ) >= 0;
}
char & String::operator[]( unsigned int index )
{
static char dummy_writable_char;
if (index >= _length || !_buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return _buffer[ index ];
}
char String::operator[]( unsigned int index ) const
{
// need to check for valid index, to do later
return _buffer[ index ];
}
boolean String::endsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0;
}
boolean String::equals( const String &s2 ) const
{
return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 );
}
boolean String::equalsIgnoreCase( const String &s2 ) const
{
if ( this == &s2 )
return true; //1;
else if ( _length != s2._length )
return false; //0;
return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0;
}
String String::replace( char findChar, char replaceChar )
{
if ( _buffer == NULL ) return *this;
String theReturn = _buffer;
char* temp = theReturn._buffer;
while( (temp = strchr( temp, findChar )) != 0 )
*temp = replaceChar;
return theReturn;
}
String String::replace( const String& match, const String& replace )
{
if ( _buffer == NULL ) return *this;
String temp = _buffer, newString;
int loc;
while ( (loc = temp.indexOf( match )) != -1 )
{
newString += temp.substring( 0, loc );
newString += replace;
temp = temp.substring( loc + match._length );
}
newString += temp;
return newString;
}
int String::indexOf( char temp ) const
{
return indexOf( temp, 0 );
}
int String::indexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char* temp = strchr( &_buffer[fromIndex], ch );
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::indexOf( const String &s2 ) const
{
return indexOf( s2, 0 );
}
int String::indexOf( const String &s2, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer );
if ( theFind == NULL )
return -1;
return theFind - _buffer; // pointer subtraction
}
int String::lastIndexOf( char theChar ) const
{
return lastIndexOf( theChar, _length - 1 );
}
int String::lastIndexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
char tempchar = _buffer[fromIndex + 1];
_buffer[fromIndex + 1] = '\0';
char* temp = strrchr( _buffer, ch );
_buffer[fromIndex + 1] = tempchar;
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::lastIndexOf( const String &s2 ) const
{
return lastIndexOf( s2, _length - s2._length );
}
int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const
{
// check for empty strings
if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length )
return -1;
// matching first character
char temp = s2[ 0 ];
for ( int i = fromIndex; i >= 0; i-- )
{
if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) )
return i;
}
return -1;
}
boolean String::startsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return startsWith( s2, 0 );
}
boolean String::startsWith( const String &s2, unsigned int offset ) const
{
if ( offset > _length - s2._length )
return 0;
return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0;
}
String String::substring( unsigned int left ) const
{
return substring( left, _length );
}
String String::substring( unsigned int left, unsigned int right ) const
{
if ( left > right )
{
int temp = right;
right = left;
left = temp;
}
if ( right > _length )
{
right = _length;
}
char temp = _buffer[ right ]; // save the replaced character
_buffer[ right ] = '\0';
String outPut = ( _buffer + left ); // pointer arithmetic
_buffer[ right ] = temp; //restore character
return outPut;
}
String String::toLowerCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] );
return temp;
}
String String::toUpperCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] );
return temp;
}
String String::trim() const
{
if ( _buffer == NULL ) return *this;
String temp = _buffer;
unsigned int i,j;
for ( i = 0; i < _length; i++ )
{
if ( !isspace(_buffer[i]) )
break;
}
for ( j = temp._length - 1; j > i; j-- )
{
if ( !isspace(_buffer[j]) )
break;
}
return temp.substring( i, j + 1);
}
void String::getBytes(unsigned char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy((char *)buf, _buffer, len);
buf[len] = 0;
}
void String::toCharArray(char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy(buf, _buffer, len);
buf[len] = 0;
}
long String::toInt() {
return atol(_buffer);
}

@ -0,0 +1,112 @@
/*
WString.h - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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 String_h
#define String_h
//#include "WProgram.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
class String
{
public:
// constructors
String( const char *value = "" );
String( const String &value );
String( const char );
String( const unsigned char );
String( const int, const int base=10);
String( const unsigned int, const int base=10 );
String( const long, const int base=10 );
String( const unsigned long, const int base=10 );
~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0;
// operators
const String & operator = ( const String &rhs );
const String & operator +=( const String &rhs );
//const String & operator +=( const char );
int operator ==( const String &rhs ) const;
int operator !=( const String &rhs ) const;
int operator < ( const String &rhs ) const;
int operator > ( const String &rhs ) const;
int operator <=( const String &rhs ) const;
int operator >=( const String &rhs ) const;
char operator []( unsigned int index ) const;
char& operator []( unsigned int index );
//operator const char *() const { return _buffer; }
// general methods
char charAt( unsigned int index ) const;
int compareTo( const String &anotherString ) const;
unsigned char endsWith( const String &suffix ) const;
unsigned char equals( const String &anObject ) const;
unsigned char equalsIgnoreCase( const String &anotherString ) const;
int indexOf( char ch ) const;
int indexOf( char ch, unsigned int fromIndex ) const;
int indexOf( const String &str ) const;
int indexOf( const String &str, unsigned int fromIndex ) const;
int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
const unsigned int length( ) const { return _length; }
void setCharAt(unsigned int index, const char ch);
unsigned char startsWith( const String &prefix ) const;
unsigned char startsWith( const String &prefix, unsigned int toffset ) const;
String substring( unsigned int beginIndex ) const;
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
String toLowerCase( ) const;
String toUpperCase( ) const;
String trim( ) const;
void getBytes(unsigned char *buf, unsigned int bufsize);
void toCharArray(char *buf, unsigned int bufsize);
long toInt( );
const String& concat( const String &str );
String replace( char oldChar, char newChar );
String replace( const String& match, const String& replace );
friend String operator + ( String lhs, const String &rhs );
protected:
char *_buffer; // the actual char array
unsigned int _capacity; // the array length minus one (for the '\0')
unsigned int _length; // the String length (not counting the '\0')
void getBuffer(unsigned int maxStrLen);
private:
};
// allocate buffer space
inline void String::getBuffer(unsigned int maxStrLen)
{
_capacity = maxStrLen;
_buffer = (char *) malloc(_capacity + 1);
if (_buffer == NULL) _length = _capacity = 0;
}
inline String operator+( String lhs, const String &rhs )
{
return lhs += rhs;
}
#endif

@ -0,0 +1,515 @@
#ifndef Binary_h
#define Binary_h
#define B0 0
#define B00 0
#define B000 0
#define B0000 0
#define B00000 0
#define B000000 0
#define B0000000 0
#define B00000000 0
#define B1 1
#define B01 1
#define B001 1
#define B0001 1
#define B00001 1
#define B000001 1
#define B0000001 1
#define B00000001 1
#define B10 2
#define B010 2
#define B0010 2
#define B00010 2
#define B000010 2
#define B0000010 2
#define B00000010 2
#define B11 3
#define B011 3
#define B0011 3
#define B00011 3
#define B000011 3
#define B0000011 3
#define B00000011 3
#define B100 4
#define B0100 4
#define B00100 4
#define B000100 4
#define B0000100 4
#define B00000100 4
#define B101 5
#define B0101 5
#define B00101 5
#define B000101 5
#define B0000101 5
#define B00000101 5
#define B110 6
#define B0110 6
#define B00110 6
#define B000110 6
#define B0000110 6
#define B00000110 6
#define B111 7
#define B0111 7
#define B00111 7
#define B000111 7
#define B0000111 7
#define B00000111 7
#define B1000 8
#define B01000 8
#define B001000 8
#define B0001000 8
#define B00001000 8
#define B1001 9
#define B01001 9
#define B001001 9
#define B0001001 9
#define B00001001 9
#define B1010 10
#define B01010 10
#define B001010 10
#define B0001010 10
#define B00001010 10
#define B1011 11
#define B01011 11
#define B001011 11
#define B0001011 11
#define B00001011 11
#define B1100 12
#define B01100 12
#define B001100 12
#define B0001100 12
#define B00001100 12
#define B1101 13
#define B01101 13
#define B001101 13
#define B0001101 13
#define B00001101 13
#define B1110 14
#define B01110 14
#define B001110 14
#define B0001110 14
#define B00001110 14
#define B1111 15
#define B01111 15
#define B001111 15
#define B0001111 15
#define B00001111 15
#define B10000 16
#define B010000 16
#define B0010000 16
#define B00010000 16
#define B10001 17
#define B010001 17
#define B0010001 17
#define B00010001 17
#define B10010 18
#define B010010 18
#define B0010010 18
#define B00010010 18
#define B10011 19
#define B010011 19
#define B0010011 19
#define B00010011 19
#define B10100 20
#define B010100 20
#define B0010100 20
#define B00010100 20
#define B10101 21
#define B010101 21
#define B0010101 21
#define B00010101 21
#define B10110 22
#define B010110 22
#define B0010110 22
#define B00010110 22
#define B10111 23
#define B010111 23
#define B0010111 23
#define B00010111 23
#define B11000 24
#define B011000 24
#define B0011000 24
#define B00011000 24
#define B11001 25
#define B011001 25
#define B0011001 25
#define B00011001 25
#define B11010 26
#define B011010 26
#define B0011010 26
#define B00011010 26
#define B11011 27
#define B011011 27
#define B0011011 27
#define B00011011 27
#define B11100 28
#define B011100 28
#define B0011100 28
#define B00011100 28
#define B11101 29
#define B011101 29
#define B0011101 29
#define B00011101 29
#define B11110 30
#define B011110 30
#define B0011110 30
#define B00011110 30
#define B11111 31
#define B011111 31
#define B0011111 31
#define B00011111 31
#define B100000 32
#define B0100000 32
#define B00100000 32
#define B100001 33
#define B0100001 33
#define B00100001 33
#define B100010 34
#define B0100010 34
#define B00100010 34
#define B100011 35
#define B0100011 35
#define B00100011 35
#define B100100 36
#define B0100100 36
#define B00100100 36
#define B100101 37
#define B0100101 37
#define B00100101 37
#define B100110 38
#define B0100110 38
#define B00100110 38
#define B100111 39
#define B0100111 39
#define B00100111 39
#define B101000 40
#define B0101000 40
#define B00101000 40
#define B101001 41
#define B0101001 41
#define B00101001 41
#define B101010 42
#define B0101010 42
#define B00101010 42
#define B101011 43
#define B0101011 43
#define B00101011 43
#define B101100 44
#define B0101100 44
#define B00101100 44
#define B101101 45
#define B0101101 45
#define B00101101 45
#define B101110 46
#define B0101110 46
#define B00101110 46
#define B101111 47
#define B0101111 47
#define B00101111 47
#define B110000 48
#define B0110000 48
#define B00110000 48
#define B110001 49
#define B0110001 49
#define B00110001 49
#define B110010 50
#define B0110010 50
#define B00110010 50
#define B110011 51
#define B0110011 51
#define B00110011 51
#define B110100 52
#define B0110100 52
#define B00110100 52
#define B110101 53
#define B0110101 53
#define B00110101 53
#define B110110 54
#define B0110110 54
#define B00110110 54
#define B110111 55
#define B0110111 55
#define B00110111 55
#define B111000 56
#define B0111000 56
#define B00111000 56
#define B111001 57
#define B0111001 57
#define B00111001 57
#define B111010 58
#define B0111010 58
#define B00111010 58
#define B111011 59
#define B0111011 59
#define B00111011 59
#define B111100 60
#define B0111100 60
#define B00111100 60
#define B111101 61
#define B0111101 61
#define B00111101 61
#define B111110 62
#define B0111110 62
#define B00111110 62
#define B111111 63
#define B0111111 63
#define B00111111 63
#define B1000000 64
#define B01000000 64
#define B1000001 65
#define B01000001 65
#define B1000010 66
#define B01000010 66
#define B1000011 67
#define B01000011 67
#define B1000100 68
#define B01000100 68
#define B1000101 69
#define B01000101 69
#define B1000110 70
#define B01000110 70
#define B1000111 71
#define B01000111 71
#define B1001000 72
#define B01001000 72
#define B1001001 73
#define B01001001 73
#define B1001010 74
#define B01001010 74
#define B1001011 75
#define B01001011 75
#define B1001100 76
#define B01001100 76
#define B1001101 77
#define B01001101 77
#define B1001110 78
#define B01001110 78
#define B1001111 79
#define B01001111 79
#define B1010000 80
#define B01010000 80
#define B1010001 81
#define B01010001 81
#define B1010010 82
#define B01010010 82
#define B1010011 83
#define B01010011 83
#define B1010100 84
#define B01010100 84
#define B1010101 85
#define B01010101 85
#define B1010110 86
#define B01010110 86
#define B1010111 87
#define B01010111 87
#define B1011000 88
#define B01011000 88
#define B1011001 89
#define B01011001 89
#define B1011010 90
#define B01011010 90
#define B1011011 91
#define B01011011 91
#define B1011100 92
#define B01011100 92
#define B1011101 93
#define B01011101 93
#define B1011110 94
#define B01011110 94
#define B1011111 95
#define B01011111 95
#define B1100000 96
#define B01100000 96
#define B1100001 97
#define B01100001 97
#define B1100010 98
#define B01100010 98
#define B1100011 99
#define B01100011 99
#define B1100100 100
#define B01100100 100
#define B1100101 101
#define B01100101 101
#define B1100110 102
#define B01100110 102
#define B1100111 103
#define B01100111 103
#define B1101000 104
#define B01101000 104
#define B1101001 105
#define B01101001 105
#define B1101010 106
#define B01101010 106
#define B1101011 107
#define B01101011 107
#define B1101100 108
#define B01101100 108
#define B1101101 109
#define B01101101 109
#define B1101110 110
#define B01101110 110
#define B1101111 111
#define B01101111 111
#define B1110000 112
#define B01110000 112
#define B1110001 113
#define B01110001 113
#define B1110010 114
#define B01110010 114
#define B1110011 115
#define B01110011 115
#define B1110100 116
#define B01110100 116
#define B1110101 117
#define B01110101 117
#define B1110110 118
#define B01110110 118
#define B1110111 119
#define B01110111 119
#define B1111000 120
#define B01111000 120
#define B1111001 121
#define B01111001 121
#define B1111010 122
#define B01111010 122
#define B1111011 123
#define B01111011 123
#define B1111100 124
#define B01111100 124
#define B1111101 125
#define B01111101 125
#define B1111110 126
#define B01111110 126
#define B1111111 127
#define B01111111 127
#define B10000000 128
#define B10000001 129
#define B10000010 130
#define B10000011 131
#define B10000100 132
#define B10000101 133
#define B10000110 134
#define B10000111 135
#define B10001000 136
#define B10001001 137
#define B10001010 138
#define B10001011 139
#define B10001100 140
#define B10001101 141
#define B10001110 142
#define B10001111 143
#define B10010000 144
#define B10010001 145
#define B10010010 146
#define B10010011 147
#define B10010100 148
#define B10010101 149
#define B10010110 150
#define B10010111 151
#define B10011000 152
#define B10011001 153
#define B10011010 154
#define B10011011 155
#define B10011100 156
#define B10011101 157
#define B10011110 158
#define B10011111 159
#define B10100000 160
#define B10100001 161
#define B10100010 162
#define B10100011 163
#define B10100100 164
#define B10100101 165
#define B10100110 166
#define B10100111 167
#define B10101000 168
#define B10101001 169
#define B10101010 170
#define B10101011 171
#define B10101100 172
#define B10101101 173
#define B10101110 174
#define B10101111 175
#define B10110000 176
#define B10110001 177
#define B10110010 178
#define B10110011 179
#define B10110100 180
#define B10110101 181
#define B10110110 182
#define B10110111 183
#define B10111000 184
#define B10111001 185
#define B10111010 186
#define B10111011 187
#define B10111100 188
#define B10111101 189
#define B10111110 190
#define B10111111 191
#define B11000000 192
#define B11000001 193
#define B11000010 194
#define B11000011 195
#define B11000100 196
#define B11000101 197
#define B11000110 198
#define B11000111 199
#define B11001000 200
#define B11001001 201
#define B11001010 202
#define B11001011 203
#define B11001100 204
#define B11001101 205
#define B11001110 206
#define B11001111 207
#define B11010000 208
#define B11010001 209
#define B11010010 210
#define B11010011 211
#define B11010100 212
#define B11010101 213
#define B11010110 214
#define B11010111 215
#define B11011000 216
#define B11011001 217
#define B11011010 218
#define B11011011 219
#define B11011100 220
#define B11011101 221
#define B11011110 222
#define B11011111 223
#define B11100000 224
#define B11100001 225
#define B11100010 226
#define B11100011 227
#define B11100100 228
#define B11100101 229
#define B11100110 230
#define B11100111 231
#define B11101000 232
#define B11101001 233
#define B11101010 234
#define B11101011 235
#define B11101100 236
#define B11101101 237
#define B11101110 238
#define B11101111 239
#define B11110000 240
#define B11110001 241
#define B11110010 242
#define B11110011 243
#define B11110100 244
#define B11110101 245
#define B11110110 246
#define B11110111 247
#define B11111000 248
#define B11111001 249
#define B11111010 250
#define B11111011 251
#define B11111100 252
#define B11111101 253
#define B11111110 254
#define B11111111 255
#endif

@ -0,0 +1,14 @@
#include <WProgram.h>
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

@ -0,0 +1,200 @@
/*
pins_arduino.c - pin definitions for the Arduino board
Part of Arduino / Wiring Lite
Copyright (c) 2005 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: pins_arduino.c 254 2007-04-20 23:17:38Z mellis $
*/
#include <avr/io.h>
#include "wiring_private.h"
#include "pins_arduino.h"
// On the Sanguino board, digital pins are also used
// for the analog output (software PWM). Analog input
// pins are a separate set.
// ATMEL ATMEGA644P / SANGUINO
//
// +---\/---+
// INT0 (D 0) PB0 1| |40 PA0 (AI 0 / D31)
// INT1 (D 1) PB1 2| |39 PA1 (AI 1 / D30)
// INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
// PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
// PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
// MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
// MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
// SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
// RST 9| |32 AREF
// VCC 10| |31 GND
// GND 11| |30 AVCC
// XTAL2 12| |29 PC7 (D 23)
// XTAL1 13| |28 PC6 (D 22)
// RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
// TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
// RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
// TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
// PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
// PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
// PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
// +--------+
//
#define PA 1
#define PB 2
#define PC 3
#define PD 4
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &DDRA,
(uint8_t) (uint16_t) &DDRB,
(uint8_t) (uint16_t) &DDRC,
(uint8_t) (uint16_t) &DDRD,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &PORTA,
(uint8_t) (uint16_t) &PORTB,
(uint8_t) (uint16_t) &PORTC,
(uint8_t) (uint16_t) &PORTD,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &PINA,
(uint8_t) (uint16_t) &PINB,
(uint8_t) (uint16_t) &PINC,
(uint8_t) (uint16_t) &PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PB, /* 0 */
PB,
PB,
PB,
PB,
PB,
PB,
PB,
PD, /* 8 */
PD,
PD,
PD,
PD,
PD,
PD,
PD,
PC, /* 16 */
PC,
PC,
PC,
PC,
PC,
PC,
PC,
PA, /* 24 */
PA,
PA,
PA,
PA,
PA,
PA,
PA /* 31 */
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0, port B */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 8, port D */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 16, port C */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(7), /* 24, port A */
_BV(6),
_BV(5),
_BV(4),
_BV(3),
_BV(2),
_BV(1),
_BV(0)
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
NOT_ON_TIMER, /* 0 - PB0 */
NOT_ON_TIMER, /* 1 - PB1 */
NOT_ON_TIMER, /* 2 - PB2 */
TIMER0A, /* 3 - PB3 */
TIMER0B, /* 4 - PB4 */
NOT_ON_TIMER, /* 5 - PB5 */
NOT_ON_TIMER, /* 6 - PB6 */
NOT_ON_TIMER, /* 7 - PB7 */
NOT_ON_TIMER, /* 8 - PD0 */
NOT_ON_TIMER, /* 9 - PD1 */
NOT_ON_TIMER, /* 10 - PD2 */
NOT_ON_TIMER, /* 11 - PD3 */
TIMER1B, /* 12 - PD4 */
TIMER1A, /* 13 - PD5 */
TIMER2B, /* 14 - PD6 */
TIMER2A, /* 15 - PD7 */
NOT_ON_TIMER, /* 16 - PC0 */
NOT_ON_TIMER, /* 17 - PC1 */
NOT_ON_TIMER, /* 18 - PC2 */
NOT_ON_TIMER, /* 19 - PC3 */
NOT_ON_TIMER, /* 20 - PC4 */
NOT_ON_TIMER, /* 21 - PC5 */
NOT_ON_TIMER, /* 22 - PC6 */
NOT_ON_TIMER, /* 23 - PC7 */
NOT_ON_TIMER, /* 24 - PA0 */
NOT_ON_TIMER, /* 25 - PA1 */
NOT_ON_TIMER, /* 26 - PA2 */
NOT_ON_TIMER, /* 27 - PA3 */
NOT_ON_TIMER, /* 28 - PA4 */
NOT_ON_TIMER, /* 29 - PA5 */
NOT_ON_TIMER, /* 30 - PA6 */
NOT_ON_TIMER /* 31 - PA7 */
};

@ -0,0 +1,65 @@
/*
pins_arduino.h - Pin definition functions for Arduino
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2007 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <avr/pgmspace.h>
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER2 5
#define TIMER2A 6
#define TIMER2B 7
extern const uint8_t PROGMEM port_to_mode_PGM[];
extern const uint8_t PROGMEM port_to_input_PGM[];
extern const uint8_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_mode_PGM + (P))) )
#endif

@ -0,0 +1,289 @@
/*
wiring.c - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#include "wiring_private.h"
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
SIGNAL(TIMER0_OVF_vect)
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
m = timer0_millis;
SREG = oldSREG;
return m;
}
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
#if defined(TCNT0)
t = TCNT0;
#elif defined(TCNT0L)
t = TCNT0L;
#else
#error TIMER 0 not defined
#endif
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
#else
if ((TIFR & _BV(TOV0)) && (t < 255))
m++;
#endif
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return. the overhead of
// the function calls takes more than two microseconds. can't just
// subtract two, since us is unsigned; we'd overflow.
if (--us == 0)
return;
if (--us == 0)
return;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}
void init()
{
// this needs to be called before setup() or some functions won't
// work there
sei();
// on the ATmega168, timer 0 is also used for fast hardware pwm
// (using phase-correct PWM would mean that timer 0 overflowed half as often
// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#endif
// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
// CPU specific: different values for the ATmega128
sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
// this combination is for the standard atmega8
sbi(TCCR0, CS01);
sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
// this combination is for the __AVR_ATmega645__ series
sbi(TCCR0A, CS01);
sbi(TCCR0A, CS00);
#else
#error Timer 0 prescale factor 64 not set correctly
#endif
// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif
// timers 1 and 2 are used for phase-correct hardware pwm
// this is better for motors as it ensures an even waveform
// note, however, that fast pwm mode can achieve a frequency of up
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
TCCR1B = 0;
// set timer 1 prescale factor to 64
#if defined(TCCR1B) && defined(CS11) && defined(CS10)
sbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
sbi(TCCR1, CS11);
sbi(TCCR1, CS10);
#endif
// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
sbi(TCCR1A, WGM10);
#elif defined(TCCR1)
#warning this needs to be finished
#endif
// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
sbi(TCCR2B, CS22);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
sbi(TCCR2A, WGM20);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
sbi(TCCR3B, CS30);
sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
#endif
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
sbi(TCCR4B, CS40);
sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
#endif
#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
#endif
#if defined(ADCSRA)
// set a2d prescale factor to 128
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
// XXX: this will not work properly for other clock speeds, and
// this code should use F_CPU to determine the prescale factor.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif
// the bootloader connects pins 0 and 1 to the USART; disconnect them
// here so they can be used as normal digital i/o; they will be
// reconnected in Serial.begin()
#if defined(UCSRB)
UCSRB = 0;
#elif defined(UCSR0B)
UCSR0B = 0;
#endif
}

@ -0,0 +1,136 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#ifndef Wiring_h
#define Wiring_h
#include <math.h>
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,259 @@
/*
wiring_analog.c - analog input and output
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 28 September 2010 by Mark Sproul
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
uint8_t analog_reference = DEFAULT;
void analogReference(uint8_t mode)
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
analog_reference = mode;
}
int analogRead(uint8_t pin)
{
uint8_t low, high;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#else
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif
#if defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
#if defined(ADMUX)
ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif
// without a delay, we seem to read from the wrong channel
//delay(1);
#if defined(ADCSRA) && defined(ADCL)
// start the conversion
sbi(ADCSRA, ADSC);
// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));
// we have to read ADCL first; doing so locks both ADCL
// and ADCH until ADCH is read. reading ADCL second would
// cause the results of each conversion to be discarded,
// as ADCL and ADCH would be locked when it completed.
low = ADCL;
high = ADCH;
#else
// we dont have an ADC, return 0
low = 0;
high = 0;
#endif
// combine the two bytes
return (high << 8) | low;
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// pins_*.c file. For the rest of the pins, we default
// to digital output.
void analogWrite(uint8_t pin, int val)
{
// We need to make sure the PWM output is enabled for those pins
// that support it, as we turn it off when digitally reading or
// writing with them. Also, make sure the pin is in output mode
// for consistenty with Wiring, which doesn't require a pinMode
// call for the analog output pins.
pinMode(pin, OUTPUT);
if (val == 0)
{
digitalWrite(pin, LOW);
}
else if (val == 255)
{
digitalWrite(pin, HIGH);
}
else
{
switch(digitalPinToTimer(pin))
{
// XXX fix needed for atmega8
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
case TIMER0A:
// connect pwm to pin on timer 0
sbi(TCCR0, COM00);
OCR0 = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A:
// connect pwm to pin on timer 0, channel A
sbi(TCCR0A, COM0A1);
OCR0A = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0B1)
case TIMER0B:
// connect pwm to pin on timer 0, channel B
sbi(TCCR0A, COM0B1);
OCR0B = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
// connect pwm to pin on timer 1, channel A
sbi(TCCR1A, COM1A1);
OCR1A = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:
// connect pwm to pin on timer 1, channel B
sbi(TCCR1A, COM1B1);
OCR1B = val; // set pwm duty
break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2:
// connect pwm to pin on timer 2
sbi(TCCR2, COM21);
OCR2 = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A:
// connect pwm to pin on timer 2, channel A
sbi(TCCR2A, COM2A1);
OCR2A = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B:
// connect pwm to pin on timer 2, channel B
sbi(TCCR2A, COM2B1);
OCR2B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A:
// connect pwm to pin on timer 3, channel A
sbi(TCCR3A, COM3A1);
OCR3A = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
// connect pwm to pin on timer 3, channel B
sbi(TCCR3A, COM3B1);
OCR3B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C:
// connect pwm to pin on timer 3, channel C
sbi(TCCR3A, COM3C1);
OCR3C = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4A1)
case TIMER4A:
// connect pwm to pin on timer 4, channel A
sbi(TCCR4A, COM4A1);
OCR4A = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
// connect pwm to pin on timer 4, channel B
sbi(TCCR4A, COM4B1);
OCR4B = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C:
// connect pwm to pin on timer 4, channel C
sbi(TCCR4A, COM4C1);
OCR4C = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5A1)
case TIMER5A:
// connect pwm to pin on timer 5, channel A
sbi(TCCR5A, COM5A1);
OCR5A = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5B1)
case TIMER5B:
// connect pwm to pin on timer 5, channel B
sbi(TCCR5A, COM5B1);
OCR5B = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5C1)
case TIMER5C:
// connect pwm to pin on timer 5, channel C
sbi(TCCR5A, COM5C1);
OCR5C = val; // set pwm duty
break;
#endif
case NOT_ON_TIMER:
default:
if (val < 128) {
digitalWrite(pin, LOW);
} else {
digitalWrite(pin, HIGH);
}
}
}
}

@ -0,0 +1,166 @@
/*
wiring_digital.c - digital input and output functions
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 28 September 2010 by Mark Sproul
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;
if (port == NOT_A_PIN) return;
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
if (mode == INPUT) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
SREG = oldSREG;
}
}
// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
// Mark Sproul:
// - Removed inline. Save 170 bytes on atmega1280
// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
// - Added more #ifdefs, now compiles for atmega645
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
switch (timer)
{
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A: cbi(TCCR1A, COM1A1); break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B: cbi(TCCR1A, COM1B1); break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2: cbi(TCCR2, COM21); break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A: cbi(TCCR0A, COM0A1); break;
#endif
#if defined(TIMER0B) && defined(COM0B1)
case TIMER0B: cbi(TCCR0A, COM0B1); break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A: cbi(TCCR2A, COM2A1); break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B: cbi(TCCR2A, COM2B1); break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A: cbi(TCCR3A, COM3A1); break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B: cbi(TCCR3A, COM3B1); break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C: cbi(TCCR3A, COM3C1); break;
#endif
#if defined(TCCR4A) && defined(COM4A1)
case TIMER4A: cbi(TCCR4A, COM4A1); break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B: cbi(TCCR4A, COM4B1); break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C: cbi(TCCR4A, COM4C1); break;
#endif
#if defined(TCCR5A)
case TIMER5A: cbi(TCCR5A, COM5A1); break;
case TIMER5B: cbi(TCCR5A, COM5B1); break;
case TIMER5C: cbi(TCCR5A, COM5C1); break;
#endif
}
}
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*out |= bit;
SREG = oldSREG;
}
}
int digitalRead(uint8_t pin)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

@ -0,0 +1,68 @@
/*
wiring_private.h - Internal header file.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
*/
#ifndef WiringPrivate_h
#define WiringPrivate_h
#include <math.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdarg.h>
#include "wiring.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define EXTERNAL_INT_0 0
#define EXTERNAL_INT_1 1
#define EXTERNAL_INT_2 2
#define EXTERNAL_INT_3 3
#define EXTERNAL_INT_4 4
#define EXTERNAL_INT_5 5
#define EXTERNAL_INT_6 6
#define EXTERNAL_INT_7 7
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define EXTERNAL_NUM_INTERRUPTS 8
#else
#define EXTERNAL_NUM_INTERRUPTS 2
#endif
typedef void (*voidFuncPtr)(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,69 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution. calling
// digitalRead() instead yields much coarser resolution.
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
width++;
}
// convert the reading to microseconds. The loop has been determined
// to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 21 + 16);
}

@ -0,0 +1,55 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
}
return value;
}
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

@ -0,0 +1,188 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for software and other kinds of works.
The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, 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 them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.
Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.
Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS
0. Definitions.
“This License” refers to version 3 of the GNU General Public License.
“Copyright” also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.
“The Program” refers to any copyrightable work licensed under this License. Each licensee is addressed as “you”. “Licensees” and “recipients” may be individuals or organizations.
To “modify” a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a “modified version” of the earlier work or a work “based on” the earlier work.
A “covered work” means either the unmodified Program or a work based on the Program.
To “propagate” a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.
To “convey” a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays “Appropriate Legal Notices” to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.
1. Source Code.
The “source code” for a work means the preferred form of the work for making modifications to it. “Object code” means any non-source form of a work.
A “Standard Interface” means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.
The “System Libraries” of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A “Major Component”, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.
The “Corresponding Source” for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.
The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.
The Corresponding Source for a work in source code form is that same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.
When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified it, and giving a relevant date.
b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to “keep intact all notices”.
c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.
A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an “aggregate” if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:
a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.
d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.
A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.
A “User Product” is either (1) a “consumer product”, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, “normally used” refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.
“Installation Information” for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.
If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).
The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.
7. Additional Terms.
“Additional permissions” are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or authors of the material; or
e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.
All other non-permissive additional terms are considered “further restrictions” within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).
However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.
Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.
An “entity transaction” is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.
11. Patents.
A “contributor” is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's “contributor version”.
A contributor's “essential patent claims” are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, “control” includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.
In the following three paragraphs, a “patent license” is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To “grant” such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.
If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. “Knowingly relying” means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.
A patent license is “discriminatory” if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of the GNU 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 Program specifies that a certain numbered version of the GNU General Public License “or any later version” applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.
If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.
Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “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 PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.

@ -0,0 +1,294 @@
#ifndef CONFIGURATION_H
#define CONFIGURATION_H
// This configurtion file contains the basic settings.
// Advanced settings can be found in Configuration_adv.h
// BASIC SETTINGS: select your board type, temperature sensor type, axis scaling, and endstop configuration
//User specified version info of THIS file to display in [Pronterface, etc] terminal window during startup.
//Implementation of an idea by Prof Braino to inform user that any changes made
//to THIS file by the user have been successfully uploaded into firmware.
#define STRING_VERSION_CONFIG_H "2012-05-02" //Personal revision number for changes to THIS file.
#define STRING_CONFIG_H_AUTHOR "erik" //Who made the changes.
// This determines the communication speed of the printer
#define BAUDRATE 250000
//#define BAUDRATE 115200
//// The following define selects which electronics board you have. Please choose the one that matches your setup
// Gen7 custom (Alfons3 Version) = 10 "https://github.com/Alfons3/Generation_7_Electronics"
// Gen7 v1.1, v1.2 = 11
// Gen7 v1.3 = 12
// Gen7 v1.4 = 13
// MEGA/RAMPS up to 1.2 = 3
// RAMPS 1.3 = 33 (Power outputs: Extruder, Bed, Fan)
// RAMPS 1.3 = 34 (Power outputs: Extruder0, Extruder1, Bed)
// Gen6 = 5
// Gen6 deluxe = 51
// Sanguinololu 1.2 and above = 62
// Melzi = 63
// Ultimaker = 7
// Teensylu = 8
// Gen3+ =9
#ifndef MOTHERBOARD
#define MOTHERBOARD 7
#endif
//===========================================================================
//=============================Thermal Settings ============================
//===========================================================================
//
//--NORMAL IS 4.7kohm PULLUP!-- 1kohm pullup can be used on hotend sensor, using correct resistor and table
//
//// Temperature sensor settings:
// -2 is thermocouple with MAX6675 (only for sensor 0)
// -1 is thermocouple with AD595
// 0 is not used
// 1 is 100k thermistor - best choice for EPCOS 100k (4.7k pullup)
// 2 is 200k thermistor - ATC Semitec 204GT-2 (4.7k pullup)
// 3 is mendel-parts thermistor (4.7k pullup)
// 4 is 10k thermistor !! do not use it for a hotend. It gives bad resolution at high temp. !!
// 5 is 100K thermistor - ATC Semitec 104GT-2 (Used in ParCan) (4.7k pullup)
// 6 is 100k EPCOS - Not as accurate as table 1 (created using a fluke thermocouple) (4.7k pullup)
// 7 is 100k Honeywell thermistor 135-104LAG-J01 (4.7k pullup)
//
// 1k ohm pullup tables - This is not normal, you would have to have changed out your 4.7k for 1k
// (but gives greater accuracy and more stable PID)
// 51 is 100k thermistor - EPCOS (1k pullup)
// 52 is 200k thermistor - ATC Semitec 204GT-2 (1k pullup)
// 55 is 100k thermistor - ATC Semitec 104GT-2 (Used in ParCan) (1k pullup)
#define TEMP_SENSOR_0 -1
#define TEMP_SENSOR_1 0
#define TEMP_SENSOR_2 0
#define TEMP_SENSOR_BED 0
// Actual temperature must be close to target for this long before M109 returns success
#define TEMP_RESIDENCY_TIME 10 // (seconds)
#define TEMP_HYSTERESIS 3 // (degC) range of +/- temperatures considered "close" to the target one
#define TEMP_WINDOW 1 // (degC) Window around target to start the recidency timer x degC early.
// The minimal temperature defines the temperature below which the heater will not be enabled It is used
// to check that the wiring to the thermistor is not broken.
// Otherwise this would lead to the heater being powered on all the time.
#define HEATER_0_MINTEMP 5
#define HEATER_1_MINTEMP 5
#define HEATER_2_MINTEMP 5
#define BED_MINTEMP 5
// When temperature exceeds max temp, your heater will be switched off.
// This feature exists to protect your hotend from overheating accidentally, but *NOT* from thermistor short/failure!
// You should use MINTEMP for thermistor short/failure protection.
#define HEATER_0_MAXTEMP 275
#define HEATER_1_MAXTEMP 275
#define HEATER_2_MAXTEMP 275
#define BED_MAXTEMP 150
// If your bed has low resistance e.g. .6 ohm and throws the fuse you can duty cycle it to reduce the
// average current. The value should be an integer and the heat bed will be turned on for 1 interval of
// HEATER_BED_DUTY_CYCLE_DIVIDER intervals.
//#define HEATER_BED_DUTY_CYCLE_DIVIDER 4
// PID settings:
// Comment the following line to disable PID and enable bang-bang.
#define PIDTEMP
#define PID_MAX 255 // limits current to nozzle; 255=full current
#ifdef PIDTEMP
//#define PID_DEBUG // Sends debug data to the serial port.
//#define PID_OPENLOOP 1 // Puts PID in open loop. M104 sets the output power in %
#define PID_INTEGRAL_DRIVE_MAX 255 //limit for the integral term
#define K1 0.95 //smoothing factor withing the PID
#define PID_dT ((16.0 * 8.0)/(F_CPU / 64.0 / 256.0)) //sampling period of the
// If you are using a preconfigured hotend then you can use one of the value sets by uncommenting it
// Ultimaker
#define DEFAULT_Kp 22.2
#define DEFAULT_Ki 1.08
#define DEFAULT_Kd 114
// Makergear
// #define DEFAULT_Kp 7.0
// #define DEFAULT_Ki 0.1
// #define DEFAULT_Kd 12
// Mendel Parts V9 on 12V
// #define DEFAULT_Kp 63.0
// #define DEFAULT_Ki 2.25
// #define DEFAULT_Kd 440
#endif // PIDTEMP
//this prevents dangerous Extruder moves, i.e. if the temperature is under the limit
//can be software-disabled for whatever purposes by
#define PREVENT_DANGEROUS_EXTRUDE
//if PREVENT_DANGEROUS_EXTRUDE is on, you can still disable (uncomment) very long bits of extrusion separately.
#define PREVENT_LENGTHY_EXTRUDE
#define EXTRUDE_MINTEMP 170
#define EXTRUDE_MAXLENGTH (X_MAX_LENGTH+Y_MAX_LENGTH) //prevent extrusion of very large distances.
//===========================================================================
//=============================Mechanical Settings===========================
//===========================================================================
// Uncomment the following line to enable CoreXY kinematics
// #define COREXY
// corse Endstop Settings
#define ENDSTOPPULLUPS // Comment this out (using // at the start of the line) to disable the endstop pullup resistors
#ifndef ENDSTOPPULLUPS
// fine Enstop settings: Individual Pullups. will be ignord if ENDSTOPPULLUPS is defined
#define ENDSTOPPULLUP_XMAX
#define ENDSTOPPULLUP_YMAX
#define ENDSTOPPULLUP_ZMAX
#define ENDSTOPPULLUP_XMIN
#define ENDSTOPPULLUP_YMIN
//#define ENDSTOPPULLUP_ZMIN
#endif
#ifdef ENDSTOPPULLUPS
#define ENDSTOPPULLUP_XMAX
#define ENDSTOPPULLUP_YMAX
#define ENDSTOPPULLUP_ZMAX
#define ENDSTOPPULLUP_XMIN
#define ENDSTOPPULLUP_YMIN
#define ENDSTOPPULLUP_ZMIN
#endif
// The pullups are needed if you directly connect a mechanical endswitch between the signal and ground pins.
const bool X_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops.
const bool Y_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops.
const bool Z_ENDSTOPS_INVERTING = true; // set to true to invert the logic of the endstops.
//#define DISABLE_MAX_ENDSTOPS
// For Inverting Stepper Enable Pins (Active Low) use 0, Non Inverting (Active High) use 1
#define X_ENABLE_ON 0
#define Y_ENABLE_ON 0
#define Z_ENABLE_ON 0
#define E_ENABLE_ON 0 // For all extruders
// Disables axis when it's not being used.
#define DISABLE_X false
#define DISABLE_Y false
#define DISABLE_Z false
#define DISABLE_E false // For all extruders
#define INVERT_X_DIR true // for Mendel set to false, for Orca set to true
#define INVERT_Y_DIR false // for Mendel set to true, for Orca set to false
#define INVERT_Z_DIR true // for Mendel set to false, for Orca set to true
#define INVERT_E0_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false
#define INVERT_E1_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false
#define INVERT_E2_DIR false // for direct drive extruder v9 set to true, for geared extruder set to false
// ENDSTOP SETTINGS:
// Sets direction of endstops when homing; 1=MAX, -1=MIN
#define X_HOME_DIR -1
#define Y_HOME_DIR -1
#define Z_HOME_DIR -1
#define min_software_endstops true //If true, axis won't move to coordinates less than HOME_POS.
#define max_software_endstops true //If true, axis won't move to coordinates greater than the defined lengths below.
// Travel limits after homing
#define X_MAX_POS 205
#define X_MIN_POS 0
#define Y_MAX_POS 205
#define Y_MIN_POS 0
#define Z_MAX_POS 200
#define Z_MIN_POS 0
#define X_MAX_LENGTH (X_MAX_POS - X_MIN_POS)
#define Y_MAX_LENGTH (Y_MAX_POS - Y_MIN_POS)
#define Z_MAX_LENGTH (Z_MAX_POS - Z_MIN_POS)
// The position of the homing switches. Use MAX_LENGTH * -0.5 if the center should be 0, 0, 0
#define X_HOME_POS 0
#define Y_HOME_POS 0
#define Z_HOME_POS 0
//// MOVEMENT SETTINGS
#define NUM_AXIS 4 // The axis order in all axis related arrays is X, Y, Z, E
#define HOMING_FEEDRATE {50*60, 50*60, 4*60, 0} // set the homing speeds (mm/min)
// default settings
#define DEFAULT_AXIS_STEPS_PER_UNIT {78.7402,78.7402,200*8/3,760*1.1} // default steps per unit for ultimaker
#define DEFAULT_MAX_FEEDRATE {500, 500, 5, 45} // (mm/sec)
#define DEFAULT_MAX_ACCELERATION {9000,9000,100,10000} // X, Y, Z, E maximum start speed for accelerated moves. E default values are good for skeinforge 40+, for older versions raise them a lot.
#define DEFAULT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for printing moves
#define DEFAULT_RETRACT_ACCELERATION 3000 // X, Y, Z and E max acceleration in mm/s^2 for r retracts
//
#define DEFAULT_XYJERK 20.0 // (mm/sec)
#define DEFAULT_ZJERK 0.4 // (mm/sec)
#define DEFAULT_EJERK 5.0 // (mm/sec)
//===========================================================================
//=============================Additional Features===========================
//===========================================================================
// EEPROM
// the microcontroller can store settings in the EEPROM, e.g. max velocity...
// M500 - stores paramters in EEPROM
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
//define this to enable eeprom support
//#define EEPROM_SETTINGS
//to disable EEPROM Serial responses and decrease program space by ~1700 byte: comment this out:
// please keep turned on if you can.
//#define EEPROM_CHITCHAT
//LCD and SD support
//#define ULTRA_LCD //general lcd support, also 16x2
//#define SDSUPPORT // Enable SD Card Support in Hardware Console
//#define ULTIMAKERCONTROLLER //as available from the ultimaker online store.
//#define ULTIPANEL //the ultipanel as on thingiverse
#ifdef ULTIMAKERCONTROLLER //automatic expansion
#define ULTIPANEL
#define NEWPANEL
#endif
#ifdef ULTIPANEL
// #define NEWPANEL //enable this if you have a click-encoder panel
#define SDSUPPORT
#define ULTRA_LCD
#define LCD_WIDTH 20
#define LCD_HEIGHT 4
// Preheat Constants
#define PLA_PREHEAT_HOTEND_TEMP 180
#define PLA_PREHEAT_HPB_TEMP 70
#define PLA_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255
#define ABS_PREHEAT_HOTEND_TEMP 240
#define ABS_PREHEAT_HPB_TEMP 100
#define ABS_PREHEAT_FAN_SPEED 255 // Insert Value between 0 and 255
#else //no panel but just lcd
#ifdef ULTRA_LCD
#define LCD_WIDTH 16
#define LCD_HEIGHT 2
#endif
#endif
// Increase the FAN pwm frequency. Removes the PWM noise but increases heating in the FET/Arduino
//#define FAST_PWM_FAN
// M240 Triggers a camera by emulating a Canon RC-1 Remote
// Data from: http://www.doc-diy.net/photo/rc-1_hacked/
// #define PHOTOGRAPH_PIN 23
// SF send wrong arc g-codes when using Arc Point as fillet procedure
//#define SF_ARC_FIX
#include "Configuration_adv.h"
#include "thermistortables.h"
#endif //__CONFIGURATION_H

@ -0,0 +1,263 @@
#ifndef CONFIGURATION_ADV_H
#define CONFIGURATION_ADV_H
//===========================================================================
//=============================Thermal Settings ============================
//===========================================================================
// Select one of these only to define how the bed temp is read.
//
//#define BED_LIMIT_SWITCHING
#ifdef BED_LIMIT_SWITCHING
#define BED_HYSTERESIS 2 //only disable heating if T>target+BED_HYSTERESIS and enable heating if T>target-BED_HYSTERESIS
#endif
#define BED_CHECK_INTERVAL 5000 //ms
//// Heating sanity check:
// This waits for the watchperiod in milliseconds whenever an M104 or M109 increases the target temperature
// If the temperature has not increased at the end of that period, the target temperature is set to zero.
// It can be reset with another M104/M109
//#define WATCHPERIOD 20000 //20 seconds
// Wait for Cooldown
// This defines if the M109 call should not block if it is cooling down.
// example: From a current temp of 220, you set M109 S200.
// if CooldownNoWait is defined M109 will not wait for the cooldown to finish
#define CooldownNoWait true
#ifdef PIDTEMP
// this adds an experimental additional term to the heatingpower, proportional to the extrusion speed.
// if Kc is choosen well, the additional required power due to increased melting should be compensated.
#define PID_ADD_EXTRUSION_RATE
#ifdef PID_ADD_EXTRUSION_RATE
#define DEFAULT_Kc (1) //heatingpower=Kc*(e_speed)
#endif
#endif
//automatic temperature: The hot end target temperature is calculated by all the buffered lines of gcode.
//The maximum buffered steps/sec of the extruder motor are called "se".
//You enter the autotemp mode by a M109 S<mintemp> T<maxtemp> F<factor>
// the target temperature is set to mintemp+factor*se[steps/sec] and limited by mintemp and maxtemp
// you exit the value by any M109 without F*
// Also, if the temperature is set to a value <mintemp, it is not changed by autotemp.
// on an ultimaker, some initial testing worked with M109 S215 B260 F1 in the start.gcode
#define AUTOTEMP
#ifdef AUTOTEMP
#define AUTOTEMP_OLDWEIGHT 0.98
#endif
// extruder run-out prevention.
//if the machine is idle, and the temperature over MINTEMP, every couple of SECONDS some filament is extruded
//#define EXTRUDER_RUNOUT_PREVENT
#define EXTRUDER_RUNOUT_MINTEMP 190
#define EXTRUDER_RUNOUT_SECONDS 30.
#define EXTRUDER_RUNOUT_ESTEPS 14. //mm filament
#define EXTRUDER_RUNOUT_SPEED 1500. //extrusion speed
#define EXTRUDER_RUNOUT_EXTRUDE 100
//These defines help to calibrate the AD595 sensor in case you get wrong temperature measurements.
//The measured temperature is defined as "actualTemp = (measuredTemp * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET"
#define TEMP_SENSOR_AD595_OFFSET 0.0
#define TEMP_SENSOR_AD595_GAIN 1.0
//This is for controlling a fan to cool down the stepper drivers
//it will turn on when any driver is enabled
//and turn off after the set amount of seconds from last driver being disabled again
//#define CONTROLLERFAN_PIN 23 //Pin used for the fan to cool controller, comment out to disable this function
#define CONTROLLERFAN_SEC 60 //How many seconds, after all motors were disabled, the fan should run
//===========================================================================
//=============================Mechanical Settings===========================
//===========================================================================
// This defines the number of extruders
#define EXTRUDERS 1
#define ENDSTOPS_ONLY_FOR_HOMING // If defined the endstops will only be used for homing
//#define Z_LATE_ENABLE // Enable Z the last moment. Needed if your Z driver overheats.
// A single Z stepper driver is usually used to drive 2 stepper motors.
// Uncomment this define to utilize a separate stepper driver for each Z axis motor.
// Only a few motherboards support this, like RAMPS, which have dual extruder support (the 2nd, often unused, extruder driver is used
// to control the 2nd Z axis stepper motor). The pins are currently only defined for a RAMPS motherboards.
// On a RAMPS (or other 5 driver) motherboard, using this feature will limit you to using 1 extruder.
//#define Z_DUAL_STEPPER_DRIVERS
#ifdef Z_DUAL_STEPPER_DRIVERS
#undef EXTRUDERS
#define EXTRUDERS 1
#endif
//homing hits the endstop, then retracts by this distance, before it tries to slowly bump again:
#define X_HOME_RETRACT_MM 5
#define Y_HOME_RETRACT_MM 5
#define Z_HOME_RETRACT_MM 1
//#define QUICK_HOME //if this is defined, if both x and y are to be homed, a diagonal move will be performed initially.
#define AXIS_RELATIVE_MODES {false, false, false, false}
#define MAX_STEP_FREQUENCY 40000 // Max step frequency for Ultimaker (5000 pps / half step)
//By default pololu step drivers require an active high signal. However, some high power drivers require an active low signal as step.
#define INVERT_X_STEP_PIN false
#define INVERT_Y_STEP_PIN false
#define INVERT_Z_STEP_PIN false
#define INVERT_E_STEP_PIN false
//default stepper release if idle
#define DEFAULT_STEPPER_DEACTIVE_TIME 60
#define DEFAULT_MINIMUMFEEDRATE 0.0 // minimum feedrate
#define DEFAULT_MINTRAVELFEEDRATE 0.0
// minimum time in microseconds that a movement needs to take if the buffer is emptied.
#define DEFAULT_MINSEGMENTTIME 20000
// If defined the movements slow down when the look ahead buffer is only half full
#define SLOWDOWN
// Frequency limit
// See nophead's blog for more info
// Not working O
//#define XY_FREQUENCY_LIMIT 15
// Minimum planner junction speed. Sets the default minimum speed the planner plans for at the end
// of the buffer and all stops. This should not be much greater than zero and should only be changed
// if unwanted behavior is observed on a user's machine when running at very slow speeds.
#define MINIMUM_PLANNER_SPEED 0.05// (mm/sec)
//===========================================================================
//=============================Additional Features===========================
//===========================================================================
#define SD_FINISHED_STEPPERRELEASE true //if sd support and the file is finished: disable steppers?
#define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // no z because of layer shift.
// The hardware watchdog should halt the Microcontroller, in case the firmware gets stuck somewhere. However:
// the Watchdog is not working well, so please only enable this for testing
// this enables the watchdog interrupt.
//#define USE_WATCHDOG
//#ifdef USE_WATCHDOG
// you cannot reboot on a mega2560 due to a bug in he bootloader. Hence, you have to reset manually, and this is done hereby:
//#define RESET_MANUAL
//#define WATCHDOG_TIMEOUT 4 //seconds
//#endif
// extruder advance constant (s2/mm3)
//
// advance (steps) = STEPS_PER_CUBIC_MM_E * EXTUDER_ADVANCE_K * cubic mm per second ^ 2
//
// hooke's law says: force = k * distance
// bernoulli's priniciple says: v ^ 2 / 2 + g . h + pressure / density = constant
// so: v ^ 2 is proportional to number of steps we advance the extruder
//#define ADVANCE
#ifdef ADVANCE
#define EXTRUDER_ADVANCE_K .0
#define D_FILAMENT 2.85
#define STEPS_MM_E 836
#define EXTRUTION_AREA (0.25 * D_FILAMENT * D_FILAMENT * 3.14159)
#define STEPS_PER_CUBIC_MM_E (axis_steps_per_unit[E_AXIS]/ EXTRUTION_AREA)
#endif // ADVANCE
// Arc interpretation settings:
#define MM_PER_ARC_SEGMENT 1
#define N_ARC_CORRECTION 25
const int dropsegments=5; //everything with less than this number of steps will be ignored as move and joined with the next movement
// If you are using a RAMPS board or cheap E-bay purchased boards that do not detect when an SD card is inserted
// You can get round this by connecting a push button or single throw switch to the pin defined as SDCARDCARDDETECT
// in the pins.h file. When using a push button pulling the pin to ground this will need inverted. This setting should
// be commented out otherwise
#define SDCARDDETECTINVERTED
#ifdef ULTIPANEL
#undef SDCARDDETECTINVERTED
#endif
//===========================================================================
//=============================Buffers ============================
//===========================================================================
// The number of linear motions that can be in the plan at any give time.
// THE BLOCK_BUFFER_SIZE NEEDS TO BE A POWER OF 2, i.g. 8,16,32 because shifts and ors are used to do the ringbuffering.
#if defined SDSUPPORT
#define BLOCK_BUFFER_SIZE 16 // SD,LCD,Buttons take more memory, block buffer needs to be smaller
#else
#define BLOCK_BUFFER_SIZE 16 // maximize block buffer
#endif
//The ASCII buffer for recieving from the serial:
#define MAX_CMD_SIZE 96
#define BUFSIZE 4
// Firmware based and LCD controled retract
// M207 and M208 can be used to define parameters for the retraction.
// The retraction can be called by the slicer using G10 and G11
// until then, intended retractions can be detected by moves that only extrude and the direction.
// the moves are than replaced by the firmware controlled ones.
// #define FWRETRACT //ONLY PARTIALLY TESTED
#define MIN_RETRACT 0.1 //minimum extruded mm to accept a automatic gcode retraction attempt
//===========================================================================
//============================= Define Defines ============================
//===========================================================================
#if TEMP_SENSOR_0 > 0
#define THERMISTORHEATER_0 TEMP_SENSOR_0
#define HEATER_0_USES_THERMISTOR
#endif
#if TEMP_SENSOR_1 > 0
#define THERMISTORHEATER_1 TEMP_SENSOR_1
#define HEATER_1_USES_THERMISTOR
#endif
#if TEMP_SENSOR_2 > 0
#define THERMISTORHEATER_2 TEMP_SENSOR_2
#define HEATER_2_USES_THERMISTOR
#endif
#if TEMP_SENSOR_BED > 0
#define THERMISTORBED TEMP_SENSOR_BED
#define BED_USES_THERMISTOR
#endif
#if TEMP_SENSOR_0 == -1
#define HEATER_0_USES_AD595
#endif
#if TEMP_SENSOR_1 == -1
#define HEATER_1_USES_AD595
#endif
#if TEMP_SENSOR_2 == -1
#define HEATER_2_USES_AD595
#endif
#if TEMP_SENSOR_BED == -1
#define BED_USES_AD595
#endif
#if TEMP_SENSOR_0 == -2
#define HEATER_0_USES_MAX6675
#endif
#if TEMP_SENSOR_0 == 0
#undef HEATER_0_MINTEMP
#undef HEATER_0_MAXTEMP
#endif
#if TEMP_SENSOR_1 == 0
#undef HEATER_1_MINTEMP
#undef HEATER_1_MAXTEMP
#endif
#if TEMP_SENSOR_2 == 0
#undef HEATER_2_MINTEMP
#undef HEATER_2_MAXTEMP
#endif
#if TEMP_SENSOR_BED == 0
#undef BED_MINTEMP
#undef BED_MAXTEMP
#endif
#endif //__CONFIGURATION_ADV_H

@ -0,0 +1,232 @@
#ifndef EEPROM_H
#define EEPROM_H
#include "Marlin.h"
#include "planner.h"
#include "temperature.h"
//#include <EEPROM.h>
int plaPreheatHotendTemp;
int plaPreheatHPBTemp;
int plaPreheatFanSpeed;
int absPreheatHotendTemp;
int absPreheatHPBTemp;
int absPreheatFanSpeed;
template <class T> int EEPROM_writeAnything(int &ee, const T& value)
{
const byte* p = (const byte*)(const void*)&value;
int i;
for (i = 0; i < (int)sizeof(value); i++)
eeprom_write_byte((unsigned char *)ee++, *p++);
return i;
}
template <class T> int EEPROM_readAnything(int &ee, T& value)
{
byte* p = (byte*)(void*)&value;
int i;
for (i = 0; i < (int)sizeof(value); i++)
*p++ = eeprom_read_byte((unsigned char *)ee++);
return i;
}
//======================================================================================
#define EEPROM_OFFSET 100
// IMPORTANT: Whenever there are changes made to the variables stored in EEPROM
// in the functions below, also increment the version number. This makes sure that
// the default values are used whenever there is a change to the data, to prevent
// wrong data being written to the variables.
// ALSO: always make sure the variables in the Store and retrieve sections are in the same order.
#define EEPROM_VERSION "V07"
inline void EEPROM_StoreSettings()
{
#ifdef EEPROM_SETTINGS
char ver[4]= "000";
int i=EEPROM_OFFSET;
EEPROM_writeAnything(i,ver); // invalidate data first
EEPROM_writeAnything(i,axis_steps_per_unit);
EEPROM_writeAnything(i,max_feedrate);
EEPROM_writeAnything(i,max_acceleration_units_per_sq_second);
EEPROM_writeAnything(i,acceleration);
EEPROM_writeAnything(i,retract_acceleration);
EEPROM_writeAnything(i,minimumfeedrate);
EEPROM_writeAnything(i,mintravelfeedrate);
EEPROM_writeAnything(i,minsegmenttime);
EEPROM_writeAnything(i,max_xy_jerk);
EEPROM_writeAnything(i,max_z_jerk);
EEPROM_writeAnything(i,max_e_jerk);
EEPROM_writeAnything(i,add_homeing);
EEPROM_writeAnything(i,plaPreheatHotendTemp);
EEPROM_writeAnything(i,plaPreheatHPBTemp);
EEPROM_writeAnything(i,plaPreheatFanSpeed);
EEPROM_writeAnything(i,absPreheatHotendTemp);
EEPROM_writeAnything(i,absPreheatHPBTemp);
EEPROM_writeAnything(i,absPreheatFanSpeed);
#ifdef PIDTEMP
EEPROM_writeAnything(i,Kp);
EEPROM_writeAnything(i,Ki);
EEPROM_writeAnything(i,Kd);
#else
EEPROM_writeAnything(i,3000);
EEPROM_writeAnything(i,0);
EEPROM_writeAnything(i,0);
#endif
char ver2[4]=EEPROM_VERSION;
i=EEPROM_OFFSET;
EEPROM_writeAnything(i,ver2); // validate data
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Settings Stored");
#endif //EEPROM_SETTINGS
}
inline void EEPROM_printSettings()
{ // if def=true, the default values will be used
// #ifdef EEPROM_SETTINGS
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Steps per unit:");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M92 X",axis_steps_per_unit[0]);
SERIAL_ECHOPAIR(" Y",axis_steps_per_unit[1]);
SERIAL_ECHOPAIR(" Z",axis_steps_per_unit[2]);
SERIAL_ECHOPAIR(" E",axis_steps_per_unit[3]);
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Maximum feedrates (mm/s):");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M203 X",max_feedrate[0]);
SERIAL_ECHOPAIR(" Y",max_feedrate[1] );
SERIAL_ECHOPAIR(" Z", max_feedrate[2] );
SERIAL_ECHOPAIR(" E", max_feedrate[3]);
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Maximum Acceleration (mm/s2):");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M201 X" ,max_acceleration_units_per_sq_second[0] );
SERIAL_ECHOPAIR(" Y" , max_acceleration_units_per_sq_second[1] );
SERIAL_ECHOPAIR(" Z" ,max_acceleration_units_per_sq_second[2] );
SERIAL_ECHOPAIR(" E" ,max_acceleration_units_per_sq_second[3]);
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Acceleration: S=acceleration, T=retract acceleration");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M204 S",acceleration );
SERIAL_ECHOPAIR(" T" ,retract_acceleration);
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Advanced variables: S=Min feedrate (mm/s), T=Min travel feedrate (mm/s), B=minimum segment time (ms), X=maximum xY jerk (mm/s), Z=maximum Z jerk (mm/s)");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M205 S",minimumfeedrate );
SERIAL_ECHOPAIR(" T" ,mintravelfeedrate );
SERIAL_ECHOPAIR(" B" ,minsegmenttime );
SERIAL_ECHOPAIR(" X" ,max_xy_jerk );
SERIAL_ECHOPAIR(" Z" ,max_z_jerk);
SERIAL_ECHOPAIR(" E" ,max_e_jerk);
SERIAL_ECHOLN("");
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Home offset (mm):");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M206 X",add_homeing[0] );
SERIAL_ECHOPAIR(" Y" ,add_homeing[1] );
SERIAL_ECHOPAIR(" Z" ,add_homeing[2] );
SERIAL_ECHOLN("");
#ifdef PIDTEMP
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("PID settings:");
SERIAL_ECHO_START;
SERIAL_ECHOPAIR(" M301 P",Kp);
SERIAL_ECHOPAIR(" I" ,Ki/PID_dT);
SERIAL_ECHOPAIR(" D" ,Kd*PID_dT);
SERIAL_ECHOLN("");
#endif
// #endif
}
inline void EEPROM_RetrieveSettings(bool def=false)
{ // if def=true, the default values will be used
#ifdef EEPROM_SETTINGS
int i=EEPROM_OFFSET;
char stored_ver[4];
char ver[4]=EEPROM_VERSION;
EEPROM_readAnything(i,stored_ver); //read stored version
// SERIAL_ECHOLN("Version: [" << ver << "] Stored version: [" << stored_ver << "]");
if ((!def)&&(strncmp(ver,stored_ver,3)==0))
{ // version number match
EEPROM_readAnything(i,axis_steps_per_unit);
EEPROM_readAnything(i,max_feedrate);
EEPROM_readAnything(i,max_acceleration_units_per_sq_second);
EEPROM_readAnything(i,acceleration);
EEPROM_readAnything(i,retract_acceleration);
EEPROM_readAnything(i,minimumfeedrate);
EEPROM_readAnything(i,mintravelfeedrate);
EEPROM_readAnything(i,minsegmenttime);
EEPROM_readAnything(i,max_xy_jerk);
EEPROM_readAnything(i,max_z_jerk);
EEPROM_readAnything(i,max_e_jerk);
EEPROM_readAnything(i,add_homeing);
EEPROM_readAnything(i,plaPreheatHotendTemp);
EEPROM_readAnything(i,plaPreheatHPBTemp);
EEPROM_readAnything(i,plaPreheatFanSpeed);
EEPROM_readAnything(i,absPreheatHotendTemp);
EEPROM_readAnything(i,absPreheatHPBTemp);
EEPROM_readAnything(i,absPreheatFanSpeed);
#ifndef PIDTEMP
float Kp,Ki,Kd;
#endif
EEPROM_readAnything(i,Kp);
EEPROM_readAnything(i,Ki);
EEPROM_readAnything(i,Kd);
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM("Stored settings retreived:");
}
else
#endif
{
float tmp1[]=DEFAULT_AXIS_STEPS_PER_UNIT;
float tmp2[]=DEFAULT_MAX_FEEDRATE;
long tmp3[]=DEFAULT_MAX_ACCELERATION;
for (short i=0;i<4;i++)
{
axis_steps_per_unit[i]=tmp1[i];
max_feedrate[i]=tmp2[i];
max_acceleration_units_per_sq_second[i]=tmp3[i];
}
acceleration=DEFAULT_ACCELERATION;
retract_acceleration=DEFAULT_RETRACT_ACCELERATION;
minimumfeedrate=DEFAULT_MINIMUMFEEDRATE;
minsegmenttime=DEFAULT_MINSEGMENTTIME;
mintravelfeedrate=DEFAULT_MINTRAVELFEEDRATE;
max_xy_jerk=DEFAULT_XYJERK;
max_z_jerk=DEFAULT_ZJERK;
max_e_jerk=DEFAULT_EJERK;
add_homeing[0] = add_homeing[1] = add_homeing[2] = 0;
SERIAL_ECHO_START;
SERIAL_ECHOLN("Using Default settings:");
#ifdef ULTIPANEL
plaPreheatHotendTemp = PLA_PREHEAT_HOTEND_TEMP;
plaPreheatHPBTemp = PLA_PREHEAT_HPB_TEMP;
plaPreheatFanSpeed = PLA_PREHEAT_FAN_SPEED;
absPreheatHotendTemp = ABS_PREHEAT_HOTEND_TEMP;
absPreheatHPBTemp = ABS_PREHEAT_HPB_TEMP;
absPreheatFanSpeed = ABS_PREHEAT_FAN_SPEED;
#endif
}
#ifdef EEPROM_CHITCHAT
EEPROM_printSettings();
#endif
}
#endif

@ -0,0 +1,101 @@
##############################################################
Gen7-644-16.name=Gen7 with ATmega644 and 16 MHz
Gen7-644-16.upload.protocol=stk500v2
Gen7-644-16.upload.maximum_size=63488
Gen7-644-16.upload.speed=115200
Gen7-644-16.bootloader.low_fuses=0xF7
Gen7-644-16.bootloader.high_fuses=0xD4
Gen7-644-16.bootloader.extended_fuses=0xFD
Gen7-644-16.bootloader.path=Gen7
Gen7-644-16.bootloader.file=bootloader-644-16MHz.hex
Gen7-644-16.bootloader.unlock_bits=0x3F
Gen7-644-16.bootloader.lock_bits=0x0F
Gen7-644-16.build.mcu=atmega644
Gen7-644-16.build.f_cpu=16000000L
Gen7-644-16.build.core=arduino
##############################################################
Gen7-644-20.name=Gen7 with ATmega644 and 20 MHz
Gen7-644-20.upload.protocol=stk500v2
Gen7-644-20.upload.maximum_size=63488
Gen7-644-20.upload.speed=115200
Gen7-644-20.bootloader.low_fuses=0xF7
Gen7-644-20.bootloader.high_fuses=0xD4
Gen7-644-20.bootloader.extended_fuses=0xFD
Gen7-644-20.bootloader.path=Gen7
Gen7-644-20.bootloader.file=bootloader-644-20MHz.hex
Gen7-644-20.bootloader.unlock_bits=0x3F
Gen7-644-20.bootloader.lock_bits=0x0F
Gen7-644-20.build.mcu=atmega644
Gen7-644-20.build.f_cpu=20000000L
Gen7-644-20.build.core=arduino
##############################################################
Gen7-644P-16.name=Gen7 with ATmega644P and 16 MHz
Gen7-644P-16.upload.protocol=stk500v2
Gen7-644P-16.upload.maximum_size=63488
Gen7-644P-16.upload.speed=115200
Gen7-644P-16.bootloader.low_fuses=0xF7
Gen7-644P-16.bootloader.high_fuses=0xD4
Gen7-644P-16.bootloader.extended_fuses=0xFD
Gen7-644P-16.bootloader.path=Gen7
Gen7-644P-16.bootloader.file=bootloader-644P-16MHz.hex
Gen7-644P-16.bootloader.unlock_bits=0x3F
Gen7-644P-16.bootloader.lock_bits=0x0F
Gen7-644P-16.build.mcu=atmega644p
Gen7-644P-16.build.f_cpu=16000000L
Gen7-644P-16.build.core=arduino
##############################################################
Gen7-644P-20.name=Gen7 with ATmega644P and 20 MHz
Gen7-644P-20.upload.protocol=stk500v2
Gen7-644P-20.upload.maximum_size=63488
Gen7-644P-20.upload.speed=115200
Gen7-644P-20.bootloader.low_fuses=0xF7
Gen7-644P-20.bootloader.high_fuses=0xD4
Gen7-644P-20.bootloader.extended_fuses=0xFD
Gen7-644P-20.bootloader.path=Gen7
Gen7-644P-20.bootloader.file=bootloader-644P-20MHz.hex
Gen7-644P-20.bootloader.unlock_bits=0x3F
Gen7-644P-20.bootloader.lock_bits=0x0F
Gen7-644P-20.build.mcu=atmega644p
Gen7-644P-20.build.f_cpu=20000000L
Gen7-644P-20.build.core=arduino
##############################################################
Gen7-1284p-16.name=Gen7 with ATmega1284 and 16 MHz
Gen7-1284p-16.upload.protocol=stk500v2
Gen7-1284p-16.upload.maximum_size=129024
Gen7-1284p-16.upload.speed=115200
Gen7-1284p-16.bootloader.low_fuses=0xF7
Gen7-1284p-16.bootloader.high_fuses=0xD4
Gen7-1284p-16.bootloader.extended_fuses=0xFD
Gen7-1284p-16.bootloader.path=Gen7
Gen7-1284p-16.bootloader.file=bootloader-1284P-16MHz.hex
Gen7-1284p-16.bootloader.unlock_bits=0x3F
Gen7-1284p-16.bootloader.lock_bits=0x2F
Gen7-1284p-16.build.mcu=atmega1284p
Gen7-1284p-16.build.f_cpu=16000000L
Gen7-1284p-16.build.core=arduino
##############################################################
Gen7-1284p-20.name=Gen7 with ATmega1284 and 20 MHz
Gen7-1284p-20.upload.protocol=stk500v2
Gen7-1284p-20.upload.maximum_size=129024
Gen7-1284p-20.upload.speed=115200
Gen7-1284p-20.bootloader.low_fuses=0xF7
Gen7-1284p-20.bootloader.high_fuses=0xD4
Gen7-1284p-20.bootloader.extended_fuses=0xFD
Gen7-1284p-20.bootloader.path=Gen7
Gen7-1284p-20.bootloader.file=bootloader-1284P-16MHz.hex
Gen7-1284p-20.bootloader.unlock_bits=0x3F
Gen7-1284p-20.bootloader.lock_bits=0x2F
Gen7-1284p-20.build.mcu=atmega1284p
Gen7-1284p-20.build.f_cpu=20000000L
Gen7-1284p-20.build.core=arduino

@ -0,0 +1,113 @@
:020000021000EC
:10F8000011241FBE8FEF90E49EBF8DBF01C32F92C6
:10F810003F924F925F926F927F928F929F92AF92A0
:10F82000BF92CF92DF92EF92FF920F931F93DF93DD
:10F83000CF93CDB7DEB7C252D1400FB6F894DEBF3A
:10F840000FBECDBF44245524DD24C25EDE4F188296
:10F85000CE51D1408824992454013AC20E9428FFF5
:10F86000282F133059F1143028F4113081F0123060
:10F8700000F507C0153081F1153030F1163071F701
:10F880003DC08B3159F711E05BE1D52EE7CF8130D8
:10F8900041F0C25EDE4F3881CE51D140831709F06E
:10F8A00019C2D226C25EDE4F2883CE51D14012E06B
:10F8B000D5CFF82EEE24D82613E0D0CF90E0E82A5A
:10F8C000F92AD22614E0CACF8E3009F003C2D82616
:10F8D00015E044245524C2CFE1E0F0E0EC0FFD1F19
:10F8E000E40DF51D80830894411C511CD8264E144C
:10F8F0005F0409F0B3CF720116E0B0CF8D1509F0A7
:10F90000E9C1EAC1CC2447C08D81803311F090E079
:10F910000AC08F81882311F49EE105C0813011F067
:10F9200095E001C097E91A821B828D818C838E81BC
:10F930008D839E831F8247E0E42EF12C88C11A82BA
:10F9400068E06B8383E58C8394E59D83EBE4EE8331
:10F9500085E38F8380E3888789878FE58A8782E3C1
:10F960008B873BE0E32EF12C72C18A81813941F013
:10F97000823941F0803911F48FE005C080E003C086
:10F9800082E001C08AE01A828B8323E0E22EF12C10
:10F990005EC1CC24C3941A8292E0E92EF12C58C1A6
:10F9A0008D81882311F48EE128C0813011F085E02B
:10F9B00024C087E922C01A8229E0E1E0F0E0209328
:10F9C000570084911BC08B81803589F48C818830ED
:10F9D00039F439E0E2E0F0E03093570084910DC053
:10F9E00069E0E0E0F0E060935700849106C099E0A0
:10F9F000E3E0F0E09093570084911A828B831C829D
:10FA000084E0E82EF12C23C18A8190E0A0E0B0E0F0
:10FA1000B82EAA24992488248B8190E0A0E0B0E03D
:10FA2000DC0199278827882A992AAA2ABB2A8D814E
:10FA300090E0A0E0B0E0882A992AAA2ABB2A8C810B
:10FA400090E0A0E0B0E0BA2FA92F982F8827882A4D
:10FA5000992AAA2ABB2A88C0EA81C05EDE4FE883C1
:10FA6000C052D140C15EDE4F1882CF51D1408B8150
:10FA7000A82FB0E0C15EDE4F28813981CF51D1403F
:10FA8000A22BB32B933109F042C075016401CC0C59
:10FA9000DD1CEE1CFF1C33E0F601E0925B003093AE
:10FAA0005700E89507B600FCFDCF8E01055F1F4F9C
:10FAB000F801808161810E5F1F4FA5019401220F23
:10FAC000331F441F551F362E222490E0822993298C
:10FAD00061E00C01F90140935B0060935700E895E9
:10FAE00011240894811C911CA11CB11C129701F7D0
:10FAF00085E0F601E0925B0080935700E89507B639
:10FB000000FCFDCF81E180935700E8952DC0FE01F8
:10FB10003B9620E030E040E050E011977D0100E0AE
:10FB200010E00894E11CF11C011D111D6081F99980
:10FB3000FECF1FBAC901880D991D92BD81BD60BD60
:10FB40000FB6F894FA9AF99A0FBE2F5F3F4F4F4FB6
:10FB50005F4F2E153F054007510711F03196E6CF54
:10FB6000820E931EA41EB51E1A826EC09A81CE5DAF
:10FB7000DE4F9883C252D140CF5DDE4F1882C15212
:10FB8000D1408B81C82EDD24CF5DDE4FE881F98125
:10FB9000C152D140CE2ADF2A1A8289818431E1F410
:10FBA0009601BE016D5F7F4FD501C401880F991F7B
:10FBB000AA1FBB1FABBFFC0187919691FB018083FD
:10FBC00091836E5F7F4F0894811C911CA11CB11C16
:10FBD0002250304049F72EC0BE016D5F7F4F20E0BC
:10FBE00030E040E050E00894C108D108760100E020
:10FBF00010E00894C11CD11C0894E11CF11C011DEB
:10FC0000111DF999FECFC901880D991D92BD81BDC5
:10FC1000F89A80B5FB018193BF012F5F3F4F4F4F93
:10FC20005F4F2E153F054007510759F7820E931E6F
:10FC3000A41EB51E23E0E22EF12CEC0CFD1CFB01F2
:10FC4000108205C080EC8A8392E0E92EF12CCC244E
:10FC50008BE10E94C7FEC25EDE4F8881CE51D1404B
:10FC60000E94C7FE8F2D0E94C7FE8E2D0E94C7FEE8
:10FC70008EE00E94C7FE85E1D82EC25EDE4FF8817D
:10FC8000CE51D140DF26DE24DF243E010894611CE2
:10FC9000711C0AC0F30111913F01812F0E94C7FE20
:10FCA000D1260894E108F108E114F10499F78D2DAB
:10FCB0000E94C7FECC2009F044C0C25EDE4FF8812E
:10FCC000CE51D140FF5FC25EDE4FF883CE51D140AE
:10FCD000EE24FF2410E0C2CD9981933109F4BCCE0B
:10FCE0009431B0F4933009F440CE943038F491302C
:10FCF00009F425CE923009F0A5CF04CE903109F455
:10FD000001CE913109F445CE963009F09BCF7CCEDF
:10FD1000983109F458CE993150F4953109F49CCEBC
:10FD2000953108F423CF963109F08CCF1FCF9B314A
:10FD300009F436CE9D3109F4E7CD9A3109F082CF2E
:10FD40003ACECE5DDE4F0FB6F894DEBF0FBECDBF0C
:10FD5000CF91DF911F910F91FF90EF90DF90CF90A7
:10FD6000BF90AF909F908F907F906F905F904F90DB
:10FD70003F902F9008958091C00087FFFCCF089599
:10FD80008091C00087FFFCCF8091C6000895982F16
:10FD90008091C00085FFFCCF9093C60008959B0121
:10FDA000AC0197FF11C08091C00082608093C000B9
:10FDB00050954095309521953F4F4F4F5F4F60E0F4
:10FDC00074E284EF90E009C08091C0008D7F809341
:10FDD000C00060E072E18AE790E00E9447FF2C5F7C
:10FDE0003F4F4F4F5F4F83E0569547953795279587
:10FDF0008A95D1F7215030403093C5002093C4003C
:10FE0000089518B817B81F921F921F920895FFCF38
:10FE100084B714BE90E083709070892B39F418B8C1
:10FE200017B81F921F921F920895FFCF88E1809309
:10FE3000C10060E07EE38EEF9FEF0E94CFFE0E9444
:10FE400007FC18B817B81F921F921F920895FFCF92
:10FE500020E030E040E050E013C02F5F3F4F4F4FB5
:10FE60005F4F21308AE6380788E1480780E058076D
:10FE700039F418B817B81F921F921F920895FFCF38
:10FE80008091C00087FFE9CF0E94C0FE0895A1E2E3
:10FE90001A2EAA1BBB1BFD010DC0AA1FBB1FEE1F04
:10FEA000FF1FA217B307E407F50720F0A21BB30B4F
:10FEB000E40BF50B661F771F881F991F1A9469F7CB
:10FEC00060957095809590959B01AC01BD01CF0127
:02FED000089593
:040000031000F800F1
:00000001FF

@ -0,0 +1,75 @@
:10F800008FEF90E19EBF8DBF11241FBE5A9A00C09A
:10F81000CDB7DEB7CD51D140DEBFCDBF1092C50010
:10F8200088E08093C40088E18093C100EE24FF2427
:10F8300020E0552400E010E039E0432E9BE0292E23
:10F84000312C2C0E3D1ECFC14150504060407040C5
:10F8500011F43FE206C08091C00087FFF5CF3091E0
:10F86000C600933021F1943028F4913099F0923011
:10F87000C8F407C0953049F1953000F19630D1F5C4
:10F8800035C03B3119F491E02BE134C03F3291F5A2
:10F890003983BBC1313011F0351559F52327532E6B
:10F8A00092E028C0B32FA0E0232793E023C0832F4A
:10F8B00090E0A82BB92B232794E01CC03E30C9F45C
:10F8C000232795E0EE24FF2415C0E1E0F0E0EC0FE3
:10F8D000FD1FEE0DFF1D30830894E11CF11C232752
:10F8E000EA16FB0639F4D70196E004C0321709F492
:10F8F0008CC190E044E755E962E470E0ACCF90E061
:10F9000044C08D81803311F090E00AC08F8188233C
:10F9100011F49EE105C0813011F099E001C096E933
:10F920001A821B828D818C838E818D839E831F82A0
:10F9300047E050E0F4C01A8288E08B8381E48C8336
:10F9400086E58D8382E58E8389E48F8383E58887CE
:10F9500080E589878FE58A8782E38B874BE050E0DB
:10F96000DEC08A81813941F0823941F0803911F459
:10F970008FE005C080E003C082E001C08AE01A8207
:10F980008B8343E050E0CBC091E01A8242E050E02C
:10F99000C7C08D81882311F48EE124C0813011F01D
:10F9A00089E020C086E91EC01A82E1E0F0E04092C2
:10F9B0005700849118C08B81803579F48C81883010
:10F9C00031F4E2E0F0E04092570084910BC0E0E0B7
:10F9D000F0E040925700849105C0E3E0F0E04092EF
:10F9E000570084911A828B831C8244E050E097C0B8
:10F9F000BC80AA248D81082F10E00A291B29000F42
:10FA0000111F1A828AC09A8088248B81682F70E027
:10FA100068297929933109F033C0F7EF0F3F1F07A9
:10FA200010F0A8013FC023E0F80120935700E895AB
:10FA300007B600FCFDCFA801D1018C9111962C9145
:10FA400011971296D22ECC2490E08C299D2921E08A
:10FA5000FA010C0120935700E89511244E5F5F4F87
:10FA60006250704051F725E0F80120935700E89567
:10FA700007B600FCFDCF81E180935700E89512C0E6
:10FA8000A801FB01D10141BD52BD4F5F5F4F8D9178
:10FA900080BDFA9AF99AF999FECF3197A1F7A8019A
:10FAA000460F571F1A828A0138C07A8066248B81DC
:10FAB000A82FB0E0A629B7291A828981843191F450
:10FAC000BD019E012D5F3F4FF80185919491F90191
:10FAD000808391832E5F3F4F0E5F1F4F62507040B7
:10FAE00099F713C0A801BD019E012D5F3F4F41BD95
:10FAF00052BD4F5F5F4FF89A80B5F90181939F0126
:10FB000061507040A1F70A0F1B1FAD014D5F5F4FA1
:10FB1000F901108204C080EC8A8342E050E090E05A
:10FB2000FBE1F093C6008091C00086FFFCCF80917E
:10FB3000C00080648093C0005092C6008091C000D5
:10FB400086FFFCCF8091C00080648093C000652F49
:10FB50005093C6008091C00086FFFCCF8091C0000A
:10FB600080648093C000342F4093C6008091C00011
:10FB700086FFFCCF8091C00080648093C0008EE03F
:10FB80008093C6008091C00086FFFCCF8091C000AA
:10FB900080648093C00025E1252523272627FE01C8
:10FBA000319610C030813093C6008091C00086FF2E
:10FBB000FCCF31968091C00080648093C0002327E1
:10FBC000415050404115510569F72093C60080917E
:10FBD000C00086FFFCCF8091C00080648093C0008D
:10FBE000992349F4539444E755E962E470E090E0C6
:10FBF000A0E0B0E030CE5A9881E180935700E895BC
:10FC000011241F921F920895FFCF9981933109F417
:10FC1000FACE9431C8F4963009F4EACE973050F415
:10FC2000923009F46CCE933009F49BCE913009F0F8
:10FC300072CF81CE913109F4A7CE923108F0E1CE96
:10FC4000903109F068CF5BCE983109F4B4CE993188
:10FC500050F4953109F4D7CE953108F426CF96317A
:10FC600009F059CF22CF9B3109F493CE9C3120F477
:10FC70009A3109F050CF98CE9D3109F442CE9F328F
:06FC800009F049CFB8CFE6
:040000030000F80001
:00000001FF

@ -0,0 +1,75 @@
:10F800008FEF90E19EBF8DBF11241FBE5A9A00C09A
:10F81000CDB7DEB7CD51D140DEBFCDBF1092C50010
:10F820008AE08093C40088E18093C100EE24FF2425
:10F8300020E0552400E010E039E0432E9BE0292E23
:10F84000312C2C0E3D1ECFC14150504060407040C5
:10F8500011F43FE206C08091C00087FFF5CF3091E0
:10F86000C600933021F1943028F4913099F0923011
:10F87000C8F407C0953049F1953000F19630D1F5C4
:10F8800035C03B3119F491E02BE134C03F3291F5A2
:10F890003983BBC1313011F0351559F52327532E6B
:10F8A00092E028C0B32FA0E0232793E023C0832F4A
:10F8B00090E0A82BB92B232794E01CC03E30C9F45C
:10F8C000232795E0EE24FF2415C0E1E0F0E0EC0FE3
:10F8D000FD1FEE0DFF1D30830894E11CF11C232752
:10F8E000EA16FB0639F4D70196E004C0321709F492
:10F8F0008CC190E041ED5AE363E570E0ACCF90E05D
:10F9000044C08D81803311F090E00AC08F8188233C
:10F9100011F49EE105C0813011F099E001C096E933
:10F920001A821B828D818C838E818D839E831F82A0
:10F9300047E050E0F4C01A8288E08B8381E48C8336
:10F9400086E58D8382E58E8389E48F8383E58887CE
:10F9500080E589878FE58A8782E38B874BE050E0DB
:10F96000DEC08A81813941F0823941F0803911F459
:10F970008FE005C080E003C082E001C08AE01A8207
:10F980008B8343E050E0CBC091E01A8242E050E02C
:10F99000C7C08D81882311F48EE124C0813011F01D
:10F9A00089E020C086E91EC01A82E1E0F0E04092C2
:10F9B0005700849118C08B81803579F48C81883010
:10F9C00031F4E2E0F0E04092570084910BC0E0E0B7
:10F9D000F0E040925700849105C0E3E0F0E04092EF
:10F9E000570084911A828B831C8244E050E097C0B8
:10F9F000BC80AA248D81082F10E00A291B29000F42
:10FA0000111F1A828AC09A8088248B81682F70E027
:10FA100068297929933109F033C0F7EF0F3F1F07A9
:10FA200010F0A8013FC023E0F80120935700E895AB
:10FA300007B600FCFDCFA801D1018C9111962C9145
:10FA400011971296D22ECC2490E08C299D2921E08A
:10FA5000FA010C0120935700E89511244E5F5F4F87
:10FA60006250704051F725E0F80120935700E89567
:10FA700007B600FCFDCF81E180935700E89512C0E6
:10FA8000A801FB01D10141BD52BD4F5F5F4F8D9178
:10FA900080BDFA9AF99AF999FECF3197A1F7A8019A
:10FAA000460F571F1A828A0138C07A8066248B81DC
:10FAB000A82FB0E0A629B7291A828981843191F450
:10FAC000BD019E012D5F3F4FF80185919491F90191
:10FAD000808391832E5F3F4F0E5F1F4F62507040B7
:10FAE00099F713C0A801BD019E012D5F3F4F41BD95
:10FAF00052BD4F5F5F4FF89A80B5F90181939F0126
:10FB000061507040A1F70A0F1B1FAD014D5F5F4FA1
:10FB1000F901108204C080EC8A8342E050E090E05A
:10FB2000FBE1F093C6008091C00086FFFCCF80917E
:10FB3000C00080648093C0005092C6008091C000D5
:10FB400086FFFCCF8091C00080648093C000652F49
:10FB50005093C6008091C00086FFFCCF8091C0000A
:10FB600080648093C000342F4093C6008091C00011
:10FB700086FFFCCF8091C00080648093C0008EE03F
:10FB80008093C6008091C00086FFFCCF8091C000AA
:10FB900080648093C00025E1252523272627FE01C8
:10FBA000319610C030813093C6008091C00086FF2E
:10FBB000FCCF31968091C00080648093C0002327E1
:10FBC000415050404115510569F72093C60080917E
:10FBD000C00086FFFCCF8091C00080648093C0008D
:10FBE000992349F4539441ED5AE363E570E090E0C2
:10FBF000A0E0B0E030CE5A9881E180935700E895BC
:10FC000011241F921F920895FFCF9981933109F417
:10FC1000FACE9431C8F4963009F4EACE973050F415
:10FC2000923009F46CCE933009F49BCE913009F0F8
:10FC300072CF81CE913109F4A7CE923108F0E1CE96
:10FC4000903109F068CF5BCE983109F4B4CE993188
:10FC500050F4953109F4D7CE953108F426CF96317A
:10FC600009F059CF22CF9B3109F493CE9C3120F477
:10FC70009A3109F050CF98CE9D3109F442CE9F328F
:06FC800009F049CFB8CFE6
:040000030000F80001
:00000001FF

@ -0,0 +1,75 @@
:10F800008FEF90E19EBF8DBF11241FBE5A9A00C09A
:10F81000CDB7DEB7CD51D140DEBFCDBF1092C50010
:10F8200088E08093C40088E18093C100EE24FF2427
:10F8300020E0552400E010E039E0432E93E0292E2B
:10F84000312C2C0E3D1ECDC14150504060407040C7
:10F8500011F43FE206C08091C00087FFF5CF3091E0
:10F86000C600933021F1943028F4913099F0923011
:10F87000C8F407C0953049F1953000F19630D1F5C4
:10F8800035C03B3119F491E02BE134C03F3291F5A2
:10F890003983B9C1313011F0351559F52327532E6D
:10F8A00092E028C0B32FA0E0232793E023C0832F4A
:10F8B00090E0A82BB92B232794E01CC03E30C9F45C
:10F8C000232795E0EE24FF2415C0E1E0F0E0EC0FE3
:10F8D000FD1FEE0DFF1D30830894E11CF11C232752
:10F8E000EA16FB0639F4D70196E004C0321709F492
:10F8F0008AC190E044E755E962E470E0ACCF90E063
:10F9000044C08D81803311F090E00AC08F8188233C
:10F9100011F49EE105C0813011F09AE001C096E932
:10F920001A821B828D818C838E818D839E831F82A0
:10F9300047E050E0F2C01A8288E08B8381E48C8338
:10F9400086E58D8382E58E8389E48F8383E58887CE
:10F9500080E589878FE58A8782E38B874BE050E0DB
:10F96000DCC08A81813941F0823941F0803911F45B
:10F970008FE005C080E003C082E001C08AE01A8207
:10F980008B8343E050E0C9C091E01A8242E050E02E
:10F99000C5C08D81882311F48EE124C0813011F01F
:10F9A0008AE020C086E91EC01A82E1E0F0E04092C1
:10F9B0005700849118C08B81803579F48C81883010
:10F9C00031F4E2E0F0E04092570084910BC0E0E0B7
:10F9D000F0E040925700849105C0E3E0F0E04092EF
:10F9E000570084911A828B831C8244E050E095C0BA
:10F9F000BC80AA248D81082F10E00A291B29000F42
:10FA0000111F1A8288C09A8088248B81682F70E029
:10FA100068297929933109F034C0F7EF0F3F1F07A8
:10FA200010F0A80141C023E0F80120935700E895A9
:10FA300007B600FCFDCFA801DE011B968C91119644
:10FA40002C9111971296D22ECC2490E08C299D29CE
:10FA500021E0FA010C0120935700E89511244E5F34
:10FA60005F4F6250704051F725E0F8012093570036
:10FA7000E89507B600FCFDCF81E180935700E8953B
:10FA800013C0A801FB01DE011B9641BD52BD4F5FB3
:10FA90005F4F8D9180BDFA9AF99AF999FECF31970F
:10FAA000A1F7A801460F571F1A828A0134C07A8035
:10FAB00066248B81A82FB0E0A629B7291A828981F4
:10FAC000843181F4BD019101F80185919491F9018E
:10FAD000808391832E5F3F4F0E5F1F4F62507040B7
:10FAE00099F711C0A801BD01910141BD52BD4F5F01
:10FAF0005F4FF89A80B5F90181939F016150704082
:10FB0000A1F70A0F1B1FAD014D5F5F4FF901108276
:10FB100004C080EC8A8342E050E090E0FBE1F09387
:10FB2000C6008091C00086FFFCCF8091C000806439
:10FB30008093C0005092C6008091C00086FFFCCF29
:10FB40008091C00080648093C000652F5093C600F0
:10FB50008091C00086FFFCCF8091C00080648093BC
:10FB6000C000342F4093C6008091C00086FFFCCFB8
:10FB70008091C00080648093C0008EE08093C600B6
:10FB80008091C00086FFFCCF8091C000806480938C
:10FB9000C00025E1252523272627FE01319610C028
:10FBA00030813093C6008091C00086FFFCCF319633
:10FBB0008091C00080648093C00023274150504052
:10FBC0004115510569F72093C6008091C00086FF5A
:10FBD000FCCF8091C00080648093C000992349F4D9
:10FBE000539444E755E962E470E090E0A0E0B0E0AF
:10FBF00032CE5A9881E180935700E89511241F92E4
:10FC00001F920895FFCF9981933109F4FCCE94316E
:10FC1000C8F4963009F4ECCE973050F4923009F4E1
:10FC20006ECE933009F49DCE913009F072CF83CE21
:10FC3000913109F4A9CE923108F0E3CE903109F068
:10FC400068CF5DCE983109F4B6CE993150F4953134
:10FC500009F4D9CE953108F42ACF963109F059CF5D
:10FC600026CF9B3109F495CE9C3120F49A3109F0CE
:10FC700050CF9ACE9D3109F444CE9F3209F049CF3E
:02FC8000B8CFFB
:040000030000F80001
:00000001FF

@ -0,0 +1,75 @@
:10F800008FEF90E19EBF8DBF11241FBE5A9A00C09A
:10F81000CDB7DEB7CD51D140DEBFCDBF1092C50010
:10F820008AE08093C40088E18093C100EE24FF2425
:10F8300020E0552400E010E039E0432E93E0292E2B
:10F84000312C2C0E3D1ECDC14150504060407040C7
:10F8500011F43FE206C08091C00087FFF5CF3091E0
:10F86000C600933021F1943028F4913099F0923011
:10F87000C8F407C0953049F1953000F19630D1F5C4
:10F8800035C03B3119F491E02BE134C03F3291F5A2
:10F890003983B9C1313011F0351559F52327532E6D
:10F8A00092E028C0B32FA0E0232793E023C0832F4A
:10F8B00090E0A82BB92B232794E01CC03E30C9F45C
:10F8C000232795E0EE24FF2415C0E1E0F0E0EC0FE3
:10F8D000FD1FEE0DFF1D30830894E11CF11C232752
:10F8E000EA16FB0639F4D70196E004C0321709F492
:10F8F0008AC190E041ED5AE363E570E0ACCF90E05F
:10F9000044C08D81803311F090E00AC08F8188233C
:10F9100011F49EE105C0813011F09AE001C096E932
:10F920001A821B828D818C838E818D839E831F82A0
:10F9300047E050E0F2C01A8288E08B8381E48C8338
:10F9400086E58D8382E58E8389E48F8383E58887CE
:10F9500080E589878FE58A8782E38B874BE050E0DB
:10F96000DCC08A81813941F0823941F0803911F45B
:10F970008FE005C080E003C082E001C08AE01A8207
:10F980008B8343E050E0C9C091E01A8242E050E02E
:10F99000C5C08D81882311F48EE124C0813011F01F
:10F9A0008AE020C086E91EC01A82E1E0F0E04092C1
:10F9B0005700849118C08B81803579F48C81883010
:10F9C00031F4E2E0F0E04092570084910BC0E0E0B7
:10F9D000F0E040925700849105C0E3E0F0E04092EF
:10F9E000570084911A828B831C8244E050E095C0BA
:10F9F000BC80AA248D81082F10E00A291B29000F42
:10FA0000111F1A8288C09A8088248B81682F70E029
:10FA100068297929933109F034C0F7EF0F3F1F07A8
:10FA200010F0A80141C023E0F80120935700E895A9
:10FA300007B600FCFDCFA801DE011B968C91119644
:10FA40002C9111971296D22ECC2490E08C299D29CE
:10FA500021E0FA010C0120935700E89511244E5F34
:10FA60005F4F6250704051F725E0F8012093570036
:10FA7000E89507B600FCFDCF81E180935700E8953B
:10FA800013C0A801FB01DE011B9641BD52BD4F5FB3
:10FA90005F4F8D9180BDFA9AF99AF999FECF31970F
:10FAA000A1F7A801460F571F1A828A0134C07A8035
:10FAB00066248B81A82FB0E0A629B7291A828981F4
:10FAC000843181F4BD019101F80185919491F9018E
:10FAD000808391832E5F3F4F0E5F1F4F62507040B7
:10FAE00099F711C0A801BD01910141BD52BD4F5F01
:10FAF0005F4FF89A80B5F90181939F016150704082
:10FB0000A1F70A0F1B1FAD014D5F5F4FF901108276
:10FB100004C080EC8A8342E050E090E0FBE1F09387
:10FB2000C6008091C00086FFFCCF8091C000806439
:10FB30008093C0005092C6008091C00086FFFCCF29
:10FB40008091C00080648093C000652F5093C600F0
:10FB50008091C00086FFFCCF8091C00080648093BC
:10FB6000C000342F4093C6008091C00086FFFCCFB8
:10FB70008091C00080648093C0008EE08093C600B6
:10FB80008091C00086FFFCCF8091C000806480938C
:10FB9000C00025E1252523272627FE01319610C028
:10FBA00030813093C6008091C00086FFFCCF319633
:10FBB0008091C00080648093C00023274150504052
:10FBC0004115510569F72093C6008091C00086FF5A
:10FBD000FCCF8091C00080648093C000992349F4D9
:10FBE000539441ED5AE363E570E090E0A0E0B0E0AB
:10FBF00032CE5A9881E180935700E89511241F92E4
:10FC00001F920895FFCF9981933109F4FCCE94316E
:10FC1000C8F4963009F4ECCE973050F4923009F4E1
:10FC20006ECE933009F49DCE913009F072CF83CE21
:10FC3000913109F4A9CE923108F0E3CE903109F068
:10FC400068CF5DCE983109F4B6CE993150F4953134
:10FC500009F4D9CE953108F42ACF963109F059CF5D
:10FC600026CF9B3109F495CE9C3120F49A3109F0CE
:10FC700050CF9ACE9D3109F444CE9F3209F049CF3E
:02FC8000B8CFFB
:040000030000F80001
:00000001FF

@ -0,0 +1,239 @@
/*
HardwareSerial.cpp - Hardware serial library for 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
Modified 23 November 2006 by David A. Mellis
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "wiring.h"
#include "wiring_private.h"
#include "HardwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
struct ring_buffer {
unsigned char buffer[RX_BUFFER_SIZE];
int head;
int tail;
};
ring_buffer rx_buffer = { { 0 }, 0, 0 };
#ifdef UDR1
ring_buffer rx_buffer1 = { { 0 }, 0, 0 };
#endif
#ifdef UDR2
ring_buffer rx_buffer2 = { { 0 }, 0, 0 };
#endif
#ifdef UDR3
ring_buffer rx_buffer3 = { { 0 }, 0, 0 };
#endif
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
int i = (rx_buffer->head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer->tail) {
rx_buffer->buffer[rx_buffer->head] = c;
rx_buffer->head = i;
}
}
ISR(USART0_RX_vect)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
#ifdef UDR1
ISR(USART1_RX_vect)
{
unsigned char c = UDR1;
store_char(c, &rx_buffer1);
}
#ifdef UDR2
ISR(USART2_RX_vect)
{
unsigned char c = UDR2;
store_char(c, &rx_buffer2);
}
#ifdef UDR2
ISR(USART3_RX_vect)
{
unsigned char c = UDR3;
store_char(c, &rx_buffer3);
}
#endif
#endif
#else
#if defined(__AVR_ATmega8__)
SIGNAL(SIG_UART_RECV)
#else
SIGNAL(USART_RX_vect)
#endif
{
#if defined(__AVR_ATmega8__)
unsigned char c = UDR;
#else
unsigned char c = UDR0;
#endif
store_char(c, &rx_buffer);
}
#endif
// Constructors ////////////////////////////////////////////////////////////////
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
{
_rx_buffer = rx_buffer;
_ubrrh = ubrrh;
_ubrrl = ubrrl;
_ucsra = ucsra;
_ucsrb = ucsrb;
_udr = udr;
_rxen = rxen;
_txen = txen;
_rxcie = rxcie;
_udre = udre;
_u2x = u2x;
}
// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long baud)
{
uint16_t baud_setting;
bool use_u2x;
// U2X mode is needed for baud rates higher than (CPU Hz / 16)
if (baud > F_CPU / 16) {
use_u2x = true;
} else {
// figure out if U2X mode would allow for a better connection
// calculate the percent difference between the baud-rate specified and
// the real baud rate for both U2X and non-U2X mode (0-255 error percent)
uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
// prefer non-U2X mode because it handles clock skew better
use_u2x = (nonu2x_baud_error > u2x_baud_error);
}
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
}
void HardwareSerial::end()
{
cbi(*_ucsrb, _rxen);
cbi(*_ucsrb, _txen);
cbi(*_ucsrb, _rxcie);
}
uint8_t HardwareSerial::available(void)
{
return (RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE;
}
int HardwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (_rx_buffer->tail + 1) % RX_BUFFER_SIZE;
return c;
}
}
void HardwareSerial::flush()
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
_rx_buffer->head = _rx_buffer->tail;
}
void HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;
*_udr = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
#if defined(__AVR_ATmega8__)
HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X);
#else
HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#endif
#ifdef UDR1
HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1);
#endif
#ifdef UDR2
HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2);
#endif
#ifdef UDR3
HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3);
#endif

@ -0,0 +1,69 @@
/*
HardwareSerial.h - Hardware serial library for 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 HardwareSerial_h
#define HardwareSerial_h
#include <inttypes.h>
#include "Print.h"
struct ring_buffer;
class HardwareSerial : public Print
{
private:
ring_buffer *_rx_buffer;
volatile uint8_t *_ubrrh;
volatile uint8_t *_ubrrl;
volatile uint8_t *_ucsra;
volatile uint8_t *_ucsrb;
volatile uint8_t *_udr;
uint8_t _rxen;
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udre;
uint8_t _u2x;
public:
HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
void begin(long);
void end();
uint8_t available(void);
int read(void);
void flush(void);
virtual void write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
};
extern HardwareSerial Serial;
#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1280__)
extern HardwareSerial Serial1;
#endif
#if defined(__AVR_ATmega1280__)
extern HardwareSerial Serial2;
extern HardwareSerial Serial3;
#endif
#endif

@ -0,0 +1,243 @@
# Arduino 0011 Makefile
# Arduino adaptation by mellis, eighthave, oli.keller
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
#
# Detailed instructions for using the makefile:
#
# 1. Copy this file into the folder with your sketch. There should be a
# file with the same name as the folder and with the extension .pde
# (e.g. foo.pde in the foo/ folder).
#
# 2. Modify the line containg "INSTALL_DIR" to point to the directory that
# contains the Arduino installation (for example, under Mac OS X, this
# might be /Applications/arduino-0012).
#
# 3. 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*).
#
# 4. Set the line containing "MCU" to match your board's processor.
# Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
# or Diecimila have the atmega168. If you're using a LilyPad Arduino,
# change F_CPU to 8000000.
#
# 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$
TARGET = $(notdir $(CURDIR))
INSTALL_DIR = /Users/dmellis/Source/arduino/trunk/build/macosx/build/work
PORT = /dev/tty.usb*
UPLOAD_RATE = 19200
AVRDUDE_PROGRAMMER = stk500v1
MCU = atmega168
F_CPU = 16000000
############################################################################
# Below here nothing should be changed...
ARDUINO = $(INSTALL_DIR)/hardware/cores/arduino
AVR_TOOLS_PATH = $(INSTALL_DIR)/hardware/tools/avr/bin
SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
$(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
$(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \
$(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c
CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(ARDUINO)/WMath.cpp
FORMAT = ihex
# 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)
# Place -I options here
CINCS = -I$(ARDUINO)
CXXINCS = -I$(ARDUINO)
# 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) $(CINCS) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA)
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
LDFLAGS = -lm
# Programming support using avrdude. Settings and variables.
AVRDUDE_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex
AVRDUDE_FLAGS = -V -F -C $(INSTALL_DIR)/hardware/tools/avr/etc/avrdude.conf \
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE)
# Program settings
CC = $(AVR_TOOLS_PATH)/avr-gcc
CXX = $(AVR_TOOLS_PATH)/avr-g++
OBJCOPY = $(AVR_TOOLS_PATH)/avr-objcopy
OBJDUMP = $(AVR_TOOLS_PATH)/avr-objdump
AR = $(AVR_TOOLS_PATH)/avr-ar
SIZE = $(AVR_TOOLS_PATH)/avr-size
NM = $(AVR_TOOLS_PATH)/avr-nm
AVRDUDE = $(AVR_TOOLS_PATH)/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: applet_files build sizeafter
build: elf hex
applet_files: $(TARGET).pde
# Here is the "preprocessing".
# It creates a .cpp file based with the same name as the .pde file.
# On top of the new .cpp file comes the WProgram.h header.
# At the end there is a generic main() function attached.
# Then the .cpp file will be compiled. Errors during compile will
# refer to this new, automatically generated, file.
# Not the original .pde file you actually edit...
test -d applet || mkdir applet
echo '#include "WProgram.h"' > applet/$(TARGET).cpp
cat $(TARGET).pde >> applet/$(TARGET).cpp
cat $(ARDUINO)/main.cxx >> applet/$(TARGET).cpp
elf: applet/$(TARGET).elf
hex: applet/$(TARGET).hex
eep: applet/$(TARGET).eep
lss: applet/$(TARGET).lss
sym: applet/$(TARGET).sym
# Program the device.
upload: applet/$(TARGET).hex
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex
ELFSIZE = $(SIZE) applet/$(TARGET).elf
sizebefore:
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi
sizeafter:
@if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(HEXSIZE); echo; fi
# 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 $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.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 $< > $@
# Link: create ELF output file from library.
applet/$(TARGET).elf: $(TARGET).pde applet/core.a
$(CC) $(ALL_CFLAGS) -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)
applet/core.a: $(OBJ)
@for i in $(OBJ); do echo $(AR) rcs applet/core.a $$i; $(AR) rcs applet/core.a $$i; done
# Compile: create object files from C++ source files.
.cpp.o:
$(CXX) -c $(ALL_CXXFLAGS) $< -o $@
# Compile: create object files from C source files.
.c.o:
$(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 $@
# Target: clean project.
clean:
$(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/core.a \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
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) $(CINCS) $(SRC) $(ASRC) >> $(MAKEFILE)
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter

@ -0,0 +1,203 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include "wiring.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
void Print::print(uint8_t b)
{
this->write(b);
}
void Print::print(char c)
{
print((byte) c);
}
void Print::print(const char c[])
{
while (*c)
print(*c++);
}
void Print::print(int n)
{
print((long) n);
}
void Print::print(unsigned int n)
{
print((unsigned long) n);
}
void Print::print(long n)
{
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
}
void Print::print(unsigned long n)
{
printNumber(n, 10);
}
void Print::print(long n, int base)
{
if (base == 0)
print((char) n);
else if (base == 10)
print(n);
else
printNumber(n, base);
}
void Print::print(double n)
{
printFloat(n, 2);
}
void Print::println(void)
{
print('\r');
print('\n');
}
void Print::println(char c)
{
print(c);
println();
}
void Print::println(const char c[])
{
print(c);
println();
}
void Print::println(uint8_t b)
{
print(b);
println();
}
void Print::println(int n)
{
print(n);
println();
}
void Print::println(unsigned int n)
{
print(n);
println();
}
void Print::println(long n)
{
print(n);
println();
}
void Print::println(unsigned long n)
{
print(n);
println();
}
void Print::println(long n, int base)
{
print(n, base);
println();
}
void Print::println(double n)
{
print(n);
println();
}
// Private Methods /////////////////////////////////////////////////////////////
void Print::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
while (n > 0) {
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
print((char) (buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
void Print::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print(".");
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}

@ -0,0 +1,59 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Print_h
#define Print_h
#include <inttypes.h>
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0
class Print
{
private:
void printNumber(unsigned long, uint8_t);
void printFloat(double, uint8_t);
public:
virtual void write(uint8_t);
void print(char);
void print(const char[]);
void print(uint8_t);
void print(int);
void print(unsigned int);
void print(long);
void print(unsigned long);
void print(long, int);
void print(double);
void println(void);
void println(char);
void println(const char[]);
void println(uint8_t);
void println(int);
void println(unsigned int);
void println(long);
void println(unsigned long);
void println(long, int);
void println(double);
};
#endif

@ -0,0 +1,515 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
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
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
*************************************************/
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <wiring.h>
#include <pins_arduino.h>
#if defined(__AVR_ATmega8__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#endif
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
#if !defined(__AVR_ATmega8__)
volatile long timer0_toggle_count;
volatile uint8_t *timer0_pin_port;
volatile uint8_t timer0_pin_mask;
#endif
volatile long timer1_toggle_count;
volatile uint8_t *timer1_pin_port;
volatile uint8_t timer1_pin_mask;
volatile long timer2_toggle_count;
volatile uint8_t *timer2_pin_port;
volatile uint8_t timer2_pin_mask;
#if defined(__AVR_ATmega1280__)
volatile long timer3_toggle_count;
volatile uint8_t *timer3_pin_port;
volatile uint8_t timer3_pin_mask;
volatile long timer4_toggle_count;
volatile uint8_t *timer4_pin_port;
volatile uint8_t timer4_pin_mask;
volatile long timer5_toggle_count;
volatile uint8_t *timer5_pin_port;
volatile uint8_t timer5_pin_mask;
#endif
#if defined(__AVR_ATmega1280__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
#elif defined(__AVR_ATmega8__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
#else
#define AVAILABLE_TONE_PINS 1
// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
#endif
static int8_t toneBegin(uint8_t _pin)
{
int8_t _timer = -1;
// if we're already using the pin, the timer should be configured.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
return pgm_read_byte(tone_pin_to_timer_PGM + i);
}
}
// search for an unused timer.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == 255) {
tone_pins[i] = _pin;
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
break;
}
}
if (_timer != -1)
{
// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch (_timer)
{
#if !defined(__AVR_ATmega8__)
case 0:
// 8 bit timer
TCCR0A = 0;
TCCR0B = 0;
bitWrite(TCCR0A, WGM01, 1);
bitWrite(TCCR0B, CS00, 1);
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer0_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
case 1:
// 16 bit timer
TCCR1A = 0;
TCCR1B = 0;
bitWrite(TCCR1B, WGM12, 1);
bitWrite(TCCR1B, CS10, 1);
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer1_pin_mask = digitalPinToBitMask(_pin);
break;
case 2:
// 8 bit timer
TCCR2A = 0;
TCCR2B = 0;
bitWrite(TCCR2A, WGM21, 1);
bitWrite(TCCR2B, CS20, 1);
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer2_pin_mask = digitalPinToBitMask(_pin);
break;
#if defined(__AVR_ATmega1280__)
case 3:
// 16 bit timer
TCCR3A = 0;
TCCR3B = 0;
bitWrite(TCCR3B, WGM32, 1);
bitWrite(TCCR3B, CS30, 1);
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer3_pin_mask = digitalPinToBitMask(_pin);
break;
case 4:
// 16 bit timer
TCCR4A = 0;
TCCR4B = 0;
bitWrite(TCCR4B, WGM42, 1);
bitWrite(TCCR4B, CS40, 1);
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer4_pin_mask = digitalPinToBitMask(_pin);
break;
case 5:
// 16 bit timer
TCCR5A = 0;
TCCR5B = 0;
bitWrite(TCCR5B, WGM52, 1);
bitWrite(TCCR5B, CS50, 1);
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer5_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
}
}
return _timer;
}
// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
uint8_t prescalarbits = 0b001;
long toggle_count = 0;
uint32_t ocr = 0;
int8_t _timer;
_timer = toneBegin(_pin);
if (_timer >= 0)
{
// Set the pinMode as OUTPUT
pinMode(_pin, OUTPUT);
// if we are using an 8 bit timer, scan through prescalars to find the best fit
if (_timer == 0 || _timer == 2)
{
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001; // ck/1: same for both timers
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 8 - 1;
prescalarbits = 0b010; // ck/8: same for both timers
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 32 - 1;
prescalarbits = 0b011;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = _timer == 0 ? 0b011 : 0b100;
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 128 - 1;
prescalarbits = 0b101;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 256 - 1;
prescalarbits = _timer == 0 ? 0b100 : 0b110;
if (ocr > 255)
{
// can't do any better than /1024
ocr = F_CPU / frequency / 2 / 1024 - 1;
prescalarbits = _timer == 0 ? 0b101 : 0b111;
}
}
}
}
#if !defined(__AVR_ATmega8__)
if (_timer == 0)
TCCR0B = prescalarbits;
else
#endif
TCCR2B = prescalarbits;
}
else
{
// two choices for the 16 bit timers: ck/1 or ck/64
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001;
if (ocr > 0xffff)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = 0b011;
}
if (_timer == 1)
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
#if defined(__AVR_ATmega1280__)
else if (_timer == 3)
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
else if (_timer == 4)
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
else if (_timer == 5)
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
#endif
}
// Calculate the toggle count
if (duration > 0)
{
toggle_count = 2 * frequency * duration / 1000;
}
else
{
toggle_count = -1;
}
// Set the OCR for the given timer,
// set the toggle count,
// then turn on the interrupts
switch (_timer)
{
#if !defined(__AVR_ATmega8__)
case 0:
OCR0A = ocr;
timer0_toggle_count = toggle_count;
bitWrite(TIMSK0, OCIE0A, 1);
break;
#endif
case 1:
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK1, OCIE1A, 1);
break;
case 2:
OCR2A = ocr;
timer2_toggle_count = toggle_count;
bitWrite(TIMSK2, OCIE2A, 1);
break;
#if defined(__AVR_ATmega1280__)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
bitWrite(TIMSK3, OCIE3A, 1);
break;
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
bitWrite(TIMSK4, OCIE4A, 1);
break;
case 5:
OCR5A = ocr;
timer5_toggle_count = toggle_count;
bitWrite(TIMSK5, OCIE5A, 1);
break;
#endif
}
}
}
void noTone(uint8_t _pin)
{
int8_t _timer = -1;
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
tone_pins[i] = 255;
}
}
switch (_timer)
{
#if defined(__AVR_ATmega8__)
case 1:
bitWrite(TIMSK1, OCIE1A, 0);
break;
case 2:
bitWrite(TIMSK2, OCIE2A, 0);
break;
#else
case 0:
TIMSK0 = 0;
break;
case 1:
TIMSK1 = 0;
break;
case 2:
TIMSK2 = 0;
break;
#endif
#if defined(__AVR_ATmega1280__)
case 3:
TIMSK3 = 0;
break;
case 4:
TIMSK4 = 0;
break;
case 5:
TIMSK5 = 0;
break;
#endif
}
digitalWrite(_pin, 0);
}
#if 0
#if !defined(__AVR_ATmega8__)
ISR(TIMER0_COMPA_vect)
{
if (timer0_toggle_count != 0)
{
// toggle the pin
*timer0_pin_port ^= timer0_pin_mask;
if (timer0_toggle_count > 0)
timer0_toggle_count--;
}
else
{
TIMSK0 = 0; // disable the interrupt
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER1_COMPA_vect)
{
if (timer1_toggle_count != 0)
{
// toggle the pin
*timer1_pin_port ^= timer1_pin_mask;
if (timer1_toggle_count > 0)
timer1_toggle_count--;
}
else
{
TIMSK1 = 0; // disable the interrupt
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER2_COMPA_vect)
{
if (timer2_toggle_count != 0)
{
// toggle the pin
*timer2_pin_port ^= timer2_pin_mask;
if (timer2_toggle_count > 0)
timer2_toggle_count--;
}
else
{
TIMSK2 = 0; // disable the interrupt
*timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
}
}
//#if defined(__AVR_ATmega1280__)
#if 0
ISR(TIMER3_COMPA_vect)
{
if (timer3_toggle_count != 0)
{
// toggle the pin
*timer3_pin_port ^= timer3_pin_mask;
if (timer3_toggle_count > 0)
timer3_toggle_count--;
}
else
{
TIMSK3 = 0; // disable the interrupt
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
}
}
ISR(TIMER4_COMPA_vect)
{
if (timer4_toggle_count != 0)
{
// toggle the pin
*timer4_pin_port ^= timer4_pin_mask;
if (timer4_toggle_count > 0)
timer4_toggle_count--;
}
else
{
TIMSK4 = 0; // disable the interrupt
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
}
}
ISR(TIMER5_COMPA_vect)
{
if (timer5_toggle_count != 0)
{
// toggle the pin
*timer5_pin_port ^= timer5_pin_mask;
if (timer5_toggle_count > 0)
timer5_toggle_count--;
}
else
{
TIMSK5 = 0; // disable the interrupt
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
}
}
#endif

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. 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 Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

@ -0,0 +1,87 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "WConstants.h"
#include "wiring_private.h"
volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)
{
if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
{
intFunc[interruptNum] = userFunc;
//clear the config for the change settings
EICRA &= ~(B00000011 << (interruptNum * 2));
//set our mode.
EICRA |= (mode << (interruptNum * 2));
// Enable the interrupt.
EIMSK |= (1 << interruptNum);
}
}
void detachInterrupt(uint8_t interruptNum)
{
if(interruptNum < EXTERNAL_NUM_INTERRUPTS)
{
// Disable the interrupt.
EIMSK &= ~(1 << interruptNum);
intFunc[interruptNum] = 0;
}
}
ISR(INT0_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
ISR(INT1_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
ISR(INT2_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
/*
SIGNAL(SIG_2WIRE_SERIAL) {
if(twiIntFunc)
twiIntFunc();
}
*/

@ -0,0 +1,60 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.org.co
Copyright (c) 2004-06 Hernando Barragan
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
extern "C" {
#include "stdlib.h"
}
void randomSeed(unsigned int seed)
{
if (seed != 0){
srandom(seed);
}
}
long random(long howbig)
{
if (howbig == 0) {
return 0;
}
return random() % howbig;
}
long random(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

@ -0,0 +1,34 @@
#ifndef WProgram_h
#define WProgram_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/interrupt.h>
#include "wiring.h"
#ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h"
#include "HardwareSerial.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
// WMath prototypes
long random(long);
long random(long, long);
void randomSeed(unsigned int);
long map(long, long, long, long, long);
#endif
#endif

@ -0,0 +1,443 @@
/*
WString.cpp - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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.
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
*/
#include <stdlib.h>
#include "WProgram.h"
#include "WString.h"
String::String( const char *value )
{
if ( value == NULL )
value = "";
getBuffer( _length = strlen( value ) );
if ( _buffer != NULL )
strcpy( _buffer, value );
}
String::String( const String &value )
{
getBuffer( _length = value._length );
if ( _buffer != NULL )
strcpy( _buffer, value._buffer );
}
String::String( const char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL ) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const unsigned char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const int value, const int base )
{
char buf[33];
itoa((signed long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned int value, const int base )
{
char buf[33];
ultoa((unsigned long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const long value, const int base )
{
char buf[33];
ltoa(value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned long value, const int base )
{
char buf[33];
ultoa(value, buf, 10);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
char String::charAt( unsigned int loc ) const
{
return operator[]( loc );
}
void String::setCharAt( unsigned int loc, const char aChar )
{
if(_buffer == NULL) return;
if(_length > loc) {
_buffer[loc] = aChar;
}
}
int String::compareTo( const String &s2 ) const
{
return strcmp( _buffer, s2._buffer );
}
const String & String::concat( const String &s2 )
{
return (*this) += s2;
}
const String & String::operator=( const String &rhs )
{
if ( this == &rhs )
return *this;
if ( rhs._length > _length )
{
free(_buffer);
getBuffer( rhs._length );
}
if ( _buffer != NULL ) {
_length = rhs._length;
strcpy( _buffer, rhs._buffer );
}
return *this;
}
//const String & String::operator+=( const char aChar )
//{
// if ( _length == _capacity )
// doubleBuffer();
//
// _buffer[ _length++ ] = aChar;
// _buffer[ _length ] = '\0';
// return *this;
//}
const String & String::operator+=( const String &other )
{
_length += other._length;
if ( _length > _capacity )
{
char *temp = (char *)realloc(_buffer, _length + 1);
if ( temp != NULL ) {
_buffer = temp;
_capacity = _length;
} else {
_length -= other._length;
return *this;
}
}
strcat( _buffer, other._buffer );
return *this;
}
int String::operator==( const String &rhs ) const
{
return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 );
}
int String::operator!=( const String &rhs ) const
{
return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 );
}
int String::operator<( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) < 0;
}
int String::operator>( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) > 0;
}
int String::operator<=( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) <= 0;
}
int String::operator>=( const String & rhs ) const
{
return strcmp( _buffer, rhs._buffer ) >= 0;
}
char & String::operator[]( unsigned int index )
{
static char dummy_writable_char;
if (index >= _length || !_buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return _buffer[ index ];
}
char String::operator[]( unsigned int index ) const
{
// need to check for valid index, to do later
return _buffer[ index ];
}
boolean String::endsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0;
}
boolean String::equals( const String &s2 ) const
{
return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 );
}
boolean String::equalsIgnoreCase( const String &s2 ) const
{
if ( this == &s2 )
return true; //1;
else if ( _length != s2._length )
return false; //0;
return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0;
}
String String::replace( char findChar, char replaceChar )
{
if ( _buffer == NULL ) return *this;
String theReturn = _buffer;
char* temp = theReturn._buffer;
while( (temp = strchr( temp, findChar )) != 0 )
*temp = replaceChar;
return theReturn;
}
String String::replace( const String& match, const String& replace )
{
if ( _buffer == NULL ) return *this;
String temp = _buffer, newString;
int loc;
while ( (loc = temp.indexOf( match )) != -1 )
{
newString += temp.substring( 0, loc );
newString += replace;
temp = temp.substring( loc + match._length );
}
newString += temp;
return newString;
}
int String::indexOf( char temp ) const
{
return indexOf( temp, 0 );
}
int String::indexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char* temp = strchr( &_buffer[fromIndex], ch );
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::indexOf( const String &s2 ) const
{
return indexOf( s2, 0 );
}
int String::indexOf( const String &s2, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer );
if ( theFind == NULL )
return -1;
return theFind - _buffer; // pointer subtraction
}
int String::lastIndexOf( char theChar ) const
{
return lastIndexOf( theChar, _length - 1 );
}
int String::lastIndexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
char tempchar = _buffer[fromIndex + 1];
_buffer[fromIndex + 1] = '\0';
char* temp = strrchr( _buffer, ch );
_buffer[fromIndex + 1] = tempchar;
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::lastIndexOf( const String &s2 ) const
{
return lastIndexOf( s2, _length - s2._length );
}
int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const
{
// check for empty strings
if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length )
return -1;
// matching first character
char temp = s2[ 0 ];
for ( int i = fromIndex; i >= 0; i-- )
{
if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) )
return i;
}
return -1;
}
boolean String::startsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return startsWith( s2, 0 );
}
boolean String::startsWith( const String &s2, unsigned int offset ) const
{
if ( offset > _length - s2._length )
return 0;
return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0;
}
String String::substring( unsigned int left ) const
{
return substring( left, _length );
}
String String::substring( unsigned int left, unsigned int right ) const
{
if ( left > right )
{
int temp = right;
right = left;
left = temp;
}
if ( right > _length )
{
right = _length;
}
char temp = _buffer[ right ]; // save the replaced character
_buffer[ right ] = '\0';
String outPut = ( _buffer + left ); // pointer arithmetic
_buffer[ right ] = temp; //restore character
return outPut;
}
String String::toLowerCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] );
return temp;
}
String String::toUpperCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] );
return temp;
}
String String::trim() const
{
if ( _buffer == NULL ) return *this;
String temp = _buffer;
unsigned int i,j;
for ( i = 0; i < _length; i++ )
{
if ( !isspace(_buffer[i]) )
break;
}
for ( j = temp._length - 1; j > i; j-- )
{
if ( !isspace(_buffer[j]) )
break;
}
return temp.substring( i, j + 1);
}
void String::getBytes(unsigned char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy((char *)buf, _buffer, len);
buf[len] = 0;
}
void String::toCharArray(char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy(buf, _buffer, len);
buf[len] = 0;
}
long String::toInt() {
return atol(_buffer);
}

@ -0,0 +1,112 @@
/*
WString.h - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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 String_h
#define String_h
//#include "WProgram.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
class String
{
public:
// constructors
String( const char *value = "" );
String( const String &value );
String( const char );
String( const unsigned char );
String( const int, const int base=10);
String( const unsigned int, const int base=10 );
String( const long, const int base=10 );
String( const unsigned long, const int base=10 );
~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0;
// operators
const String & operator = ( const String &rhs );
const String & operator +=( const String &rhs );
//const String & operator +=( const char );
int operator ==( const String &rhs ) const;
int operator !=( const String &rhs ) const;
int operator < ( const String &rhs ) const;
int operator > ( const String &rhs ) const;
int operator <=( const String &rhs ) const;
int operator >=( const String &rhs ) const;
char operator []( unsigned int index ) const;
char& operator []( unsigned int index );
//operator const char *() const { return _buffer; }
// general methods
char charAt( unsigned int index ) const;
int compareTo( const String &anotherString ) const;
unsigned char endsWith( const String &suffix ) const;
unsigned char equals( const String &anObject ) const;
unsigned char equalsIgnoreCase( const String &anotherString ) const;
int indexOf( char ch ) const;
int indexOf( char ch, unsigned int fromIndex ) const;
int indexOf( const String &str ) const;
int indexOf( const String &str, unsigned int fromIndex ) const;
int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
const unsigned int length( ) const { return _length; }
void setCharAt(unsigned int index, const char ch);
unsigned char startsWith( const String &prefix ) const;
unsigned char startsWith( const String &prefix, unsigned int toffset ) const;
String substring( unsigned int beginIndex ) const;
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
String toLowerCase( ) const;
String toUpperCase( ) const;
String trim( ) const;
void getBytes(unsigned char *buf, unsigned int bufsize);
void toCharArray(char *buf, unsigned int bufsize);
long toInt( );
const String& concat( const String &str );
String replace( char oldChar, char newChar );
String replace( const String& match, const String& replace );
friend String operator + ( String lhs, const String &rhs );
protected:
char *_buffer; // the actual char array
unsigned int _capacity; // the array length minus one (for the '\0')
unsigned int _length; // the String length (not counting the '\0')
void getBuffer(unsigned int maxStrLen);
private:
};
// allocate buffer space
inline void String::getBuffer(unsigned int maxStrLen)
{
_capacity = maxStrLen;
_buffer = (char *) malloc(_capacity + 1);
if (_buffer == NULL) _length = _capacity = 0;
}
inline String operator+( String lhs, const String &rhs )
{
return lhs += rhs;
}
#endif

@ -0,0 +1,515 @@
#ifndef Binary_h
#define Binary_h
#define B0 0
#define B00 0
#define B000 0
#define B0000 0
#define B00000 0
#define B000000 0
#define B0000000 0
#define B00000000 0
#define B1 1
#define B01 1
#define B001 1
#define B0001 1
#define B00001 1
#define B000001 1
#define B0000001 1
#define B00000001 1
#define B10 2
#define B010 2
#define B0010 2
#define B00010 2
#define B000010 2
#define B0000010 2
#define B00000010 2
#define B11 3
#define B011 3
#define B0011 3
#define B00011 3
#define B000011 3
#define B0000011 3
#define B00000011 3
#define B100 4
#define B0100 4
#define B00100 4
#define B000100 4
#define B0000100 4
#define B00000100 4
#define B101 5
#define B0101 5
#define B00101 5
#define B000101 5
#define B0000101 5
#define B00000101 5
#define B110 6
#define B0110 6
#define B00110 6
#define B000110 6
#define B0000110 6
#define B00000110 6
#define B111 7
#define B0111 7
#define B00111 7
#define B000111 7
#define B0000111 7
#define B00000111 7
#define B1000 8
#define B01000 8
#define B001000 8
#define B0001000 8
#define B00001000 8
#define B1001 9
#define B01001 9
#define B001001 9
#define B0001001 9
#define B00001001 9
#define B1010 10
#define B01010 10
#define B001010 10
#define B0001010 10
#define B00001010 10
#define B1011 11
#define B01011 11
#define B001011 11
#define B0001011 11
#define B00001011 11
#define B1100 12
#define B01100 12
#define B001100 12
#define B0001100 12
#define B00001100 12
#define B1101 13
#define B01101 13
#define B001101 13
#define B0001101 13
#define B00001101 13
#define B1110 14
#define B01110 14
#define B001110 14
#define B0001110 14
#define B00001110 14
#define B1111 15
#define B01111 15
#define B001111 15
#define B0001111 15
#define B00001111 15
#define B10000 16
#define B010000 16
#define B0010000 16
#define B00010000 16
#define B10001 17
#define B010001 17
#define B0010001 17
#define B00010001 17
#define B10010 18
#define B010010 18
#define B0010010 18
#define B00010010 18
#define B10011 19
#define B010011 19
#define B0010011 19
#define B00010011 19
#define B10100 20
#define B010100 20
#define B0010100 20
#define B00010100 20
#define B10101 21
#define B010101 21
#define B0010101 21
#define B00010101 21
#define B10110 22
#define B010110 22
#define B0010110 22
#define B00010110 22
#define B10111 23
#define B010111 23
#define B0010111 23
#define B00010111 23
#define B11000 24
#define B011000 24
#define B0011000 24
#define B00011000 24
#define B11001 25
#define B011001 25
#define B0011001 25
#define B00011001 25
#define B11010 26
#define B011010 26
#define B0011010 26
#define B00011010 26
#define B11011 27
#define B011011 27
#define B0011011 27
#define B00011011 27
#define B11100 28
#define B011100 28
#define B0011100 28
#define B00011100 28
#define B11101 29
#define B011101 29
#define B0011101 29
#define B00011101 29
#define B11110 30
#define B011110 30
#define B0011110 30
#define B00011110 30
#define B11111 31
#define B011111 31
#define B0011111 31
#define B00011111 31
#define B100000 32
#define B0100000 32
#define B00100000 32
#define B100001 33
#define B0100001 33
#define B00100001 33
#define B100010 34
#define B0100010 34
#define B00100010 34
#define B100011 35
#define B0100011 35
#define B00100011 35
#define B100100 36
#define B0100100 36
#define B00100100 36
#define B100101 37
#define B0100101 37
#define B00100101 37
#define B100110 38
#define B0100110 38
#define B00100110 38
#define B100111 39
#define B0100111 39
#define B00100111 39
#define B101000 40
#define B0101000 40
#define B00101000 40
#define B101001 41
#define B0101001 41
#define B00101001 41
#define B101010 42
#define B0101010 42
#define B00101010 42
#define B101011 43
#define B0101011 43
#define B00101011 43
#define B101100 44
#define B0101100 44
#define B00101100 44
#define B101101 45
#define B0101101 45
#define B00101101 45
#define B101110 46
#define B0101110 46
#define B00101110 46
#define B101111 47
#define B0101111 47
#define B00101111 47
#define B110000 48
#define B0110000 48
#define B00110000 48
#define B110001 49
#define B0110001 49
#define B00110001 49
#define B110010 50
#define B0110010 50
#define B00110010 50
#define B110011 51
#define B0110011 51
#define B00110011 51
#define B110100 52
#define B0110100 52
#define B00110100 52
#define B110101 53
#define B0110101 53
#define B00110101 53
#define B110110 54
#define B0110110 54
#define B00110110 54
#define B110111 55
#define B0110111 55
#define B00110111 55
#define B111000 56
#define B0111000 56
#define B00111000 56
#define B111001 57
#define B0111001 57
#define B00111001 57
#define B111010 58
#define B0111010 58
#define B00111010 58
#define B111011 59
#define B0111011 59
#define B00111011 59
#define B111100 60
#define B0111100 60
#define B00111100 60
#define B111101 61
#define B0111101 61
#define B00111101 61
#define B111110 62
#define B0111110 62
#define B00111110 62
#define B111111 63
#define B0111111 63
#define B00111111 63
#define B1000000 64
#define B01000000 64
#define B1000001 65
#define B01000001 65
#define B1000010 66
#define B01000010 66
#define B1000011 67
#define B01000011 67
#define B1000100 68
#define B01000100 68
#define B1000101 69
#define B01000101 69
#define B1000110 70
#define B01000110 70
#define B1000111 71
#define B01000111 71
#define B1001000 72
#define B01001000 72
#define B1001001 73
#define B01001001 73
#define B1001010 74
#define B01001010 74
#define B1001011 75
#define B01001011 75
#define B1001100 76
#define B01001100 76
#define B1001101 77
#define B01001101 77
#define B1001110 78
#define B01001110 78
#define B1001111 79
#define B01001111 79
#define B1010000 80
#define B01010000 80
#define B1010001 81
#define B01010001 81
#define B1010010 82
#define B01010010 82
#define B1010011 83
#define B01010011 83
#define B1010100 84
#define B01010100 84
#define B1010101 85
#define B01010101 85
#define B1010110 86
#define B01010110 86
#define B1010111 87
#define B01010111 87
#define B1011000 88
#define B01011000 88
#define B1011001 89
#define B01011001 89
#define B1011010 90
#define B01011010 90
#define B1011011 91
#define B01011011 91
#define B1011100 92
#define B01011100 92
#define B1011101 93
#define B01011101 93
#define B1011110 94
#define B01011110 94
#define B1011111 95
#define B01011111 95
#define B1100000 96
#define B01100000 96
#define B1100001 97
#define B01100001 97
#define B1100010 98
#define B01100010 98
#define B1100011 99
#define B01100011 99
#define B1100100 100
#define B01100100 100
#define B1100101 101
#define B01100101 101
#define B1100110 102
#define B01100110 102
#define B1100111 103
#define B01100111 103
#define B1101000 104
#define B01101000 104
#define B1101001 105
#define B01101001 105
#define B1101010 106
#define B01101010 106
#define B1101011 107
#define B01101011 107
#define B1101100 108
#define B01101100 108
#define B1101101 109
#define B01101101 109
#define B1101110 110
#define B01101110 110
#define B1101111 111
#define B01101111 111
#define B1110000 112
#define B01110000 112
#define B1110001 113
#define B01110001 113
#define B1110010 114
#define B01110010 114
#define B1110011 115
#define B01110011 115
#define B1110100 116
#define B01110100 116
#define B1110101 117
#define B01110101 117
#define B1110110 118
#define B01110110 118
#define B1110111 119
#define B01110111 119
#define B1111000 120
#define B01111000 120
#define B1111001 121
#define B01111001 121
#define B1111010 122
#define B01111010 122
#define B1111011 123
#define B01111011 123
#define B1111100 124
#define B01111100 124
#define B1111101 125
#define B01111101 125
#define B1111110 126
#define B01111110 126
#define B1111111 127
#define B01111111 127
#define B10000000 128
#define B10000001 129
#define B10000010 130
#define B10000011 131
#define B10000100 132
#define B10000101 133
#define B10000110 134
#define B10000111 135
#define B10001000 136
#define B10001001 137
#define B10001010 138
#define B10001011 139
#define B10001100 140
#define B10001101 141
#define B10001110 142
#define B10001111 143
#define B10010000 144
#define B10010001 145
#define B10010010 146
#define B10010011 147
#define B10010100 148
#define B10010101 149
#define B10010110 150
#define B10010111 151
#define B10011000 152
#define B10011001 153
#define B10011010 154
#define B10011011 155
#define B10011100 156
#define B10011101 157
#define B10011110 158
#define B10011111 159
#define B10100000 160
#define B10100001 161
#define B10100010 162
#define B10100011 163
#define B10100100 164
#define B10100101 165
#define B10100110 166
#define B10100111 167
#define B10101000 168
#define B10101001 169
#define B10101010 170
#define B10101011 171
#define B10101100 172
#define B10101101 173
#define B10101110 174
#define B10101111 175
#define B10110000 176
#define B10110001 177
#define B10110010 178
#define B10110011 179
#define B10110100 180
#define B10110101 181
#define B10110110 182
#define B10110111 183
#define B10111000 184
#define B10111001 185
#define B10111010 186
#define B10111011 187
#define B10111100 188
#define B10111101 189
#define B10111110 190
#define B10111111 191
#define B11000000 192
#define B11000001 193
#define B11000010 194
#define B11000011 195
#define B11000100 196
#define B11000101 197
#define B11000110 198
#define B11000111 199
#define B11001000 200
#define B11001001 201
#define B11001010 202
#define B11001011 203
#define B11001100 204
#define B11001101 205
#define B11001110 206
#define B11001111 207
#define B11010000 208
#define B11010001 209
#define B11010010 210
#define B11010011 211
#define B11010100 212
#define B11010101 213
#define B11010110 214
#define B11010111 215
#define B11011000 216
#define B11011001 217
#define B11011010 218
#define B11011011 219
#define B11011100 220
#define B11011101 221
#define B11011110 222
#define B11011111 223
#define B11100000 224
#define B11100001 225
#define B11100010 226
#define B11100011 227
#define B11100100 228
#define B11100101 229
#define B11100110 230
#define B11100111 231
#define B11101000 232
#define B11101001 233
#define B11101010 234
#define B11101011 235
#define B11101100 236
#define B11101101 237
#define B11101110 238
#define B11101111 239
#define B11110000 240
#define B11110001 241
#define B11110010 242
#define B11110011 243
#define B11110100 244
#define B11110101 245
#define B11110110 246
#define B11110111 247
#define B11111000 248
#define B11111001 249
#define B11111010 250
#define B11111011 251
#define B11111100 252
#define B11111101 253
#define B11111110 254
#define B11111111 255
#endif

@ -0,0 +1,14 @@
#include <WProgram.h>
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

@ -0,0 +1,12 @@
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

@ -0,0 +1,200 @@
/*
pins_arduino.c - pin definitions for the Arduino board
Part of Arduino / Wiring Lite
Copyright (c) 2005 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: pins_arduino.c 254 2007-04-20 23:17:38Z mellis $
*/
#include <avr/io.h>
#include "wiring_private.h"
#include "pins_arduino.h"
// On the Sanguino board, digital pins are also used
// for the analog output (software PWM). Analog input
// pins are a separate set.
// ATMEL ATMEGA644P / SANGUINO
//
// +---\/---+
// INT0 (D 0) PB0 1| |40 PA0 (AI 0 / D31)
// INT1 (D 1) PB1 2| |39 PA1 (AI 1 / D30)
// INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
// PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
// PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
// MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
// MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
// SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
// RST 9| |32 AREF
// VCC 10| |31 GND
// GND 11| |30 AVCC
// XTAL2 12| |29 PC7 (D 23)
// XTAL1 13| |28 PC6 (D 22)
// RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
// TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
// RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
// TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
// PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
// PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
// PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
// +--------+
//
#define PA 1
#define PB 2
#define PC 3
#define PD 4
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
(uint8_t) &DDRA,
(uint8_t) &DDRB,
(uint8_t) &DDRC,
(uint8_t) &DDRD,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
(uint8_t) &PORTA,
(uint8_t) &PORTB,
(uint8_t) &PORTC,
(uint8_t) &PORTD,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PORT,
(uint8_t) &PINA,
(uint8_t) &PINB,
(uint8_t) &PINC,
(uint8_t) &PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PB, /* 0 */
PB,
PB,
PB,
PB,
PB,
PB,
PB,
PD, /* 8 */
PD,
PD,
PD,
PD,
PD,
PD,
PD,
PC, /* 16 */
PC,
PC,
PC,
PC,
PC,
PC,
PC,
PA, /* 24 */
PA,
PA,
PA,
PA,
PA,
PA,
PA /* 31 */
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0, port B */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 8, port D */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 16, port C */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(7), /* 24, port A */
_BV(6),
_BV(5),
_BV(4),
_BV(3),
_BV(2),
_BV(1),
_BV(0)
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
NOT_ON_TIMER, /* 0 - PB0 */
NOT_ON_TIMER, /* 1 - PB1 */
NOT_ON_TIMER, /* 2 - PB2 */
TIMER0A, /* 3 - PB3 */
TIMER0B, /* 4 - PB4 */
NOT_ON_TIMER, /* 5 - PB5 */
NOT_ON_TIMER, /* 6 - PB6 */
NOT_ON_TIMER, /* 7 - PB7 */
NOT_ON_TIMER, /* 8 - PD0 */
NOT_ON_TIMER, /* 9 - PD1 */
NOT_ON_TIMER, /* 10 - PD2 */
NOT_ON_TIMER, /* 11 - PD3 */
TIMER1B, /* 12 - PD4 */
TIMER1A, /* 13 - PD5 */
TIMER2B, /* 14 - PD6 */
TIMER2A, /* 15 - PD7 */
NOT_ON_TIMER, /* 16 - PC0 */
NOT_ON_TIMER, /* 17 - PC1 */
NOT_ON_TIMER, /* 18 - PC2 */
NOT_ON_TIMER, /* 19 - PC3 */
NOT_ON_TIMER, /* 20 - PC4 */
NOT_ON_TIMER, /* 21 - PC5 */
NOT_ON_TIMER, /* 22 - PC6 */
NOT_ON_TIMER, /* 23 - PC7 */
NOT_ON_TIMER, /* 24 - PA0 */
NOT_ON_TIMER, /* 25 - PA1 */
NOT_ON_TIMER, /* 26 - PA2 */
NOT_ON_TIMER, /* 27 - PA3 */
NOT_ON_TIMER, /* 28 - PA4 */
NOT_ON_TIMER, /* 29 - PA5 */
NOT_ON_TIMER, /* 30 - PA6 */
NOT_ON_TIMER /* 31 - PA7 */
};

@ -0,0 +1,65 @@
/*
pins_arduino.h - Pin definition functions for Arduino
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2007 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <avr/pgmspace.h>
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER2 5
#define TIMER2A 6
#define TIMER2B 7
extern const uint8_t PROGMEM port_to_mode_PGM[];
extern const uint8_t PROGMEM port_to_input_PGM[];
extern const uint8_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_byte( port_to_mode_PGM + (P))) )
#endif

@ -0,0 +1,203 @@
/*
wiring.c - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 388 2008-03-08 22:05:23Z mellis $
*/
#include "wiring_private.h"
volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_clock_cycles = 0;
volatile unsigned long timer0_millis = 0;
SIGNAL(TIMER0_OVF_vect)
{
timer0_overflow_count++;
// timer 0 prescale factor is 64 and the timer overflows at 256
timer0_clock_cycles += 64UL * 256UL;
while (timer0_clock_cycles > clockCyclesPerMicrosecond() * 1000UL) {
timer0_clock_cycles -= clockCyclesPerMicrosecond() * 1000UL;
timer0_millis++;
}
}
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of the timer0_millis++)
cli();
m = timer0_millis;
SREG = oldSREG;
return m;
}
unsigned long micros() {
unsigned long m, t;
uint8_t oldSREG = SREG;
cli();
t = TCNT0;
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t == 0))
t = 256;
#else
if ((TIFR & _BV(TOV0)) && (t == 0))
t = 256;
#endif
m = timer0_overflow_count;
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
void delay(unsigned long ms)
{
unsigned long start = millis();
while (millis() - start <= ms)
;
}
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock.
* Disables interrupts, which will disrupt the millis() function if used
* too frequently. */
void delayMicroseconds(unsigned int us)
{
uint8_t oldSREG;
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return. the overhead of
// the function calls takes more than two microseconds. can't just
// subtract two, since us is unsigned; we'd overflow.
if (--us == 0)
return;
if (--us == 0)
return;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// disable interrupts, otherwise the timer 0 overflow interrupt that
// tracks milliseconds will make us delay longer than we want.
oldSREG = SREG;
cli();
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
// reenable interrupts.
SREG = oldSREG;
}
void init()
{
// this needs to be called before setup() or some functions won't
// work there
sei();
// on the ATmega168, timer 0 is also used for fast hardware pwm
// (using phase-correct PWM would mean that timer 0 overflowed half as often
// resulting in different millis() behavior on the ATmega8 and ATmega168)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
// set timer 0 prescale factor to 64
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
// enable timer 0 overflow interrupt
sbi(TIMSK0, TOIE0);
// timers 1 and 2 are used for phase-correct hardware pwm
// this is better for motors as it ensures an even waveform
// note, however, that fast pwm mode can achieve a frequency of up
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
// set timer 1 prescale factor to 64
sbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
// put timer 1 in 8-bit phase correct pwm mode
sbi(TCCR1A, WGM10);
// set timer 2 prescale factor to 64
sbi(TCCR2B, CS22);
// configure timer 2 for phase correct pwm (8-bit)
sbi(TCCR2A, WGM20);
// set a2d prescale factor to 128
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
// XXX: this will not work properly for other clock speeds, and
// this code should use F_CPU to determine the prescale factor.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
// enable a2d conversions
sbi(ADCSRA, ADEN);
// the bootloader connects pins 0 and 1 to the USART; disconnect them
// here so they can be used as normal digital i/o; they will be
// reconnected in Serial.begin()
UCSR0B = 0;
#if defined(__AVR_ATmega644P__)
//TODO: test to see if disabling this helps?
//UCSR1B = 0;
#endif
}

@ -0,0 +1,133 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 387 2008-03-08 21:30:00Z mellis $
*/
#ifndef Wiring_h
#define Wiring_h
#include <avr/io.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.14159265
#define HALF_PI 1.57079
#define TWO_PI 6.283185
#define DEG_TO_RAD 0.01745329
#define RAD_TO_DEG 57.2957786
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#define INTERNAL 3
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
#define lowByte(w) ((w) & 0xff)
#define highByte(w) ((w) >> 8)
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1 << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
void beginSerial(uint8_t, long);
void serialWrite(uint8_t, unsigned char);
int serialAvailable(uint8_t);
int serialRead(uint8_t);
void serialFlush(uint8_t);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,116 @@
/*
wiring_analog.c - analog input and output
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
uint8_t analog_reference = DEFAULT;
void analogReference(uint8_t mode)
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
analog_reference = mode;
}
int analogRead(uint8_t pin)
{
uint8_t low, high, ch = analogInPinToBit(pin);
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
// the final AND is to clear the pos/neg reference bits
ADMUX = ((analog_reference << 6) | (pin & 0x0f)) & B11000111;
// without a delay, we seem to read from the wrong channel
//delay(1);
// start the conversion
sbi(ADCSRA, ADSC);
// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));
// we have to read ADCL first; doing so locks both ADCL
// and ADCH until ADCH is read. reading ADCL second would
// cause the results of each conversion to be discarded,
// as ADCL and ADCH would be locked when it completed.
low = ADCL;
high = ADCH;
// combine the two bytes
return (high << 8) | low;
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// pins_*.c file. For the rest of the pins, we default
// to digital output.
void analogWrite(uint8_t pin, int val)
{
// We need to make sure the PWM output is enabled for those pins
// that support it, as we turn it off when digitally reading or
// writing with them. Also, make sure the pin is in output mode
// for consistenty with Wiring, which doesn't require a pinMode
// call for the analog output pins.
pinMode(pin, OUTPUT);
if (digitalPinToTimer(pin) == TIMER1A) {
// connect pwm to pin on timer 1, channel A
sbi(TCCR1A, COM1A1);
// set pwm duty
OCR1A = val;
} else if (digitalPinToTimer(pin) == TIMER1B) {
// connect pwm to pin on timer 1, channel B
sbi(TCCR1A, COM1B1);
// set pwm duty
OCR1B = val;
} else if (digitalPinToTimer(pin) == TIMER0A) {
// connect pwm to pin on timer 0, channel A
sbi(TCCR0A, COM0A1);
// set pwm duty
OCR0A = val;
} else if (digitalPinToTimer(pin) == TIMER0B) {
// connect pwm to pin on timer 0, channel B
sbi(TCCR0A, COM0B1);
// set pwm duty
OCR0B = val;
} else if (digitalPinToTimer(pin) == TIMER2A) {
// connect pwm to pin on timer 2, channel A
sbi(TCCR2A, COM2A1);
// set pwm duty
OCR2A = val;
} else if (digitalPinToTimer(pin) == TIMER2B) {
// connect pwm to pin on timer 2, channel B
sbi(TCCR2A, COM2B1);
// set pwm duty
OCR2B = val;
} else if (val < 128)
//fail semi-intelligently
digitalWrite(pin, LOW);
else
digitalWrite(pin, HIGH);
}

@ -0,0 +1,95 @@
/*
wiring_digital.c - digital input and output functions
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;
if (port == NOT_A_PIN) return;
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
if (mode == INPUT) *reg &= ~bit;
else *reg |= bit;
}
// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
static inline void turnOffPWM(uint8_t timer)
{
if (timer == TIMER0A) cbi(TCCR0A, COM0A1);
if (timer == TIMER0B) cbi(TCCR0A, COM0B1);
if (timer == TIMER1A) cbi(TCCR1A, COM1A1);
if (timer == TIMER1B) cbi(TCCR1A, COM1B1);
if (timer == TIMER2A) cbi(TCCR2A, COM2A1);
if (timer == TIMER2B) cbi(TCCR2A, COM2B1);
}
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
if (val == LOW) *out &= ~bit;
else *out |= bit;
}
int digitalRead(uint8_t pin)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

@ -0,0 +1,60 @@
/*
wiring_private.h - Internal header file.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
*/
#ifndef WiringPrivate_h
#define WiringPrivate_h
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/delay.h>
#include <stdio.h>
#include <stdarg.h>
#include "wiring.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define EXTERNAL_INT_0 0
#define EXTERNAL_INT_1 1
#define EXTERNAL_INT_2 2
#define EXTERNAL_NUM_INTERRUPTS 3
typedef void (*voidFuncPtr)(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,66 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution. calling
// digitalRead() instead yields much coarser resolution.
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask)
width++;
// convert the reading to microseconds. The loop has been determined
// to be 10 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 10 + 16);
}

@ -0,0 +1,138 @@
/*
wiring_serial.c - serial functions.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
Modified 29 January 2009, Marius Kintel for Sanguino - http://www.sanguino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
#if defined(__AVR_ATmega644P__)
unsigned char rx_buffer[2][RX_BUFFER_SIZE];
int rx_buffer_head[2] = {0, 0};
int rx_buffer_tail[2] = {0, 0};
#else
unsigned char rx_buffer[1][RX_BUFFER_SIZE];
int rx_buffer_head[1] = {0};
int rx_buffer_tail[1] = {0};
#endif
#define BEGIN_SERIAL(uart_, baud_) \
{ \
UBRR##uart_##H = ((F_CPU / 16 + baud / 2) / baud - 1) >> 8; \
UBRR##uart_##L = ((F_CPU / 16 + baud / 2) / baud - 1); \
\
/* reset config for UART */ \
UCSR##uart_##A = 0; \
UCSR##uart_##B = 0; \
UCSR##uart_##C = 0; \
\
/* enable rx and tx */ \
sbi(UCSR##uart_##B, RXEN##uart_);\
sbi(UCSR##uart_##B, TXEN##uart_);\
\
/* enable interrupt on complete reception of a byte */ \
sbi(UCSR##uart_##B, RXCIE##uart_); \
UCSR##uart_##C = _BV(UCSZ##uart_##1)|_BV(UCSZ##uart_##0); \
/* defaults to 8-bit, no parity, 1 stop bit */ \
}
void beginSerial(uint8_t uart, long baud)
{
if (uart == 0) BEGIN_SERIAL(0, baud)
#if defined(__AVR_ATmega644P__)
else BEGIN_SERIAL(1, baud)
#endif
}
#define SERIAL_WRITE(uart_, c_) \
while (!(UCSR##uart_##A & (1 << UDRE##uart_))) \
; \
UDR##uart_ = c
void serialWrite(uint8_t uart, unsigned char c)
{
if (uart == 0) {
SERIAL_WRITE(0, c);
}
#if defined(__AVR_ATmega644P__)
else {
SERIAL_WRITE(1, c);
}
#endif
}
int serialAvailable(uint8_t uart)
{
return (RX_BUFFER_SIZE + rx_buffer_head[uart] - rx_buffer_tail[uart]) % RX_BUFFER_SIZE;
}
int serialRead(uint8_t uart)
{
// if the head isn't ahead of the tail, we don't have any characters
if (rx_buffer_head[uart] == rx_buffer_tail[uart]) {
return -1;
} else {
unsigned char c = rx_buffer[uart][rx_buffer_tail[uart]];
rx_buffer_tail[uart] = (rx_buffer_tail[uart] + 1) % RX_BUFFER_SIZE;
return c;
}
}
void serialFlush(uint8_t uart)
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
rx_buffer_head[uart] = rx_buffer_tail[uart];
}
#define UART_ISR(uart_) \
ISR(USART##uart_##_RX_vect) \
{ \
unsigned char c = UDR##uart_; \
\
int i = (rx_buffer_head[uart_] + 1) % RX_BUFFER_SIZE; \
\
/* if we should be storing the received character into the location \
just before the tail (meaning that the head would advance to the \
current location of the tail), we're about to overflow the buffer \
and so we don't write the character or advance the head. */ \
if (i != rx_buffer_tail[uart_]) { \
rx_buffer[uart_][rx_buffer_head[uart_]] = c; \
rx_buffer_head[uart_] = i; \
} \
}
UART_ISR(0)
#if defined(__AVR_ATmega644P__)
UART_ISR(1)
#endif

@ -0,0 +1,40 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val)
{
int i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

Binary file not shown.

@ -0,0 +1,298 @@
# Sprinter Arduino Project Makefile
#
# Makefile Based on:
# Arduino 0011 Makefile
# Arduino adaptation by mellis, eighthave, oli.keller
#
# This has been tested with Arduino 0022.
#
# This makefile allows you to build sketches from the command line
# without the Arduino environment (or Java).
#
# Detailed instructions for using the makefile:
#
# 1. Modify the line containg "INSTALL_DIR" to point to the directory that
# contains the Arduino installation (for example, under Mac OS X, this
# might be /Applications/arduino-0012).
#
# 2. 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*).
#
# 3. Set the line containing "MCU" to match your board's processor.
# Older one's are atmega8 based, newer ones like Arduino Mini, Bluetooth
# or Diecimila have the atmega168. If you're using a LilyPad Arduino,
# change F_CPU to 8000000. If you are using Gen7 electronics, you
# probably need to use 20000000. Either way, you must regenerate
# the speed lookup table with create_speed_lookuptable.py.
#
# 4. Type "make" and press enter to compile/verify your program.
#
# 5. Type "make upload", reset your Arduino board, and press enter to
# upload your program to the Arduino board.
#
# $Id$
#For "old" Arduino Mega
#MCU = atmega1280
#For Arduino Mega2560
#MCU = atmega2560
#For Sanguinololu
MCU = atmega644p
# Here you select "arduino", "Sanguino", "Gen7", ...
HARDWARE_VARIANT = Sanguino
# This defined the board you are compiling for
HARDWARE_MOTHERBOARD = 91
# Arduino source install directory
INSTALL_DIR = ../../arduino-0022
# Arduino containd the main source code for the Arduino
# Libraries, the "hardware variant" are for boards
# that derives from that, and their source are present in
# the main Marlin source directory
ARDUINO = $(INSTALL_DIR)/hardware/arduino/cores/arduino
ifeq (${HARDWARE_VARIANT}, arduino)
HARDWARE_SRC= $(ARDUINO)
else
HARDWARE_SRC= $(HARDWARE_VARIANT)/cores/arduino
endif
# Be sure to regenerate speed_lookuptable.h with create_speed_lookuptable.py
# if you are setting this to something other than 16MHz
F_CPU = 16000000
UPLOAD_RATE = 115200
AVRDUDE_PROGRAMMER = arduino
PORT = /dev/arduino
TARGET = $(notdir $(CURDIR))
# VPATH tells make to look into these directory for source files,
# there is no need to specify explicit pathnames as long as the
# directory is added here
VPATH = .
VPATH += applet
VPATH += $(HARDWARE_SRC)
VPATH += $(ARDUINO)
VPATH += $(INSTALL_DIR)/libraries/LiquidCrystal
############################################################################
# Below here nothing should be changed...
AVR_TOOLS_PATH =
SRC = pins_arduino.c wiring.c \
wiring_analog.c wiring_digital.c \
wiring_pulse.c \
wiring_shift.c WInterrupts.c
CXXSRC = WMath.cpp WString.cpp Print.cpp \
Marlin.cpp MarlinSerial.cpp Sd2Card.cpp SdBaseFile.cpp \
SdFatUtil.cpp SdFile.cpp SdVolume.cpp motion_control.cpp \
planner.cpp stepper.cpp temperature.cpp cardreader.cpp
#CXXSRC += LiquidCrystal.cpp ultralcd.cpp
#CXXSRC += ultralcd.cpp
FORMAT = ihex
# 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)
# Add all the source directories as include directories too
CINCS = ${addprefix -I ,${VPATH}}
CXXINCS = ${addprefix -I ,${VPATH}}
# 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 -w -ffunction-sections -fdata-sections \
-DARDUINO=22
ifneq (${HARDWARE_MOTHERBOARD},)
CTUNING += -DMOTHERBOARD=${HARDWARE_MOTHERBOARD}
endif
#CEXTRA = -Wa,-adhlns=$(<:.c=.lst)
CFLAGS = $(CDEBUG) $(CDEFS) $(CINCS) -O$(OPT) $(CWARN) $(CEXTRA) $(CTUNING)
CXXFLAGS = $(CDEFS) $(CINCS) -O$(OPT) -Wall $(CEXTRA) $(CTUNING)
#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs
LDFLAGS = -lm
# Programming support using avrdude. Settings and variables.
AVRDUDE_PORT = $(PORT)
AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex:i
AVRDUDE_FLAGS = -D -C $(INSTALL_DIR)/hardware/tools/avrdude.conf \
-p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \
-b $(UPLOAD_RATE)
# Program settings
CC = $(AVR_TOOLS_PATH)avr-gcc
CXX = $(AVR_TOOLS_PATH)avr-g++
OBJCOPY = $(AVR_TOOLS_PATH)avr-objcopy
OBJDUMP = $(AVR_TOOLS_PATH)avr-objdump
AR = $(AVR_TOOLS_PATH)avr-ar
SIZE = $(AVR_TOOLS_PATH)avr-size
NM = $(AVR_TOOLS_PATH)avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
MV = mv -f
# Define all object files.
OBJ = ${patsubst %.c, applet/%.o, ${SRC}}
OBJ += ${patsubst %.cpp, applet/%.o, ${CXXSRC}}
OBJ += ${patsubst %.S, applet/%.o, ${ASRC}}
# 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) $(CXXFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp $(ASFLAGS)
# set V=1 (eg, "make V=1") to print the full commands etc.
ifneq ($V,1)
Pecho=@echo
P=@
else
Pecho=@:
P=
endif
# Default target.
all: sizeafter
build: applet elf hex
# Creates the object directory
applet:
$P mkdir -p applet
# the .cpp for Marlin depends on the .pde
#applet/$(TARGET).cpp: $(TARGET).pde
# ..and the .o depends from the .cpp
#applet/%.o: applet/%.cpp
applet/%.cpp: %.pde $(MAKEFILE)
# Here is the "preprocessing".
# It creates a .cpp file based with the same name as the .pde file.
# On top of the new .cpp file comes the WProgram.h header.
$(Pecho) " WR $@"
$P echo '#include "WProgram.h"' > $@
$P echo '#include "$<"' >>$@
$P echo '#include "$(ARDUINO)/main.cpp"' >> $@
elf: applet/$(TARGET).elf
hex: applet/$(TARGET).hex
eep: applet/$(TARGET).eep
lss: applet/$(TARGET).lss
sym: applet/$(TARGET).sym
# Program the device.
# Do not try to reset an arduino if it's not one
upload: applet/$(TARGET).hex
ifeq (${AVRDUDE_PROGRAMMER}, arduino)
stty hup < $(PORT); true
endif
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH)
ifeq (${AVRDUDE_PROGRAMMER}, arduino)
stty -hup < $(PORT); true
endif
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) applet/$(TARGET).hex
ELFSIZE = $(SIZE) --mcu=$(MCU) -C applet/$(TARGET).elf; \
$(SIZE) applet/$(TARGET).elf
sizebefore:
$P if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_BEFORE); $(HEXSIZE); echo; fi
sizeafter: build
$P if [ -f applet/$(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
# 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 $(TARGET).cof
extcoff: $(TARGET).elf
$(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf $(TARGET).cof
.SUFFIXES: .elf .hex .eep .lss .sym
.PRECIOUS: .o
.elf.hex:
$(Pecho) " COPY $@"
$P $(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 $< > $@
# Link: create ELF output file from library.
applet/$(TARGET).elf: applet/$(TARGET).cpp applet/core.a Configuration.h
$(Pecho) " CXX $@"
$P $(CC) $(ALL_CXXFLAGS) -Wl,--gc-sections -o $@ applet/$(TARGET).cpp -L. applet/core.a $(LDFLAGS)
applet/core.a: $(OBJ)
$P for i in $(OBJ); do echo " AR $$i"; $(AR) rcs applet/core.a $$i; done
applet/%.o: %.c Configuration.h Configuration_adv.h $(MAKEFILE)
$(Pecho) " CC $@"
$P $(CC) -MMD -c $(ALL_CFLAGS) $< -o $@
applet/%.o: %.cpp Configuration.h Configuration_adv.h $(MAKEFILE)
$(Pecho) " CXX $@"
$P $(CXX) -MMD -c $(ALL_CXXFLAGS) $< -o $@
# Target: clean project.
clean:
$(Pecho) " RM applet/*"
$P $(REMOVE) applet/$(TARGET).hex applet/$(TARGET).eep applet/$(TARGET).cof applet/$(TARGET).elf \
applet/$(TARGET).map applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp applet/core.a \
$(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d)
$(Pecho) " RMDIR applet/"
$P rm -rf applet
.PHONY: all build elf hex eep lss sym program coff extcoff clean depend applet_files sizebefore sizeafter
# Automaticaly include the dependency files created by gcc
-include ${wildcard applet/*.d}

@ -0,0 +1,203 @@
// Tonokip RepRap firmware rewrite based off of Hydra-mmm firmware.
// Licence: GPL
#ifndef MARLIN_H
#define MARLIN_H
#define HardwareSerial_h // trick to disable the standard HWserial
#define FORCE_INLINE __attribute__((always_inline)) inline
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include "fastio.h"
#include "Configuration.h"
#include "pins.h"
#if ARDUINO >= 100
#if defined(__AVR_ATmega644P__)
#include "WProgram.h"
#else
#include "Arduino.h"
#endif
#else
#include "WProgram.h"
#endif
#include "MarlinSerial.h"
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#include "WString.h"
#if MOTHERBOARD == 8 // Teensylu
#define MYSERIAL Serial
#else
#define MYSERIAL MSerial
#endif
//this is a unfinsihed attemp to removes a lot of warning messages, see:
// http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=57011
//typedef char prog_char PROGMEM;
// //#define PSTR (s ) ((const PROGMEM char *)(s))
// //# define MYPGM(s) (__extension__({static prog_char __c[] = (s); &__c[0];}))
// //#define MYPGM(s) ((const prog_char *g PROGMEM=s))
#define MYPGM(s) PSTR(s)
//#define MYPGM(s) (__extension__({static char __c[] __attribute__((__progmem__)) = (s); &__c[0];})) //This is the normal behaviour
//#define MYPGM(s) (__extension__({static prog_char __c[] = (s); &__c[0];})) //this does not work but hides the warnings
#define SERIAL_PROTOCOL(x) MYSERIAL.print(x);
#define SERIAL_PROTOCOL_F(x,y) MYSERIAL.print(x,y);
#define SERIAL_PROTOCOLPGM(x) serialprintPGM(MYPGM(x));
#define SERIAL_PROTOCOLLN(x) {MYSERIAL.print(x);MYSERIAL.write('\n');}
#define SERIAL_PROTOCOLLNPGM(x) {serialprintPGM(MYPGM(x));MYSERIAL.write('\n');}
const char errormagic[] PROGMEM ="Error:";
const char echomagic[] PROGMEM ="echo:";
#define SERIAL_ERROR_START serialprintPGM(errormagic);
#define SERIAL_ERROR(x) SERIAL_PROTOCOL(x)
#define SERIAL_ERRORPGM(x) SERIAL_PROTOCOLPGM(x)
#define SERIAL_ERRORLN(x) SERIAL_PROTOCOLLN(x)
#define SERIAL_ERRORLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
#define SERIAL_ECHO_START serialprintPGM(echomagic);
#define SERIAL_ECHO(x) SERIAL_PROTOCOL(x)
#define SERIAL_ECHOPGM(x) SERIAL_PROTOCOLPGM(x)
#define SERIAL_ECHOLN(x) SERIAL_PROTOCOLLN(x)
#define SERIAL_ECHOLNPGM(x) SERIAL_PROTOCOLLNPGM(x)
#define SERIAL_ECHOPAIR(name,value) (serial_echopair_P(PSTR(name),(value)))
void serial_echopair_P(const char *s_P, float v);
void serial_echopair_P(const char *s_P, double v);
void serial_echopair_P(const char *s_P, unsigned long v);
//things to write to serial from Programmemory. saves 400 to 2k of RAM.
#define SerialprintPGM(x) serialprintPGM(MYPGM(x))
FORCE_INLINE void serialprintPGM(const char *str)
{
char ch=pgm_read_byte(str);
while(ch)
{
MYSERIAL.write(ch);
ch=pgm_read_byte(++str);
}
}
void get_command();
void process_commands();
void manage_inactivity();
#if X_ENABLE_PIN > -1
#define enable_x() WRITE(X_ENABLE_PIN, X_ENABLE_ON)
#define disable_x() WRITE(X_ENABLE_PIN,!X_ENABLE_ON)
#else
#define enable_x() ;
#define disable_x() ;
#endif
#if Y_ENABLE_PIN > -1
#define enable_y() WRITE(Y_ENABLE_PIN, Y_ENABLE_ON)
#define disable_y() WRITE(Y_ENABLE_PIN,!Y_ENABLE_ON)
#else
#define enable_y() ;
#define disable_y() ;
#endif
#if Z_ENABLE_PIN > -1
#ifdef Z_DUAL_STEPPER_DRIVERS
#define enable_z() { WRITE(Z_ENABLE_PIN, Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN, Z_ENABLE_ON); }
#define disable_z() { WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON); WRITE(Z2_ENABLE_PIN,!Z_ENABLE_ON); }
#else
#define enable_z() WRITE(Z_ENABLE_PIN, Z_ENABLE_ON)
#define disable_z() WRITE(Z_ENABLE_PIN,!Z_ENABLE_ON)
#endif
#else
#define enable_z() ;
#define disable_z() ;
#endif
#if defined(E0_ENABLE_PIN) && (E0_ENABLE_PIN > -1)
#define enable_e0() WRITE(E0_ENABLE_PIN, E_ENABLE_ON)
#define disable_e0() WRITE(E0_ENABLE_PIN,!E_ENABLE_ON)
#else
#define enable_e0() /* nothing */
#define disable_e0() /* nothing */
#endif
#if (EXTRUDERS > 1) && defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
#define enable_e1() WRITE(E1_ENABLE_PIN, E_ENABLE_ON)
#define disable_e1() WRITE(E1_ENABLE_PIN,!E_ENABLE_ON)
#else
#define enable_e1() /* nothing */
#define disable_e1() /* nothing */
#endif
#if (EXTRUDERS > 2) && defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
#define enable_e2() WRITE(E2_ENABLE_PIN, E_ENABLE_ON)
#define disable_e2() WRITE(E2_ENABLE_PIN,!E_ENABLE_ON)
#else
#define enable_e2() /* nothing */
#define disable_e2() /* nothing */
#endif
enum AxisEnum {X_AXIS=0, Y_AXIS=1, Z_AXIS=2, E_AXIS=3};
void FlushSerialRequestResend();
void ClearToSend();
void get_coordinates();
void prepare_move();
void kill();
void Stop();
bool IsStopped();
void enquecommand(const char *cmd); //put an ascii command at the end of the current buffer.
void prepare_arc_move(char isclockwise);
void clamp_to_software_endstops(float target[3]);
#ifdef FAST_PWM_FAN
void setPwmFrequency(uint8_t pin, int val);
#endif
#ifndef CRITICAL_SECTION_START
#define CRITICAL_SECTION_START unsigned char _sreg = SREG; cli();
#define CRITICAL_SECTION_END SREG = _sreg;
#endif //CRITICAL_SECTION_START
extern float homing_feedrate[];
extern bool axis_relative_modes[];
extern float current_position[NUM_AXIS] ;
extern float add_homeing[3];
extern float min_pos[3];
extern float max_pos[3];
extern unsigned char FanSpeed;
// Handling multiple extruders pins
extern uint8_t active_extruder;
#endif

@ -0,0 +1,1832 @@
/* -*- c++ -*- */
/*
Reprap firmware based on Sprinter and grbl.
Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This firmware is a mashup between Sprinter and grbl.
(https://github.com/kliment/Sprinter)
(https://github.com/simen/grbl/tree)
It has preliminary support for Matthew Roberts advance algorithm
http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
*/
#include "Marlin.h"
#include "ultralcd.h"
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "motion_control.h"
#include "cardreader.h"
#include "watchdog.h"
#include "EEPROMwrite.h"
#include "language.h"
#include "pins_arduino.h"
#define VERSION_STRING "1.0.0"
// look here for descriptions of gcodes: http://linuxcnc.org/handbook/gcode/g-code.html
// http://objects.reprap.org/wiki/Mendel_User_Manual:_RepRapGCodes
//Implemented Codes
//-------------------
// G0 -> G1
// G1 - Coordinated Movement X Y Z E
// G2 - CW ARC
// G3 - CCW ARC
// G4 - Dwell S<seconds> or P<milliseconds>
// G10 - retract filament according to settings of M207
// G11 - retract recover filament according to settings of M208
// G28 - Home all Axis
// G90 - Use Absolute Coordinates
// G91 - Use Relative Coordinates
// G92 - Set current position to cordinates given
//RepRap M Codes
// M0 - Unconditional stop - Wait for user to press a button on the LCD (Only if ULTRA_LCD is enabled)
// M1 - Same as M0
// M104 - Set extruder target temp
// M105 - Read current temp
// M106 - Fan on
// M107 - Fan off
// M109 - Wait for extruder current temp to reach target temp.
// M114 - Display current position
//Custom M Codes
// M17 - Enable/Power all stepper motors
// M18 - Disable all stepper motors; same as M84
// M20 - List SD card
// M21 - Init SD card
// M22 - Release SD card
// M23 - Select SD file (M23 filename.g)
// M24 - Start/resume SD print
// M25 - Pause SD print
// M26 - Set SD position in bytes (M26 S12345)
// M27 - Report SD print status
// M28 - Start SD write (M28 filename.g)
// M29 - Stop SD write
// M30 - Delete file from SD (M30 filename.g)
// M31 - Output time since last M109 or SD card start to serial
// M42 - Change pin status via gcode
// M80 - Turn on Power Supply
// M81 - Turn off Power Supply
// M82 - Set E codes absolute (default)
// M83 - Set E codes relative while in Absolute Coordinates (G90) mode
// M84 - Disable steppers until next move,
// or use S<seconds> to specify an inactivity timeout, after which the steppers will be disabled. S0 to disable the timeout.
// M85 - Set inactivity shutdown timer with parameter S<seconds>. To disable set zero (default)
// M92 - Set axis_steps_per_unit - same syntax as G92
// M114 - Output current position to serial port
// M115 - Capabilities string
// M117 - display message
// M119 - Output Endstop status to serial port
// M140 - Set bed target temp
// M190 - Wait for bed current temp to reach target temp.
// M200 - Set filament diameter
// M201 - Set max acceleration in units/s^2 for print moves (M201 X1000 Y1000)
// M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
// M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
// M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate
// M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk, E=maximum E jerk
// M206 - set additional homeing offset
// M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
// M208 - set recover=unretract length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
// M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
// M220 S<factor in percent>- set speed factor override percentage
// M221 S<factor in percent>- set extrude factor override percentage
// M240 - Trigger a camera to take a photograph
// M301 - Set PID parameters P I and D
// M302 - Allow cold extrudes
// M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
// M400 - Finish all moves
// M500 - stores paramters in EEPROM
// M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
// M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
// M503 - print the current settings (from memory not from eeprom)
// M999 - Restart after being stopped by error
//Stepper Movement Variables
//===========================================================================
//=============================imported variables============================
//===========================================================================
//===========================================================================
//=============================public variables=============================
//===========================================================================
#ifdef SDSUPPORT
CardReader card;
#endif
float homing_feedrate[] = HOMING_FEEDRATE;
bool axis_relative_modes[] = AXIS_RELATIVE_MODES;
volatile int feedmultiply=100; //100->1 200->2
int saved_feedmultiply;
volatile bool feedmultiplychanged=false;
volatile int extrudemultiply=100; //100->1 200->2
float current_position[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0 };
float add_homeing[3]={0,0,0};
float min_pos[3] = { X_MIN_POS, Y_MIN_POS, Z_MIN_POS };
float max_pos[3] = { X_MAX_POS, Y_MAX_POS, Z_MAX_POS };
uint8_t active_extruder = 0;
unsigned char FanSpeed=0;
#ifdef FWRETRACT
bool autoretract_enabled=true;
bool retracted=false;
float retract_length=3, retract_feedrate=17*60, retract_zlift=0.8;
float retract_recover_length=0, retract_recover_feedrate=8*60;
#endif
//===========================================================================
//=============================private variables=============================
//===========================================================================
const char axis_codes[NUM_AXIS] = {'X', 'Y', 'Z', 'E'};
static float destination[NUM_AXIS] = { 0.0, 0.0, 0.0, 0.0};
static float offset[3] = {0.0, 0.0, 0.0};
static bool home_all_axis = true;
static float feedrate = 1500.0, next_feedrate, saved_feedrate;
static long gcode_N, gcode_LastN, Stopped_gcode_LastN = 0;
static bool relative_mode = false; //Determines Absolute or Relative Coordinates
static bool relative_mode_e = false; //Determines Absolute or Relative E Codes while in Absolute Coordinates mode. E is always relative in Relative Coordinates mode.
static char cmdbuffer[BUFSIZE][MAX_CMD_SIZE];
static bool fromsd[BUFSIZE];
static int bufindr = 0;
static int bufindw = 0;
static int buflen = 0;
//static int i = 0;
static char serial_char;
static int serial_count = 0;
static boolean comment_mode = false;
static char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc
const int sensitive_pins[] = SENSITIVE_PINS; // Sensitive pin list for M42
//static float tt = 0;
//static float bt = 0;
//Inactivity shutdown variables
static unsigned long previous_millis_cmd = 0;
static unsigned long max_inactive_time = 0;
static unsigned long stepper_inactive_time = DEFAULT_STEPPER_DEACTIVE_TIME*1000l;
static unsigned long starttime=0;
static unsigned long stoptime=0;
static uint8_t tmp_extruder;
bool Stopped=false;
//===========================================================================
//=============================ROUTINES=============================
//===========================================================================
void get_arc_coordinates();
void serial_echopair_P(const char *s_P, float v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_P(const char *s_P, double v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_P(const char *s_P, unsigned long v)
{ serialprintPGM(s_P); SERIAL_ECHO(v); }
extern "C"{
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;
int freeMemory() {
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;
}
}
//adds an command to the main command buffer
//thats really done in a non-safe way.
//needs overworking someday
void enquecommand(const char *cmd)
{
if(buflen < BUFSIZE)
{
//this is dangerous if a mixing of serial and this happsens
strcpy(&(cmdbuffer[bufindw][0]),cmd);
SERIAL_ECHO_START;
SERIAL_ECHOPGM("enqueing \"");
SERIAL_ECHO(cmdbuffer[bufindw]);
SERIAL_ECHOLNPGM("\"");
bufindw= (bufindw + 1)%BUFSIZE;
buflen += 1;
}
}
void setup_killpin()
{
#if( KILL_PIN>-1 )
pinMode(KILL_PIN,INPUT);
WRITE(KILL_PIN,HIGH);
#endif
}
void setup_photpin()
{
#ifdef PHOTOGRAPH_PIN
#if (PHOTOGRAPH_PIN > -1)
SET_OUTPUT(PHOTOGRAPH_PIN);
WRITE(PHOTOGRAPH_PIN, LOW);
#endif
#endif
}
void setup_powerhold()
{
#ifdef SUICIDE_PIN
#if (SUICIDE_PIN> -1)
SET_OUTPUT(SUICIDE_PIN);
WRITE(SUICIDE_PIN, HIGH);
#endif
#endif
}
void suicide()
{
#ifdef SUICIDE_PIN
#if (SUICIDE_PIN> -1)
SET_OUTPUT(SUICIDE_PIN);
WRITE(SUICIDE_PIN, LOW);
#endif
#endif
}
void setup()
{
setup_killpin();
setup_powerhold();
MYSERIAL.begin(BAUDRATE);
SERIAL_PROTOCOLLNPGM("start");
SERIAL_ECHO_START;
// Check startup - does nothing if bootloader sets MCUSR to 0
byte mcu = MCUSR;
if(mcu & 1) SERIAL_ECHOLNPGM(MSG_POWERUP);
if(mcu & 2) SERIAL_ECHOLNPGM(MSG_EXTERNAL_RESET);
if(mcu & 4) SERIAL_ECHOLNPGM(MSG_BROWNOUT_RESET);
if(mcu & 8) SERIAL_ECHOLNPGM(MSG_WATCHDOG_RESET);
if(mcu & 32) SERIAL_ECHOLNPGM(MSG_SOFTWARE_RESET);
MCUSR=0;
SERIAL_ECHOPGM(MSG_MARLIN);
SERIAL_ECHOLNPGM(VERSION_STRING);
#ifdef STRING_VERSION_CONFIG_H
#ifdef STRING_CONFIG_H_AUTHOR
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_CONFIGURATION_VER);
SERIAL_ECHOPGM(STRING_VERSION_CONFIG_H);
SERIAL_ECHOPGM(MSG_AUTHOR);
SERIAL_ECHOLNPGM(STRING_CONFIG_H_AUTHOR);
#endif
#endif
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_FREE_MEMORY);
SERIAL_ECHO(freeMemory());
SERIAL_ECHOPGM(MSG_PLANNER_BUFFER_BYTES);
SERIAL_ECHOLN((int)sizeof(block_t)*BLOCK_BUFFER_SIZE);
for(int8_t i = 0; i < BUFSIZE; i++)
{
fromsd[i] = false;
}
EEPROM_RetrieveSettings(); // loads data from EEPROM if available
for(int8_t i=0; i < NUM_AXIS; i++)
{
axis_steps_per_sqr_second[i] = max_acceleration_units_per_sq_second[i] * axis_steps_per_unit[i];
}
tp_init(); // Initialize temperature loop
plan_init(); // Initialize planner;
st_init(); // Initialize stepper;
wd_init();
setup_photpin();
LCD_INIT;
}
void loop()
{
if(buflen < (BUFSIZE-1))
get_command();
#ifdef SDSUPPORT
card.checkautostart(false);
#endif
if(buflen)
{
#ifdef SDSUPPORT
if(card.saving)
{
if(strstr(cmdbuffer[bufindr],"M29") == NULL)
{
card.write_command(cmdbuffer[bufindr]);
SERIAL_PROTOCOLLNPGM(MSG_OK);
}
else
{
card.closefile();
SERIAL_PROTOCOLLNPGM(MSG_FILE_SAVED);
}
}
else
{
process_commands();
}
#else
process_commands();
#endif //SDSUPPORT
buflen = (buflen-1);
bufindr = (bufindr + 1)%BUFSIZE;
}
//check heater every n milliseconds
manage_heater();
manage_inactivity();
checkHitEndstops();
LCD_STATUS;
}
void get_command()
{
while( MYSERIAL.available() > 0 && buflen < BUFSIZE) {
serial_char = MYSERIAL.read();
if(serial_char == '\n' ||
serial_char == '\r' ||
(serial_char == ':' && comment_mode == false) ||
serial_count >= (MAX_CMD_SIZE - 1) )
{
if(!serial_count) { //if empty line
comment_mode = false; //for new command
return;
}
cmdbuffer[bufindw][serial_count] = 0; //terminate string
if(!comment_mode){
comment_mode = false; //for new command
fromsd[bufindw] = false;
if(strstr(cmdbuffer[bufindw], "N") != NULL)
{
strchr_pointer = strchr(cmdbuffer[bufindw], 'N');
gcode_N = (strtol(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL, 10));
if(gcode_N != gcode_LastN+1 && (strstr(cmdbuffer[bufindw], "M110") == NULL) ) {
SERIAL_ERROR_START;
SERIAL_ERRORPGM(MSG_ERR_LINE_NO);
SERIAL_ERRORLN(gcode_LastN);
//Serial.println(gcode_N);
FlushSerialRequestResend();
serial_count = 0;
return;
}
if(strstr(cmdbuffer[bufindw], "*") != NULL)
{
byte checksum = 0;
byte count = 0;
while(cmdbuffer[bufindw][count] != '*') checksum = checksum^cmdbuffer[bufindw][count++];
strchr_pointer = strchr(cmdbuffer[bufindw], '*');
if( (int)(strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)) != checksum) {
SERIAL_ERROR_START;
SERIAL_ERRORPGM(MSG_ERR_CHECKSUM_MISMATCH);
SERIAL_ERRORLN(gcode_LastN);
FlushSerialRequestResend();
serial_count = 0;
return;
}
//if no errors, continue parsing
}
else
{
SERIAL_ERROR_START;
SERIAL_ERRORPGM(MSG_ERR_NO_CHECKSUM);
SERIAL_ERRORLN(gcode_LastN);
FlushSerialRequestResend();
serial_count = 0;
return;
}
gcode_LastN = gcode_N;
//if no errors, continue parsing
}
else // if we don't receive 'N' but still see '*'
{
if((strstr(cmdbuffer[bufindw], "*") != NULL))
{
SERIAL_ERROR_START;
SERIAL_ERRORPGM(MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM);
SERIAL_ERRORLN(gcode_LastN);
serial_count = 0;
return;
}
}
if((strstr(cmdbuffer[bufindw], "G") != NULL)){
strchr_pointer = strchr(cmdbuffer[bufindw], 'G');
switch((int)((strtod(&cmdbuffer[bufindw][strchr_pointer - cmdbuffer[bufindw] + 1], NULL)))){
case 0:
case 1:
case 2:
case 3:
if(Stopped == false) { // If printer is stopped by an error the G[0-3] codes are ignored.
#ifdef SDSUPPORT
if(card.saving)
break;
#endif //SDSUPPORT
SERIAL_PROTOCOLLNPGM(MSG_OK);
}
else {
SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
}
break;
default:
break;
}
}
bufindw = (bufindw + 1)%BUFSIZE;
buflen += 1;
}
serial_count = 0; //clear buffer
}
else
{
if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
}
}
#ifdef SDSUPPORT
if(!card.sdprinting || serial_count!=0){
return;
}
while( !card.eof() && buflen < BUFSIZE) {
int16_t n=card.get();
serial_char = (char)n;
if(serial_char == '\n' ||
serial_char == '\r' ||
(serial_char == ':' && comment_mode == false) ||
serial_count >= (MAX_CMD_SIZE - 1)||n==-1)
{
if(card.eof()){
SERIAL_PROTOCOLLNPGM(MSG_FILE_PRINTED);
stoptime=millis();
char time[30];
unsigned long t=(stoptime-starttime)/1000;
int sec,min;
min=t/60;
sec=t%60;
sprintf(time,"%i min, %i sec",min,sec);
SERIAL_ECHO_START;
SERIAL_ECHOLN(time);
LCD_MESSAGE(time);
card.printingHasFinished();
card.checkautostart(true);
}
if(!serial_count)
{
comment_mode = false; //for new command
return; //if empty line
}
cmdbuffer[bufindw][serial_count] = 0; //terminate string
// if(!comment_mode){
fromsd[bufindw] = true;
buflen += 1;
bufindw = (bufindw + 1)%BUFSIZE;
// }
comment_mode = false; //for new command
serial_count = 0; //clear buffer
}
else
{
if(serial_char == ';') comment_mode = true;
if(!comment_mode) cmdbuffer[bufindw][serial_count++] = serial_char;
}
}
#endif //SDSUPPORT
}
float code_value()
{
return (strtod(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL));
}
long code_value_long()
{
return (strtol(&cmdbuffer[bufindr][strchr_pointer - cmdbuffer[bufindr] + 1], NULL, 10));
}
bool code_seen(char code_string[]) //Return True if the string was found
{
return (strstr(cmdbuffer[bufindr], code_string) != NULL);
}
bool code_seen(char code)
{
strchr_pointer = strchr(cmdbuffer[bufindr], code);
return (strchr_pointer != NULL); //Return True if a character was found
}
#define DEFINE_PGM_READ_ANY(type, reader) \
static inline type pgm_read_any(const type *p) \
{ return pgm_read_##reader##_near(p); }
DEFINE_PGM_READ_ANY(float, float);
DEFINE_PGM_READ_ANY(signed char, byte);
#define XYZ_CONSTS_FROM_CONFIG(type, array, CONFIG) \
static const PROGMEM type array##_P[3] = \
{ X_##CONFIG, Y_##CONFIG, Z_##CONFIG }; \
static inline type array(int axis) \
{ return pgm_read_any(&array##_P[axis]); }
XYZ_CONSTS_FROM_CONFIG(float, base_min_pos, MIN_POS);
XYZ_CONSTS_FROM_CONFIG(float, base_max_pos, MAX_POS);
XYZ_CONSTS_FROM_CONFIG(float, base_home_pos, HOME_POS);
XYZ_CONSTS_FROM_CONFIG(float, max_length, MAX_LENGTH);
XYZ_CONSTS_FROM_CONFIG(float, home_retract_mm, HOME_RETRACT_MM);
XYZ_CONSTS_FROM_CONFIG(signed char, home_dir, HOME_DIR);
static void axis_is_at_home(int axis) {
current_position[axis] = base_home_pos(axis) + add_homeing[axis];
min_pos[axis] = base_min_pos(axis) + add_homeing[axis];
max_pos[axis] = base_max_pos(axis) + add_homeing[axis];
}
static void homeaxis(int axis) {
#define HOMEAXIS_DO(LETTER) \
((LETTER##_MIN_PIN > -1 && LETTER##_HOME_DIR==-1) || (LETTER##_MAX_PIN > -1 && LETTER##_HOME_DIR==1))
if (axis==X_AXIS ? HOMEAXIS_DO(X) :
axis==Y_AXIS ? HOMEAXIS_DO(Y) :
axis==Z_AXIS ? HOMEAXIS_DO(Z) :
0) {
current_position[axis] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[axis] = 1.5 * max_length(axis) * home_dir(axis);
feedrate = homing_feedrate[axis];
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
current_position[axis] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[axis] = -home_retract_mm(axis) * home_dir(axis);
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
destination[axis] = 2*home_retract_mm(axis) * home_dir(axis);
feedrate = homing_feedrate[axis]/2 ;
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
axis_is_at_home(axis);
destination[axis] = current_position[axis];
feedrate = 0.0;
endstops_hit_on_purpose();
}
}
#define HOMEAXIS(LETTER) homeaxis(LETTER##_AXIS)
void process_commands()
{
unsigned long codenum; //throw away variable
char *starpos = NULL;
if(code_seen('G'))
{
switch((int)code_value())
{
case 0: // G0 -> G1
case 1: // G1
if(Stopped == false) {
get_coordinates(); // For X Y Z E F
prepare_move();
//ClearToSend();
return;
}
//break;
case 2: // G2 - CW ARC
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(true);
return;
}
case 3: // G3 - CCW ARC
if(Stopped == false) {
get_arc_coordinates();
prepare_arc_move(false);
return;
}
case 4: // G4 dwell
LCD_MESSAGEPGM(MSG_DWELL);
codenum = 0;
if(code_seen('P')) codenum = code_value(); // milliseconds to wait
if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
st_synchronize();
codenum += millis(); // keep track of when we started waiting
previous_millis_cmd = millis();
while(millis() < codenum ){
manage_heater();
manage_inactivity();
LCD_STATUS;
}
break;
#ifdef FWRETRACT
case 10: // G10 retract
if(!retracted)
{
destination[X_AXIS]=current_position[X_AXIS];
destination[Y_AXIS]=current_position[Y_AXIS];
destination[Z_AXIS]=current_position[Z_AXIS];
current_position[Z_AXIS]+=-retract_zlift;
destination[E_AXIS]=current_position[E_AXIS]-retract_length;
feedrate=retract_feedrate;
retracted=true;
prepare_move();
}
break;
case 11: // G10 retract_recover
if(!retracted)
{
destination[X_AXIS]=current_position[X_AXIS];
destination[Y_AXIS]=current_position[Y_AXIS];
destination[Z_AXIS]=current_position[Z_AXIS];
current_position[Z_AXIS]+=retract_zlift;
current_position[E_AXIS]+=-retract_recover_length;
feedrate=retract_recover_feedrate;
retracted=false;
prepare_move();
}
break;
#endif //FWRETRACT
case 28: //G28 Home all Axis one at a time
saved_feedrate = feedrate;
saved_feedmultiply = feedmultiply;
feedmultiply = 100;
previous_millis_cmd = millis();
enable_endstops(true);
for(int8_t i=0; i < NUM_AXIS; i++) {
destination[i] = current_position[i];
}
feedrate = 0.0;
home_all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2])));
#if Z_HOME_DIR > 0 // If homing away from BED do Z first
if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
HOMEAXIS(Z);
}
#endif
#ifdef QUICK_HOME
if((home_all_axis)||( code_seen(axis_codes[X_AXIS]) && code_seen(axis_codes[Y_AXIS])) ) //first diagonal move
{
current_position[X_AXIS] = 0;current_position[Y_AXIS] = 0;
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[X_AXIS] = 1.5 * X_MAX_LENGTH * X_HOME_DIR;destination[Y_AXIS] = 1.5 * Y_MAX_LENGTH * Y_HOME_DIR;
feedrate = homing_feedrate[X_AXIS];
if(homing_feedrate[Y_AXIS]<feedrate)
feedrate =homing_feedrate[Y_AXIS];
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
st_synchronize();
axis_is_at_home(X_AXIS);
axis_is_at_home(Y_AXIS);
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
destination[X_AXIS] = current_position[X_AXIS];
destination[Y_AXIS] = current_position[Y_AXIS];
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
feedrate = 0.0;
st_synchronize();
endstops_hit_on_purpose();
}
#endif
if((home_all_axis) || (code_seen(axis_codes[X_AXIS])))
{
HOMEAXIS(X);
}
if((home_all_axis) || (code_seen(axis_codes[Y_AXIS]))) {
HOMEAXIS(Y);
}
#if Z_HOME_DIR < 0 // If homing towards BED do Z last
if((home_all_axis) || (code_seen(axis_codes[Z_AXIS]))) {
HOMEAXIS(Z);
}
#endif
if(code_seen(axis_codes[X_AXIS]))
{
if(code_value_long() != 0) {
current_position[X_AXIS]=code_value()+add_homeing[0];
}
}
if(code_seen(axis_codes[Y_AXIS])) {
if(code_value_long() != 0) {
current_position[Y_AXIS]=code_value()+add_homeing[1];
}
}
if(code_seen(axis_codes[Z_AXIS])) {
if(code_value_long() != 0) {
current_position[Z_AXIS]=code_value()+add_homeing[2];
}
}
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
#ifdef ENDSTOPS_ONLY_FOR_HOMING
enable_endstops(false);
#endif
feedrate = saved_feedrate;
feedmultiply = saved_feedmultiply;
previous_millis_cmd = millis();
endstops_hit_on_purpose();
break;
case 90: // G90
relative_mode = false;
break;
case 91: // G91
relative_mode = true;
break;
case 92: // G92
if(!code_seen(axis_codes[E_AXIS]))
st_synchronize();
for(int8_t i=0; i < NUM_AXIS; i++) {
if(code_seen(axis_codes[i])) {
if(i == E_AXIS) {
current_position[i] = code_value();
plan_set_e_position(current_position[E_AXIS]);
}
else {
current_position[i] = code_value()+add_homeing[i];
plan_set_position(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS], current_position[E_AXIS]);
}
}
}
break;
}
}
else if(code_seen('M'))
{
switch( (int)code_value() )
{
#ifdef ULTRA_LCD
case 0: // M0 - Unconditional stop - Wait for user button press on LCD
case 1: // M1 - Conditional stop - Wait for user button press on LCD
{
LCD_MESSAGEPGM(MSG_USERWAIT);
codenum = 0;
if(code_seen('P')) codenum = code_value(); // milliseconds to wait
if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait
st_synchronize();
previous_millis_cmd = millis();
if (codenum > 0){
codenum += millis(); // keep track of when we started waiting
while(millis() < codenum && !CLICKED){
manage_heater();
manage_inactivity();
LCD_STATUS;
}
}else{
while(!CLICKED){
manage_heater();
manage_inactivity();
LCD_STATUS;
}
}
}
break;
#endif
case 17:
LCD_MESSAGEPGM(MSG_NO_MOVE);
enable_x();
enable_y();
enable_z();
enable_e0();
enable_e1();
enable_e2();
break;
#ifdef SDSUPPORT
case 20: // M20 - list SD card
SERIAL_PROTOCOLLNPGM(MSG_BEGIN_FILE_LIST);
card.ls();
SERIAL_PROTOCOLLNPGM(MSG_END_FILE_LIST);
break;
case 21: // M21 - init SD card
card.initsd();
break;
case 22: //M22 - release SD card
card.release();
break;
case 23: //M23 - Select file
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos!=NULL)
*(starpos-1)='\0';
card.openFile(strchr_pointer + 4,true);
break;
case 24: //M24 - Start SD print
card.startFileprint();
starttime=millis();
break;
case 25: //M25 - Pause SD print
card.pauseSDPrint();
break;
case 26: //M26 - Set SD index
if(card.cardOK && code_seen('S')) {
card.setIndex(code_value_long());
}
break;
case 27: //M27 - Get SD status
card.getStatus();
break;
case 28: //M28 - Start SD write
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos != NULL){
char* npos = strchr(cmdbuffer[bufindr], 'N');
strchr_pointer = strchr(npos,' ') + 1;
*(starpos-1) = '\0';
}
card.openFile(strchr_pointer+4,false);
break;
case 29: //M29 - Stop SD write
//processed in write to file routine above
//card,saving = false;
break;
case 30: //M30 <filename> Delete File
if (card.cardOK){
card.closefile();
starpos = (strchr(strchr_pointer + 4,'*'));
if(starpos != NULL){
char* npos = strchr(cmdbuffer[bufindr], 'N');
strchr_pointer = strchr(npos,' ') + 1;
*(starpos-1) = '\0';
}
card.removeFile(strchr_pointer + 4);
}
break;
#endif //SDSUPPORT
case 31: //M31 take time since the start of the SD print or an M109 command
{
stoptime=millis();
char time[30];
unsigned long t=(stoptime-starttime)/1000;
int sec,min;
min=t/60;
sec=t%60;
sprintf(time,"%i min, %i sec",min,sec);
SERIAL_ECHO_START;
SERIAL_ECHOLN(time);
LCD_MESSAGE(time);
autotempShutdown();
}
break;
case 42: //M42 -Change pin status via gcode
if (code_seen('S'))
{
int pin_status = code_value();
if (code_seen('P') && pin_status >= 0 && pin_status <= 255)
{
int pin_number = code_value();
for(int8_t i = 0; i < (int8_t)sizeof(sensitive_pins); i++)
{
if (sensitive_pins[i] == pin_number)
{
pin_number = -1;
break;
}
}
if (pin_number > -1)
{
pinMode(pin_number, OUTPUT);
digitalWrite(pin_number, pin_status);
analogWrite(pin_number, pin_status);
}
}
}
break;
case 104: // M104
tmp_extruder = active_extruder;
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_ECHO(MSG_M104_INVALID_EXTRUDER);
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
setWatch();
break;
case 140: // M140 set bed temp
if (code_seen('S')) setTargetBed(code_value());
break;
case 105 : // M105
tmp_extruder = active_extruder;
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_ECHO(MSG_M105_INVALID_EXTRUDER);
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
#if (TEMP_0_PIN > -1)
SERIAL_PROTOCOLPGM("ok T:");
SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
SERIAL_PROTOCOLPGM(" /");
SERIAL_PROTOCOL_F(degTargetHotend(tmp_extruder),1);
#if TEMP_BED_PIN > -1
SERIAL_PROTOCOLPGM(" B:");
SERIAL_PROTOCOL_F(degBed(),1);
SERIAL_PROTOCOLPGM(" /");
SERIAL_PROTOCOL_F(degTargetBed(),1);
#endif //TEMP_BED_PIN
#else
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_ERR_NO_THERMISTORS);
#endif
#ifdef PIDTEMP
SERIAL_PROTOCOLPGM(" @:");
SERIAL_PROTOCOL(getHeaterPower(tmp_extruder));
#endif
SERIAL_PROTOCOLLN("");
return;
break;
case 109:
{// M109 - Wait for extruder heater to reach target.
tmp_extruder = active_extruder;
if(code_seen('T')) {
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_ECHO(MSG_M109_INVALID_EXTRUDER);
SERIAL_ECHOLN(tmp_extruder);
break;
}
}
LCD_MESSAGEPGM(MSG_HEATING);
#ifdef AUTOTEMP
autotemp_enabled=false;
#endif
if (code_seen('S')) setTargetHotend(code_value(), tmp_extruder);
#ifdef AUTOTEMP
if (code_seen('S')) autotemp_min=code_value();
if (code_seen('B')) autotemp_max=code_value();
if (code_seen('F'))
{
autotemp_factor=code_value();
autotemp_enabled=true;
}
#endif
setWatch();
codenum = millis();
/* See if we are heating up or cooling down */
bool target_direction = isHeatingHotend(tmp_extruder); // true if heating, false if cooling
#ifdef TEMP_RESIDENCY_TIME
long residencyStart;
residencyStart = -1;
/* continue to loop until we have reached the target temp
_and_ until TEMP_RESIDENCY_TIME hasn't passed since we reached it */
while((residencyStart == -1) ||
(residencyStart >= 0 && (((unsigned int) (millis() - residencyStart)) < (TEMP_RESIDENCY_TIME * 1000UL))) ) {
#else
while ( target_direction ? (isHeatingHotend(tmp_extruder)) : (isCoolingHotend(tmp_extruder)&&(CooldownNoWait==false)) ) {
#endif //TEMP_RESIDENCY_TIME
if( (millis() - codenum) > 1000UL )
{ //Print Temp Reading and remaining time every 1 second while heating up/cooling down
SERIAL_PROTOCOLPGM("T:");
SERIAL_PROTOCOL_F(degHotend(tmp_extruder),1);
SERIAL_PROTOCOLPGM(" E:");
SERIAL_PROTOCOL((int)tmp_extruder);
#ifdef TEMP_RESIDENCY_TIME
SERIAL_PROTOCOLPGM(" W:");
if(residencyStart > -1)
{
codenum = ((TEMP_RESIDENCY_TIME * 1000UL) - (millis() - residencyStart)) / 1000UL;
SERIAL_PROTOCOLLN( codenum );
}
else
{
SERIAL_PROTOCOLLN( "?" );
}
#else
SERIAL_PROTOCOLLN("");
#endif
codenum = millis();
}
manage_heater();
manage_inactivity();
LCD_STATUS;
#ifdef TEMP_RESIDENCY_TIME
/* start/restart the TEMP_RESIDENCY_TIME timer whenever we reach target temp for the first time
or when current temp falls outside the hysteresis after target temp was reached */
if ((residencyStart == -1 && target_direction && (degHotend(tmp_extruder) >= (degTargetHotend(tmp_extruder)-TEMP_WINDOW))) ||
(residencyStart == -1 && !target_direction && (degHotend(tmp_extruder) <= (degTargetHotend(tmp_extruder)+TEMP_WINDOW))) ||
(residencyStart > -1 && labs(degHotend(tmp_extruder) - degTargetHotend(tmp_extruder)) > TEMP_HYSTERESIS) )
{
residencyStart = millis();
}
#endif //TEMP_RESIDENCY_TIME
}
LCD_MESSAGEPGM(MSG_HEATING_COMPLETE);
starttime=millis();
previous_millis_cmd = millis();
}
break;
case 190: // M190 - Wait for bed heater to reach target.
#if TEMP_BED_PIN > -1
LCD_MESSAGEPGM(MSG_BED_HEATING);
if (code_seen('S')) setTargetBed(code_value());
codenum = millis();
while(isHeatingBed())
{
if(( millis() - codenum) > 1000 ) //Print Temp Reading every 1 second while heating up.
{
float tt=degHotend(active_extruder);
SERIAL_PROTOCOLPGM("T:");
SERIAL_PROTOCOL(tt);
SERIAL_PROTOCOLPGM(" E:");
SERIAL_PROTOCOL((int)active_extruder);
SERIAL_PROTOCOLPGM(" B:");
SERIAL_PROTOCOL_F(degBed(),1);
SERIAL_PROTOCOLLN("");
codenum = millis();
}
manage_heater();
manage_inactivity();
LCD_STATUS;
}
LCD_MESSAGEPGM(MSG_BED_DONE);
previous_millis_cmd = millis();
#endif
break;
#if FAN_PIN > -1
case 106: //M106 Fan On
if (code_seen('S')){
FanSpeed=constrain(code_value(),0,255);
}
else {
FanSpeed=255;
}
break;
case 107: //M107 Fan Off
FanSpeed = 0;
break;
#endif //FAN_PIN
#if (PS_ON_PIN > -1)
case 80: // M80 - ATX Power On
SET_OUTPUT(PS_ON_PIN); //GND
WRITE(PS_ON_PIN, LOW);
break;
#endif
case 81: // M81 - ATX Power Off
#if defined SUICIDE_PIN && SUICIDE_PIN > -1
st_synchronize();
suicide();
#elif (PS_ON_PIN > -1)
SET_INPUT(PS_ON_PIN); //Floating
#endif
break;
case 82:
axis_relative_modes[3] = false;
break;
case 83:
axis_relative_modes[3] = true;
break;
case 18: //compatibility
case 84: // M84
if(code_seen('S')){
stepper_inactive_time = code_value() * 1000;
}
else
{
bool all_axis = !((code_seen(axis_codes[0])) || (code_seen(axis_codes[1])) || (code_seen(axis_codes[2]))|| (code_seen(axis_codes[3])));
if(all_axis)
{
st_synchronize();
disable_e0();
disable_e1();
disable_e2();
finishAndDisableSteppers();
}
else
{
st_synchronize();
if(code_seen('X')) disable_x();
if(code_seen('Y')) disable_y();
if(code_seen('Z')) disable_z();
#if ((E0_ENABLE_PIN != X_ENABLE_PIN) && (E1_ENABLE_PIN != Y_ENABLE_PIN)) // Only enable on boards that have seperate ENABLE_PINS
if(code_seen('E')) {
disable_e0();
disable_e1();
disable_e2();
}
#endif
LCD_MESSAGEPGM(MSG_PART_RELEASE);
}
}
break;
case 85: // M85
code_seen('S');
max_inactive_time = code_value() * 1000;
break;
case 92: // M92
for(int8_t i=0; i < NUM_AXIS; i++)
{
if(code_seen(axis_codes[i]))
if(i == 3) { // E
float value = code_value();
if(value < 20.0) {
float factor = axis_steps_per_unit[i] / value; // increase e constants if M92 E14 is given for netfab.
max_e_jerk *= factor;
max_feedrate[i] *= factor;
axis_steps_per_sqr_second[i] *= factor;
}
axis_steps_per_unit[i] = value;
}
else {
axis_steps_per_unit[i] = code_value();
}
}
break;
case 115: // M115
SerialprintPGM(MSG_M115_REPORT);
break;
case 117: // M117 display message
LCD_MESSAGE(cmdbuffer[bufindr]+5);
break;
case 114: // M114
SERIAL_PROTOCOLPGM("X:");
SERIAL_PROTOCOL(current_position[X_AXIS]);
SERIAL_PROTOCOLPGM("Y:");
SERIAL_PROTOCOL(current_position[Y_AXIS]);
SERIAL_PROTOCOLPGM("Z:");
SERIAL_PROTOCOL(current_position[Z_AXIS]);
SERIAL_PROTOCOLPGM("E:");
SERIAL_PROTOCOL(current_position[E_AXIS]);
SERIAL_PROTOCOLPGM(MSG_COUNT_X);
SERIAL_PROTOCOL(float(st_get_position(X_AXIS))/axis_steps_per_unit[X_AXIS]);
SERIAL_PROTOCOLPGM("Y:");
SERIAL_PROTOCOL(float(st_get_position(Y_AXIS))/axis_steps_per_unit[Y_AXIS]);
SERIAL_PROTOCOLPGM("Z:");
SERIAL_PROTOCOL(float(st_get_position(Z_AXIS))/axis_steps_per_unit[Z_AXIS]);
SERIAL_PROTOCOLLN("");
break;
case 120: // M120
enable_endstops(false) ;
break;
case 121: // M121
enable_endstops(true) ;
break;
case 119: // M119
#if (X_MIN_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_X_MIN);
SERIAL_PROTOCOL(((READ(X_MIN_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
#if (X_MAX_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_X_MAX);
SERIAL_PROTOCOL(((READ(X_MAX_PIN)^X_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
#if (Y_MIN_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_Y_MIN);
SERIAL_PROTOCOL(((READ(Y_MIN_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
#if (Y_MAX_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_Y_MAX);
SERIAL_PROTOCOL(((READ(Y_MAX_PIN)^Y_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
#if (Z_MIN_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_Z_MIN);
SERIAL_PROTOCOL(((READ(Z_MIN_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
#if (Z_MAX_PIN > -1)
SERIAL_PROTOCOLPGM(MSG_Z_MAX);
SERIAL_PROTOCOL(((READ(Z_MAX_PIN)^Z_ENDSTOPS_INVERTING)?"H ":"L "));
#endif
SERIAL_PROTOCOLLN("");
break;
//TODO: update for all axis, use for loop
case 201: // M201
for(int8_t i=0; i < NUM_AXIS; i++)
{
if(code_seen(axis_codes[i]))
{
max_acceleration_units_per_sq_second[i] = code_value();
axis_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
}
}
break;
#if 0 // Not used for Sprinter/grbl gen6
case 202: // M202
for(int8_t i=0; i < NUM_AXIS; i++) {
if(code_seen(axis_codes[i])) axis_travel_steps_per_sqr_second[i] = code_value() * axis_steps_per_unit[i];
}
break;
#endif
case 203: // M203 max feedrate mm/sec
for(int8_t i=0; i < NUM_AXIS; i++) {
if(code_seen(axis_codes[i])) max_feedrate[i] = code_value();
}
break;
case 204: // M204 acclereration S normal moves T filmanent only moves
{
if(code_seen('S')) acceleration = code_value() ;
if(code_seen('T')) retract_acceleration = code_value() ;
}
break;
case 205: //M205 advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
{
if(code_seen('S')) minimumfeedrate = code_value();
if(code_seen('T')) mintravelfeedrate = code_value();
if(code_seen('B')) minsegmenttime = code_value() ;
if(code_seen('X')) max_xy_jerk = code_value() ;
if(code_seen('Z')) max_z_jerk = code_value() ;
if(code_seen('E')) max_e_jerk = code_value() ;
}
break;
case 206: // M206 additional homeing offset
for(int8_t i=0; i < 3; i++)
{
if(code_seen(axis_codes[i])) add_homeing[i] = code_value();
}
break;
#ifdef FWRETRACT
case 207: //M207 - set retract length S[positive mm] F[feedrate mm/sec] Z[additional zlift/hop]
{
if(code_seen('S'))
{
retract_length = code_value() ;
}
if(code_seen('F'))
{
retract_feedrate = code_value() ;
}
if(code_seen('Z'))
{
retract_zlift = code_value() ;
}
}break;
case 208: // M208 - set retract recover length S[positive mm surplus to the M207 S*] F[feedrate mm/sec]
{
if(code_seen('S'))
{
retract_recover_length = code_value() ;
}
if(code_seen('F'))
{
retract_recover_feedrate = code_value() ;
}
}break;
case 209: // M209 - S<1=true/0=false> enable automatic retract detect if the slicer did not support G10/11: every normal extrude-only move will be classified as retract depending on the direction.
{
if(code_seen('S'))
{
int t= code_value() ;
switch(t)
{
case 0: autoretract_enabled=false;retracted=false;break;
case 1: autoretract_enabled=true;retracted=false;break;
default:
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
SERIAL_ECHO(cmdbuffer[bufindr]);
SERIAL_ECHOLNPGM("\"");
}
}
}break;
#endif
case 220: // M220 S<factor in percent>- set speed factor override percentage
{
if(code_seen('S'))
{
feedmultiply = code_value() ;
feedmultiplychanged=true;
}
}
break;
case 221: // M221 S<factor in percent>- set extrude factor override percentage
{
if(code_seen('S'))
{
extrudemultiply = code_value() ;
}
}
break;
#ifdef PIDTEMP
case 301: // M301
{
if(code_seen('P')) Kp = code_value();
if(code_seen('I')) Ki = code_value()*PID_dT;
if(code_seen('D')) Kd = code_value()/PID_dT;
#ifdef PID_ADD_EXTRUSION_RATE
if(code_seen('C')) Kc = code_value();
#endif
updatePID();
SERIAL_PROTOCOL(MSG_OK);
SERIAL_PROTOCOL(" p:");
SERIAL_PROTOCOL(Kp);
SERIAL_PROTOCOL(" i:");
SERIAL_PROTOCOL(Ki/PID_dT);
SERIAL_PROTOCOL(" d:");
SERIAL_PROTOCOL(Kd*PID_dT);
#ifdef PID_ADD_EXTRUSION_RATE
SERIAL_PROTOCOL(" c:");
SERIAL_PROTOCOL(Kc*PID_dT);
#endif
SERIAL_PROTOCOLLN("");
}
break;
#endif //PIDTEMP
case 240: // M240 Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
{
#ifdef PHOTOGRAPH_PIN
#if (PHOTOGRAPH_PIN > -1)
const uint8_t NUM_PULSES=16;
const float PULSE_LENGTH=0.01524;
for(int i=0; i < NUM_PULSES; i++) {
WRITE(PHOTOGRAPH_PIN, HIGH);
_delay_ms(PULSE_LENGTH);
WRITE(PHOTOGRAPH_PIN, LOW);
_delay_ms(PULSE_LENGTH);
}
delay(7.33);
for(int i=0; i < NUM_PULSES; i++) {
WRITE(PHOTOGRAPH_PIN, HIGH);
_delay_ms(PULSE_LENGTH);
WRITE(PHOTOGRAPH_PIN, LOW);
_delay_ms(PULSE_LENGTH);
}
#endif
#endif
}
break;
case 302: // allow cold extrudes
{
allow_cold_extrudes(true);
}
break;
case 303: // M303 PID autotune
{
float temp = 150.0;
if (code_seen('S')) temp=code_value();
PID_autotune(temp);
}
break;
case 400: // M400 finish all moves
{
st_synchronize();
}
break;
case 500: // Store settings in EEPROM
{
EEPROM_StoreSettings();
}
break;
case 501: // Read settings from EEPROM
{
EEPROM_RetrieveSettings();
}
break;
case 502: // Revert to default settings
{
EEPROM_RetrieveSettings(true);
}
break;
case 503: // print settings currently in memory
{
EEPROM_printSettings();
}
break;
case 999: // Restart after being stopped
Stopped = false;
gcode_LastN = Stopped_gcode_LastN;
FlushSerialRequestResend();
break;
}
}
else if(code_seen('T'))
{
tmp_extruder = code_value();
if(tmp_extruder >= EXTRUDERS) {
SERIAL_ECHO_START;
SERIAL_ECHO("T");
SERIAL_ECHO(tmp_extruder);
SERIAL_ECHOLN(MSG_INVALID_EXTRUDER);
}
else {
active_extruder = tmp_extruder;
SERIAL_ECHO_START;
SERIAL_ECHO(MSG_ACTIVE_EXTRUDER);
SERIAL_PROTOCOLLN((int)active_extruder);
}
}
else
{
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_UNKNOWN_COMMAND);
SERIAL_ECHO(cmdbuffer[bufindr]);
SERIAL_ECHOLNPGM("\"");
}
ClearToSend();
}
void FlushSerialRequestResend()
{
//char cmdbuffer[bufindr][100]="Resend:";
MYSERIAL.flush();
SERIAL_PROTOCOLPGM(MSG_RESEND);
SERIAL_PROTOCOLLN(gcode_LastN + 1);
ClearToSend();
}
void ClearToSend()
{
previous_millis_cmd = millis();
#ifdef SDSUPPORT
if(fromsd[bufindr])
return;
#endif //SDSUPPORT
SERIAL_PROTOCOLLNPGM(MSG_OK);
}
void get_coordinates()
{
bool seen[4]={false,false,false,false};
for(int8_t i=0; i < NUM_AXIS; i++) {
if(code_seen(axis_codes[i]))
{
destination[i] = (float)code_value() + (axis_relative_modes[i] || relative_mode)*current_position[i];
seen[i]=true;
}
else destination[i] = current_position[i]; //Are these else lines really needed?
}
if(code_seen('F')) {
next_feedrate = code_value();
if(next_feedrate > 0.0) feedrate = next_feedrate;
}
#ifdef FWRETRACT
if(autoretract_enabled)
if( !(seen[X_AXIS] || seen[Y_AXIS] || seen[Z_AXIS]) && seen[E_AXIS])
{
float echange=destination[E_AXIS]-current_position[E_AXIS];
if(echange<-MIN_RETRACT) //retract
{
if(!retracted)
{
destination[Z_AXIS]+=retract_zlift; //not sure why chaninging current_position negatively does not work.
//if slicer retracted by echange=-1mm and you want to retract 3mm, corrrectede=-2mm additionally
float correctede=-echange-retract_length;
//to generate the additional steps, not the destination is changed, but inversely the current position
current_position[E_AXIS]+=-correctede;
feedrate=retract_feedrate;
retracted=true;
}
}
else
if(echange>MIN_RETRACT) //retract_recover
{
if(retracted)
{
//current_position[Z_AXIS]+=-retract_zlift;
//if slicer retracted_recovered by echange=+1mm and you want to retract_recover 3mm, corrrectede=2mm additionally
float correctede=-echange+1*retract_length+retract_recover_length; //total unretract=retract_length+retract_recover_length[surplus]
current_position[E_AXIS]+=correctede; //to generate the additional steps, not the destination is changed, but inversely the current position
feedrate=retract_recover_feedrate;
retracted=false;
}
}
}
#endif //FWRETRACT
}
void get_arc_coordinates()
{
#ifdef SF_ARC_FIX
bool relative_mode_backup = relative_mode;
relative_mode = true;
#endif
get_coordinates();
#ifdef SF_ARC_FIX
relative_mode=relative_mode_backup;
#endif
if(code_seen('I')) {
offset[0] = code_value();
}
else {
offset[0] = 0.0;
}
if(code_seen('J')) {
offset[1] = code_value();
}
else {
offset[1] = 0.0;
}
}
void clamp_to_software_endstops(float target[3])
{
if (min_software_endstops) {
if (target[X_AXIS] < min_pos[X_AXIS]) target[X_AXIS] = min_pos[X_AXIS];
if (target[Y_AXIS] < min_pos[Y_AXIS]) target[Y_AXIS] = min_pos[Y_AXIS];
if (target[Z_AXIS] < min_pos[Z_AXIS]) target[Z_AXIS] = min_pos[Z_AXIS];
}
if (max_software_endstops) {
if (target[X_AXIS] > max_pos[X_AXIS]) target[X_AXIS] = max_pos[X_AXIS];
if (target[Y_AXIS] > max_pos[Y_AXIS]) target[Y_AXIS] = max_pos[Y_AXIS];
if (target[Z_AXIS] > max_pos[Z_AXIS]) target[Z_AXIS] = max_pos[Z_AXIS];
}
}
void prepare_move()
{
clamp_to_software_endstops(destination);
previous_millis_cmd = millis();
// Do not use feedmultiply for E or Z only moves
if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) {
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder);
}
else {
plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder);
}
for(int8_t i=0; i < NUM_AXIS; i++) {
current_position[i] = destination[i];
}
}
void prepare_arc_move(char isclockwise) {
float r = hypot(offset[X_AXIS], offset[Y_AXIS]); // Compute arc radius for mc_arc
// Trace the arc
mc_arc(current_position, destination, offset, X_AXIS, Y_AXIS, Z_AXIS, feedrate*feedmultiply/60/100.0, r, isclockwise, active_extruder);
// As far as the parser is concerned, the position is now == target. In reality the
// motion control system might still be processing the action and the real tool position
// in any intermediate location.
for(int8_t i=0; i < NUM_AXIS; i++) {
current_position[i] = destination[i];
}
previous_millis_cmd = millis();
}
#ifdef CONTROLLERFAN_PIN
unsigned long lastMotor = 0; //Save the time for when a motor was turned on last
unsigned long lastMotorCheck = 0;
void controllerFan()
{
if ((millis() - lastMotorCheck) >= 2500) //Not a time critical function, so we only check every 2500ms
{
lastMotorCheck = millis();
if(!READ(X_ENABLE_PIN) || !READ(Y_ENABLE_PIN) || !READ(Z_ENABLE_PIN)
#if EXTRUDERS > 2
|| !READ(E2_ENABLE_PIN)
#endif
#if EXTRUDER > 1
|| !READ(E2_ENABLE_PIN)
#endif
|| !READ(E0_ENABLE_PIN)) //If any of the drivers are enabled...
{
lastMotor = millis(); //... set time to NOW so the fan will turn on
}
if ((millis() - lastMotor) >= (CONTROLLERFAN_SEC*1000UL) || lastMotor == 0) //If the last time any driver was enabled, is longer since than CONTROLLERSEC...
{
WRITE(CONTROLLERFAN_PIN, LOW); //... turn the fan off
}
else
{
WRITE(CONTROLLERFAN_PIN, HIGH); //... turn the fan on
}
}
}
#endif
void manage_inactivity()
{
if( (millis() - previous_millis_cmd) > max_inactive_time )
if(max_inactive_time)
kill();
if(stepper_inactive_time) {
if( (millis() - previous_millis_cmd) > stepper_inactive_time )
{
if(blocks_queued() == false) {
disable_x();
disable_y();
disable_z();
disable_e0();
disable_e1();
disable_e2();
}
}
}
#if( KILL_PIN>-1 )
if( 0 == READ(KILL_PIN) )
kill();
#endif
#ifdef CONTROLLERFAN_PIN
controllerFan(); //Check if fan should be turned on to cool stepper drivers down
#endif
#ifdef EXTRUDER_RUNOUT_PREVENT
if( (millis() - previous_millis_cmd) > EXTRUDER_RUNOUT_SECONDS*1000 )
if(degHotend(active_extruder)>EXTRUDER_RUNOUT_MINTEMP)
{
bool oldstatus=READ(E0_ENABLE_PIN);
enable_e0();
float oldepos=current_position[E_AXIS];
float oldedes=destination[E_AXIS];
plan_buffer_line(current_position[X_AXIS], current_position[Y_AXIS], current_position[Z_AXIS],
current_position[E_AXIS]+EXTRUDER_RUNOUT_EXTRUDE*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS],
EXTRUDER_RUNOUT_SPEED/60.*EXTRUDER_RUNOUT_ESTEPS/axis_steps_per_unit[E_AXIS], active_extruder);
current_position[E_AXIS]=oldepos;
destination[E_AXIS]=oldedes;
plan_set_e_position(oldepos);
previous_millis_cmd=millis();
st_synchronize();
WRITE(E0_ENABLE_PIN,oldstatus);
}
#endif
check_axes_activity();
}
void kill()
{
cli(); // Stop interrupts
disable_heater();
disable_x();
disable_y();
disable_z();
disable_e0();
disable_e1();
disable_e2();
if(PS_ON_PIN > -1) pinMode(PS_ON_PIN,INPUT);
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_ERR_KILLED);
LCD_ALERTMESSAGEPGM(MSG_KILLED);
suicide();
while(1); // Wait for reset
}
void Stop()
{
disable_heater();
if(Stopped == false) {
Stopped = true;
Stopped_gcode_LastN = gcode_LastN; // Save last g_code for restart
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_ERR_STOPPED);
LCD_MESSAGEPGM(MSG_STOPPED);
}
}
bool IsStopped() { return Stopped; };
#ifdef FAST_PWM_FAN
void setPwmFrequency(uint8_t pin, int val)
{
val &= 0x07;
switch(digitalPinToTimer(pin))
{
#if defined(TCCR0A)
case TIMER0A:
case TIMER0B:
// TCCR0B &= ~(CS00 | CS01 | CS02);
// TCCR0B |= val;
break;
#endif
#if defined(TCCR1A)
case TIMER1A:
case TIMER1B:
// TCCR1B &= ~(CS10 | CS11 | CS12);
// TCCR1B |= val;
break;
#endif
#if defined(TCCR2)
case TIMER2:
case TIMER2:
TCCR2 &= ~(CS10 | CS11 | CS12);
TCCR2 |= val;
break;
#endif
#if defined(TCCR2A)
case TIMER2A:
case TIMER2B:
TCCR2B &= ~(CS20 | CS21 | CS22);
TCCR2B |= val;
break;
#endif
#if defined(TCCR3A)
case TIMER3A:
case TIMER3B:
case TIMER3C:
TCCR3B &= ~(CS30 | CS31 | CS32);
TCCR3B |= val;
break;
#endif
#if defined(TCCR4A)
case TIMER4A:
case TIMER4B:
case TIMER4C:
TCCR4B &= ~(CS40 | CS41 | CS42);
TCCR4B |= val;
break;
#endif
#if defined(TCCR5A)
case TIMER5A:
case TIMER5B:
case TIMER5C:
TCCR5B &= ~(CS50 | CS51 | CS52);
TCCR5B |= val;
break;
#endif
}
}
#endif

@ -0,0 +1,329 @@
/*
HardwareSerial.cpp - Hardware serial library for 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
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include "Marlin.h"
#include "MarlinSerial.h"
#if MOTHERBOARD != 8 // !teensylu
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
#if defined(UBRRH) || defined(UBRR0H)
ring_buffer rx_buffer = { { 0 }, 0, 0 };
#endif
FORCE_INLINE void store_char(unsigned char c)
{
int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer.tail) {
rx_buffer.buffer[rx_buffer.head] = c;
rx_buffer.head = i;
}
}
//#elif defined(SIG_USART_RECV)
#if defined(USART0_RX_vect)
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL(USART0_RX_vect)
{
#if defined(UDR0)
unsigned char c = UDR0;
#elif defined(UDR)
unsigned char c = UDR; // atmega8, atmega32
#else
#error UDR not defined
#endif
store_char(c);
}
#endif
// Constructors ////////////////////////////////////////////////////////////////
MarlinSerial::MarlinSerial()
{
}
// Public Methods //////////////////////////////////////////////////////////////
void MarlinSerial::begin(long baud)
{
uint16_t baud_setting;
bool useU2X0 = true;
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600) {
useU2X0 = false;
}
#endif
if (useU2X0) {
UCSR0A = 1 << U2X0;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
UCSR0A = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
UBRR0H = baud_setting >> 8;
UBRR0L = baud_setting;
sbi(UCSR0B, RXEN0);
sbi(UCSR0B, TXEN0);
sbi(UCSR0B, RXCIE0);
}
void MarlinSerial::end()
{
cbi(UCSR0B, RXEN0);
cbi(UCSR0B, TXEN0);
cbi(UCSR0B, RXCIE0);
}
int MarlinSerial::peek(void)
{
if (rx_buffer.head == rx_buffer.tail) {
return -1;
} else {
return rx_buffer.buffer[rx_buffer.tail];
}
}
int MarlinSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (rx_buffer.head == rx_buffer.tail) {
return -1;
} else {
unsigned char c = rx_buffer.buffer[rx_buffer.tail];
rx_buffer.tail = (unsigned int)(rx_buffer.tail + 1) % RX_BUFFER_SIZE;
return c;
}
}
void MarlinSerial::flush()
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
rx_buffer.head = rx_buffer.tail;
}
/// imports from print.h
void MarlinSerial::print(char c, int base)
{
print((long) c, base);
}
void MarlinSerial::print(unsigned char b, int base)
{
print((unsigned long) b, base);
}
void MarlinSerial::print(int n, int base)
{
print((long) n, base);
}
void MarlinSerial::print(unsigned int n, int base)
{
print((unsigned long) n, base);
}
void MarlinSerial::print(long n, int base)
{
if (base == 0) {
write(n);
} else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
} else {
printNumber(n, base);
}
}
void MarlinSerial::print(unsigned long n, int base)
{
if (base == 0) write(n);
else printNumber(n, base);
}
void MarlinSerial::print(double n, int digits)
{
printFloat(n, digits);
}
void MarlinSerial::println(void)
{
print('\r');
print('\n');
}
void MarlinSerial::println(const String &s)
{
print(s);
println();
}
void MarlinSerial::println(const char c[])
{
print(c);
println();
}
void MarlinSerial::println(char c, int base)
{
print(c, base);
println();
}
void MarlinSerial::println(unsigned char b, int base)
{
print(b, base);
println();
}
void MarlinSerial::println(int n, int base)
{
print(n, base);
println();
}
void MarlinSerial::println(unsigned int n, int base)
{
print(n, base);
println();
}
void MarlinSerial::println(long n, int base)
{
print(n, base);
println();
}
void MarlinSerial::println(unsigned long n, int base)
{
print(n, base);
println();
}
void MarlinSerial::println(double n, int digits)
{
print(n, digits);
println();
}
// Private Methods /////////////////////////////////////////////////////////////
void MarlinSerial::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
while (n > 0) {
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
print((char) (buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
void MarlinSerial::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print(".");
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}
// Preinstantiate Objects //////////////////////////////////////////////////////
MarlinSerial MSerial;
#endif // whole file
#endif //teensylu

@ -0,0 +1,150 @@
/*
HardwareSerial.h - Hardware serial library for 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
Modified 28 September 2010 by Mark Sproul
*/
#ifndef MarlinSerial_h
#define MarlinSerial_h
#include "Marlin.h"
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0
#if MOTHERBOARD != 8 // ! teensylu
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
struct ring_buffer
{
unsigned char buffer[RX_BUFFER_SIZE];
int head;
int tail;
};
#if defined(UBRRH) || defined(UBRR0H)
extern ring_buffer rx_buffer;
#endif
class MarlinSerial //: public Stream
{
public:
MarlinSerial();
void begin(long);
void end();
int peek(void);
int read(void);
void flush(void);
FORCE_INLINE int available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + rx_buffer.head - rx_buffer.tail) % RX_BUFFER_SIZE;
}
FORCE_INLINE void write(uint8_t c)
{
while (!((UCSR0A) & (1 << UDRE0)))
;
UDR0 = c;
}
FORCE_INLINE void checkRx(void)
{
if((UCSR0A & (1<<RXC0)) != 0) {
unsigned char c = UDR0;
int i = (unsigned int)(rx_buffer.head + 1) % RX_BUFFER_SIZE;
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer.tail) {
rx_buffer.buffer[rx_buffer.head] = c;
rx_buffer.head = i;
}
}
}
private:
void printNumber(unsigned long, uint8_t);
void printFloat(double, uint8_t);
public:
FORCE_INLINE void write(const char *str)
{
while (*str)
write(*str++);
}
FORCE_INLINE void write(const uint8_t *buffer, size_t size)
{
while (size--)
write(*buffer++);
}
FORCE_INLINE void print(const String &s)
{
for (int i = 0; i < (int)s.length(); i++) {
write(s[i]);
}
}
FORCE_INLINE void print(const char *str)
{
write(str);
}
void print(char, int = BYTE);
void print(unsigned char, int = BYTE);
void print(int, int = DEC);
void print(unsigned int, int = DEC);
void print(long, int = DEC);
void print(unsigned long, int = DEC);
void print(double, int = 2);
void println(const String &s);
void println(const char[]);
void println(char, int = BYTE);
void println(unsigned char, int = BYTE);
void println(int, int = DEC);
void println(unsigned int, int = DEC);
void println(long, int = DEC);
void println(unsigned long, int = DEC);
void println(double, int = 2);
void println(void);
};
extern MarlinSerial MSerial;
#endif // ! teensylu
#endif

Binary file not shown.

@ -0,0 +1,16 @@
##############################################################
sanguino.name=Sanguino
sanguino.upload.protocol=stk500
sanguino.upload.maximum_size=63488
sanguino.upload.speed=38400
sanguino.bootloader.low_fuses=0xFF
sanguino.bootloader.high_fuses=0xDC
sanguino.bootloader.extended_fuses=0xFD
sanguino.bootloader.path=atmega644p
sanguino.bootloader.file=ATmegaBOOT_644P.hex
sanguino.bootloader.unlock_bits=0x3F
sanguino.bootloader.lock_bits=0x0F
sanguino.build.mcu=atmega644p
sanguino.build.f_cpu=16000000L
sanguino.build.core=arduino

@ -0,0 +1,713 @@
/**********************************************************/
/* Serial Bootloader for Atmel megaAVR Controllers */
/* */
/* tested with ATmega644 and ATmega644P */
/* should work with other mega's, see code for details */
/* */
/* ATmegaBOOT.c */
/* */
/* 20090131: Added 324P support from Alex Leone */
/* Marius Kintel */
/* 20080915: applied ADABoot mods for Sanguino 644P */
/* Brian Riley */
/* 20080711: hacked for Sanguino by Zach Smith */
/* and Justin Day */
/* 20070626: hacked for Arduino Diecimila (which auto- */
/* resets when a USB connection is made to it) */
/* by D. Mellis */
/* 20060802: hacked for Arduino by D. Cuartielles */
/* based on a previous hack by D. Mellis */
/* and D. Cuartielles */
/* */
/* Monitor and debug functions were added to the original */
/* code by Dr. Erik Lins, chip45.com. (See below) */
/* */
/* Thanks to Karl Pitrich for fixing a bootloader pin */
/* problem and more informative LED blinking! */
/* */
/* For the latest version see: */
/* http://www.chip45.com/ */
/* */
/* ------------------------------------------------------ */
/* */
/* based on stk500boot.c */
/* Copyright (c) 2003, Jason P. Kyle */
/* All rights reserved. */
/* see avr1.org for original file and information */
/* */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will */
/* be useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with this program; if not, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/* Target = Atmel AVR m128,m64,m32,m16,m8,m162,m163,m169, */
/* m8515,m8535. ATmega161 has a very small boot block so */
/* isn't supported. */
/* */
/* Tested with m168 */
/**********************************************************/
/* $Id$ */
/* some includes */
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>
#include <avr/boot.h>
#ifdef ADABOOT
#define NUM_LED_FLASHES 3
#define ADABOOT_VER 1
#endif
/* 20070707: hacked by David A. Mellis - after this many errors give up and launch application */
#define MAX_ERROR_COUNT 5
/* set the UART baud rate */
/* 20080711: hack by Zach Hoeken */
#define BAUD_RATE 38400
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
/* never allow AVR Studio to do an update !!!! */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x10
/* onboard LED is used to indicate, that the bootloader was entered (3x flashing) */
/* if monitor functions are included, LED goes on after monitor was entered */
#define LED_DDR DDRB
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED PINB0
/* define various device id's */
/* manufacturer byte is always the same */
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#if defined(__AVR_ATmega644P__)
#define SIG2 0x96
#define SIG3 0x0A
#elif defined(__AVR_ATmega644__)
#define SIG2 0x96
#define SIG3 0x09
#elif defined(__AVR_ATmega324P__)
#define SIG2 0x95
#define SIG3 0x08
#endif
#define PAGE_SIZE 0x080U //128 words
#define PAGE_SIZE_BYTES 0x100U //256 bytes
/* function prototypes */
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
char gethex(void);
void puthex(char);
void flash_led(uint8_t);
/* some variables */
union address_union
{
uint16_t word;
uint8_t byte[2];
} address;
union length_union
{
uint16_t word;
uint8_t byte[2];
} length;
struct flags_struct
{
unsigned eeprom : 1;
unsigned rampz : 1;
} flags;
uint8_t buff[256];
uint8_t error_count = 0;
uint8_t sreg;
void (*app_start)(void) = 0x0000;
/* main program starts here */
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
uint16_t i;
asm volatile("nop\n\t");
#ifdef ADABOOT // BBR/LF 10/8/2007 & 9/13/2008
ch = MCUSR;
MCUSR = 0;
WDTCSR |= _BV(WDCE) | _BV(WDE);
WDTCSR = 0;
// Check if the WDT was used to reset, in which case we dont bootload and skip straight to the code. woot.
if (! (ch & _BV(EXTRF))) // if its a not an external reset...
app_start(); // skip bootloader
#endif
//initialize our serial port.
UBRR0L = (uint8_t)(F_CPU/(BAUD_RATE*16L)-1);
UBRR0H = (F_CPU/(BAUD_RATE*16L)-1) >> 8;
UCSR0B = (1<<RXEN0) | (1<<TXEN0);
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
/* Enable internal pull-up resistor on pin D0 (RX), in order
to supress line noise that prevents the bootloader from
timing out (DAM: 20070509) */
DDRD &= ~_BV(PIND0);
PORTD |= _BV(PIND0);
/* set LED pin as output */
LED_DDR |= _BV(LED);
/* flash onboard LED to signal entering of bootloader */
/* ADABOOT will do two series of flashes. first 4 - signifying ADABOOT */
/* then a pause and another flash series signifying ADABOOT sub-version */
flash_led(NUM_LED_FLASHES);
#ifdef ADABOOT
flash_led(ADABOOT_VER); // BBR 9/13/2008
#endif
/* forever loop */
for (;;)
{
/* get character from UART */
ch = getch();
/* A bunch of if...else if... gives smaller code than switch...case ! */
/* Hello is anyone home ? */
if(ch=='0')
nothing_response();
/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else if(ch=='1')
{
if (getch() == ' ')
{
putch(0x14);
putch('A');
putch('V');
putch('R');
putch(' ');
putch('I');
putch('S');
putch('P');
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else if(ch=='@')
{
ch2 = getch();
if (ch2 > 0x85)
getch();
nothing_response();
}
/* AVR ISP/STK500 board requests */
else if(ch=='A')
{
ch2 = getch();
if(ch2 == 0x80)
byte_response(HW_VER); // Hardware version
else if(ch2==0x81)
byte_response(SW_MAJOR); // Software major version
else if(ch2==0x82)
byte_response(SW_MINOR); // Software minor version
else if(ch2==0x98)
byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
else
byte_response(0x00); // Covers various unnecessary responses we don't care about
}
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
else if(ch=='B')
{
getNch(20);
nothing_response();
}
/* Parallel programming stuff DON'T CARE */
else if(ch=='E')
{
getNch(5);
nothing_response();
}
/* Enter programming mode */
else if(ch=='P')
{
nothing_response();
}
/* Leave programming mode */
else if(ch=='Q')
{
nothing_response();
#ifdef ADABOOT
// autoreset via watchdog (sneaky!) BBR/LF 9/13/2008
WDTCSR = _BV(WDE);
while (1); // 16 ms
#endif
}
/* Erase device, don't care as we will erase one page at a time anyway. */
else if(ch=='R')
{
nothing_response();
}
/* Set address, little endian. EEPROM in bytes, FLASH in words */
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
/* This might explain why little endian was used here, big endian used everywhere else. */
else if(ch=='U')
{
address.byte[0] = getch();
address.byte[1] = getch();
nothing_response();
}
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
else if(ch=='V')
{
getNch(4);
byte_response(0x00);
}
/* Write memory, length is big endian and is in bytes */
else if(ch=='d')
{
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E')
flags.eeprom = 1;
for (i=0; i<PAGE_SIZE; i++)
buff[i] = 0;
for (w = 0; w < length.word; w++)
{
// Store data in buffer, can't keep up with serial data stream whilst programming pages
buff[w] = getch();
}
if (getch() == ' ')
{
if (flags.eeprom)
{
//Write to EEPROM one byte at a time
for(w=0;w<length.word;w++)
{
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EEDR = buff[w];
EECR |= (1<<EEMPE);
EECR |= (1<<EEPE);
address.word++;
}
}
else
{
//address * 2 -> byte location
address.word = address.word << 1;
//Even up an odd number of bytes
if ((length.byte[0] & 0x01))
length.word++;
// HACKME: EEPE used to be EEWE
//Wait for previous EEPROM writes to complete
//while(bit_is_set(EECR,EEPE));
while(EECR & (1<<EEPE));
asm volatile(
"clr r17 \n\t" //page_word_count
"lds r30,address \n\t" //Address of FLASH location (in bytes)
"lds r31,address+1 \n\t"
"ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
"ldi r29,hi8(buff) \n\t"
"lds r24,length \n\t" //Length of data to be written (in bytes)
"lds r25,length+1 \n\t"
"length_loop: \n\t" //Main loop, repeat for number of words in block
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
"brne no_page_erase \n\t"
"wait_spm1: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm1 \n\t"
"ldi r16,0x03 \n\t" //Erase page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"wait_spm2: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm2 \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"no_page_erase: \n\t"
"ld r0,Y+ \n\t" //Write 2 bytes into page buffer
"ld r1,Y+ \n\t"
"wait_spm3: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm3 \n\t"
"ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
"sts %0,r16 \n\t"
"spm \n\t"
"inc r17 \n\t" //page_word_count++
"cpi r17,%1 \n\t"
"brlo same_page \n\t" //Still same page in FLASH
"write_page: \n\t"
"clr r17 \n\t" //New page, write current one first
"wait_spm4: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm4 \n\t"
"ldi r16,0x05 \n\t" //Write page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"wait_spm5: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm5 \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"same_page: \n\t"
"adiw r30,2 \n\t" //Next word in FLASH
"sbiw r24,2 \n\t" //length-2
"breq final_write \n\t" //Finished
"rjmp length_loop \n\t"
"final_write: \n\t"
"cpi r17,0 \n\t"
"breq block_done \n\t"
"adiw r24,2 \n\t" //length+2, fool above check on length after short page write
"rjmp write_page \n\t"
"block_done: \n\t"
"clr __zero_reg__ \n\t" //restore zero register
: "=m" (SPMCSR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31"
);
}
putch(0x14);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* Read memory block mode, length is big endian. */
else if(ch=='t')
{
length.byte[1] = getch();
length.byte[0] = getch();
if (getch() == 'E')
flags.eeprom = 1;
else
{
flags.eeprom = 0;
address.word = address.word << 1; // address * 2 -> byte location
}
// Command terminator
if (getch() == ' ')
{
putch(0x14);
for (w=0; w<length.word; w++)
{
// Can handle odd and even lengths okay
if (flags.eeprom)
{
// Byte access EEPROM read
while(EECR & (1<<EEPE));
EEAR = (uint16_t)(void *)address.word;
EECR |= (1<<EERE);
putch(EEDR);
address.word++;
}
else
{
if (!flags.rampz)
putch(pgm_read_byte_near(address.word));
address.word++;
}
}
putch(0x10);
}
}
/* Get device signature bytes */
else if(ch=='u')
{
if (getch() == ' ')
{
putch(0x14);
putch(SIG1);
putch(SIG2);
putch(SIG3);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
/* Read oscillator calibration byte */
else if(ch=='v')
byte_response(0x00);
else if (++error_count == MAX_ERROR_COUNT)
app_start();
}
/* end of forever loop */
}
char gethex(void)
{
char ah,al;
ah = getch();
putch(ah);
al = getch();
putch(al);
if(ah >= 'a')
ah = ah - 'a' + 0x0a;
else if(ah >= '0')
ah -= '0';
if(al >= 'a')
al = al - 'a' + 0x0a;
else if(al >= '0')
al -= '0';
return (ah << 4) + al;
}
void puthex(char ch)
{
char ah,al;
ah = (ch & 0xf0) >> 4;
if(ah >= 0x0a)
ah = ah - 0x0a + 'a';
else
ah += '0';
al = (ch & 0x0f);
if(al >= 0x0a)
al = al - 0x0a + 'a';
else
al += '0';
putch(ah);
putch(al);
}
void putch(char ch)
{
while (!(UCSR0A & _BV(UDRE0)));
UDR0 = ch;
}
char getch(void)
{
uint32_t count = 0;
#ifdef ADABOOT
LED_PORT &= ~_BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
#endif
while(!(UCSR0A & _BV(RXC0)))
{
/* 20060803 DojoCorp:: Addon coming from the previous Bootloader*/
/* HACKME:: here is a good place to count times*/
count++;
if (count > MAX_TIME_COUNT)
app_start();
}
#ifdef ADABOOT
LED_PORT |= _BV(LED); // toggle LED to show activity - BBR/LF 10/3/2007 & 9/13/2008
#endif
return UDR0;
}
void getNch(uint8_t count)
{
uint8_t i;
for(i=0;i<count;i++)
{
while(!(UCSR0A & _BV(RXC0)));
UDR0;
}
}
void byte_response(uint8_t val)
{
if (getch() == ' ')
{
putch(0x14);
putch(val);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
void nothing_response(void)
{
if (getch() == ' ')
{
putch(0x14);
putch(0x10);
}
else
{
if (++error_count == MAX_ERROR_COUNT)
app_start();
}
}
#ifdef ADABOOT
void flash_led(uint8_t count)
{
/* flash onboard LED count times to signal entering of bootloader */
/* l needs to be volatile or the delay loops below might get */
/* optimized away if compiling with optimizations (DAM). */
volatile uint32_t l;
if (count == 0) {
count = ADABOOT;
}
int8_t i;
for (i = 0; i < count; ++i) {
LED_PORT |= _BV(LED); // LED on
for(l = 0; l < (F_CPU / 1000); ++l); // delay NGvalue was 1000 for both loops - BBR
LED_PORT &= ~_BV(LED); // LED off
for(l = 0; l < (F_CPU / 250); ++l); // delay asymmteric for ADA BOOT BBR
}
for(l = 0; l < (F_CPU / 100); ++l); // pause ADA BOOT BBR
}
#else
void flash_led(uint8_t count)
{
/* flash onboard LED three times to signal entering of bootloader */
/* l needs to be volatile or the delay loops below might get
optimized away if compiling with optimizations (DAM). */
volatile uint32_t l;
if (count == 0) {
count = 3;
}
int8_t i;
for (i = 0; i < count; ++i) {
LED_PORT |= _BV(LED);
for(l = 0; l < (F_CPU / 1000); ++l);
LED_PORT &= ~_BV(LED);
for(l = 0; l < (F_CPU / 1000); ++l);
}
}
#endif
/* end of file ATmegaBOOT.c */

@ -0,0 +1,121 @@
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
:10F88000CFEFD8E0DEBFCDBF11E0A0E0B1E0E6E60B
:10F89000FFEF02C005900D92A030B107D9F712E03A
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
:10F8D00009F481E020E0482F55274115510509F42E
:10F8E0003DC0289A19821A821B821C820BC0898112
:10F8F0009A81AB81BC810196A11DB11D89839A8338
:10F90000AB83BC8389819A81AB81BC8180589E4343
:10F91000A040B04060F3289819821A821B821C8292
:10F920000BC089819A81AB81BC810196A11DB11D5B
:10F9300089839A83AB83BC8389819A81AB81BC81A3
:10F9400080509A4FA040B04060F32F5F822F9927DC
:10F9500087FD9095841795070CF4C3CF19821A82FE
:10F960001B821C8289819A81AB81BC818050914726
:10F97000A240B040A0F489819A81AB81BC810196FC
:10F98000A11DB11D89839A83AB83BC8389819A8130
:10F99000AB81BC8180509147A240B04060F3249677
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
:10F9B000EF92FF920F931F93EE24FF248701289864
:10F9C0008091C00087FD17C00894E11CF11C011D47
:10F9D000111D81E0E81689E0F8068DE3080780E054
:10F9E000180770F3E0910001F091010109958091F1
:10F9F000C00087FFE9CF289A8091C600992787FD2C
:10FA000090951F910F91FF90EF900895982F8091FE
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
:10FA2000803271F0809102018F5F809302018530F6
:10FA300009F00895E0910001F09101010995089500
:10FA400084E10E94067D80E10E94067D0895CF93A7
:10FA5000C82F0E94D87C803241F0809102018F5FD4
:10FA600080930201853081F40AC084E10E94067D02
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
:10FA80000001F09101010995CF910895282F90E090
:10FA900007C08091C0008823E4F78091C6009F5F73
:10FAA0009217B8F30895CFEFD8E0DEBFCDBF0000C6
:10FAB00094B714BE809160008861809360001092BA
:10FAC000600091FF74C189E18093C4001092C50069
:10FAD00088E18093C10086E08093C2005098589AD4
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
:10FAF000D87C8033B9F18133C1F1803409F456C028
:10FB0000813409F45CC0823409F46EC0853409F490
:10FB100071C0803539F1813509F4F3C0823511F1B6
:10FB2000853509F4D3C0863509F4CBC0843609F491
:10FB300065C0843709F4EBC0853709F4D2C0863735
:10FB400009F44AC0809102018F5F809302018530E1
:10FB500071F6E0910001F091010109950E94D87CB5
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
:10FB7000803241F784E10E94067D81E40E94067D87
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
:10FB9000067D89E40E94067D83E50E94067D80E55E
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
:10FBC000D87C803809F407C1813809F400C1823833
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
:10FC0000809306020E94D87C8093050280910802AE
:10FC10008E7F809308020E94D87C853409F44BC003
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
:10FC3000C0E0D0E0809105029091060218161906E6
:10FC400078F405E011E00E94D87CF80181938F01DF
:10FC500021968091050290910602C817D90798F362
:10FC60000E94D87C803209F06DCF8091080280FF1D
:10FC7000B6C0C0E0D0E02091050230910602121615
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
:10FCA00031962196C217D30798F3F0930401E0939D
:10FCB000030184E175CF809108028160809308027E
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
:10FCD000809303010E94D87C809304010E940E7DD2
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
:10FCF000067D8EE10E94067D85E90E94067D88E0F2
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
:10FD1000D87C809306020E94D87C809305020E94C2
:10FD2000D87C853409F449C0809108028E7F809385
:10FD300008028091030190910401880F991F90930C
:10FD40000401809303010E94D87C803209F0CFCE59
:10FD500084E10E94067DC0E0D0E020910502309150
:10FD600006021216130608F01DCFE0910301F09170
:10FD700004018091080280FF96C0F999FECFF2BD80
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
:10FD900004013196F0930401E093030120910502E0
:10FDA000309106022196C217D30718F3FBCEE091DB
:10FDB0000001F0910101099586CE809108028160D1
:10FDC00080930802C0CF80E10E94277D90CE81E021
:10FDD0000E94277D8CCE82E00E94277D88CE809174
:10FDE000030190910401880F991F9093040180935F
:10FDF00003018091050280FF09C080910502909166
:10FE0000060201969093060280930502F999FECFAF
:10FE10001127E0910301F0910401C5E0D1E0809148
:10FE2000050290910602103091F400915700017084
:10FE30000130D9F303E000935700E8950091570093
:10FE400001700130D9F301E100935700E895099062
:10FE500019900091570001700130D9F301E000932F
:10FE60005700E8951395103898F011270091570026
:10FE700001700130D9F305E000935700E895009137
:10FE8000570001700130D9F301E100935700E89564
:10FE90003296029709F0C7CF103011F00296E5CFE5
:10FEA000112484E17DCE869580FF06C03196F093C3
:10FEB0000401E093030176CF84910E94067D209196
:10FEC000050230910602E0910301F0910401EECFAA
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
:10FF000010330CF01053C295C07FC10F8C2F99276E
:10FF100087FD9095CF911F910895CF93282F992712
:10FF200087FD9095807F907095958795959587959D
:10FF300095958795959587958A303CF0895AC22F7B
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
:06FF6000CF910895FFCFD0
:040000030000F80001
:00000001FF

@ -0,0 +1,120 @@
:10F800000C94387C0C94557C0C94557C0C94557C51
:10F810000C94557C0C94557C0C94557C0C94557C24
:10F820000C94557C0C94557C0C94557C0C94557C14
:10F830000C94557C0C94557C0C94557C0C94557C04
:10F840000C94557C0C94557C0C94557C0C94557CF4
:10F850000C94557C0C94557C0C94557C0C94557CE4
:10F860000C94557C0C94557C0C94557C0C94557CD4
:10F8700011241FBECFEFD0E1DEBFCDBF11E0A0E06D
:10F88000B1E0EAE5FFEF02C005900D92A030B107AC
:10F89000D9F712E0A0E0B1E001C01D92A930B10794
:10F8A000E1F70E944D7D0C94AC7F0C94007CCF93CB
:10F8B000DF93CDB7DEB724970FB6F894DEBF0FBE47
:10F8C000CDBF882309F481E020E0482F552741155A
:10F8D000510509F43DC0289A19821A821B821C82A4
:10F8E0000BC089819A81AB81BC810196A11DB11D9C
:10F8F00089839A83AB83BC8389819A81AB81BC81E4
:10F9000080589E43A040B04060F3289819821A8224
:10F910001B821C820BC089819A81AB81BC810196BC
:10F92000A11DB11D89839A83AB83BC8389819A8190
:10F93000AB81BC8180509A4FA040B04060F32F5FF4
:10F94000822F992787FD9095841795070CF4C3CFD4
:10F9500019821A821B821C8289819A81AB81BC81A7
:10F9600080509147A240B040A0F489819A81AB8138
:10F97000BC810196A11DB11D89839A83AB83BC8391
:10F9800089819A81AB81BC8180509147A240B0406F
:10F9900060F324960FB6F894DEBF0FBECDBFDF91A3
:10F9A000CF910895EF92FF920F931F93EE24FF24BF
:10F9B000870128988091C00087FD17C00894E11C3A
:10F9C000F11C011D111D81E0E81689E0F8068DE3A8
:10F9D000080780E0180770F3E0910001F091010141
:10F9E00009958091C00087FFE9CF289A8091C600D1
:10F9F000992787FD90951F910F91FF90EF900895A3
:10FA0000982F8091C00085FFFCCF9093C600089589
:10FA10000E94D27C803271F0809102018F5F8093CE
:10FA20000201853009F00895E0910001F091010193
:10FA30000995089584E10E94007D80E10E94007D87
:10FA40000895CF93C82F0E94D27C803241F08091DC
:10FA500002018F5F80930201853081F40AC084E146
:10FA60000E94007D8C2F0E94007D80E10E94007D1D
:10FA700005C0E0910001F09101010995CF91089531
:10FA8000282F90E007C08091C0008823E4F7809180
:10FA9000C6009F5F9217B8F30895CFEFD0E1DEBFA5
:10FAA000CDBF000094B714BE809160008861809340
:10FAB00060001092600091FF74C189E18093C400DE
:10FAC0001092C50088E18093C10086E08093C20057
:10FAD0005098589A209A83E00E94577C81E00E94B7
:10FAE000577C0E94D27C8033B9F18133C1F18034DC
:10FAF00009F456C0813409F45CC0823409F46EC044
:10FB0000853409F471C0803539F1813509F4F3C0C9
:10FB1000823511F1853509F4D3C0863509F4CBC09F
:10FB2000843609F465C0843709F4EBC0853709F4DD
:10FB3000D2C0863709F44AC0809102018F5F80935A
:10FB40000201853071F6E0910001F0910101099503
:10FB50000E94D27C803349F60E94087DC2CF0E9469
:10FB6000D27CC82F803241F784E10E94007D81E47D
:10FB70000E94007D86E50E94007D82E50E94007D56
:10FB80008C2F0E94007D89E40E94007D83E50E9405
:10FB9000007D80E50E94007D80E10E94007DA1CF74
:10FBA0000E94D27C8638C0F20E94D27C0E94087DDE
:10FBB00098CF0E94D27C803809F407C1813809F4BB
:10FBC00000C1823809F4F9C0883921F080E00E9430
:10FBD000217D87CF83E00E94217D83CF84E10E9435
:10FBE000407D0E94087D7DCF85E00E94407DF9CF59
:10FBF0000E94D27C809306020E94D27C80930502F0
:10FC0000809108028E7F809308020E94D27C853406
:10FC100009F44BC0E5E0F1E0119281E0E438F80727
:10FC2000D9F3D0F3C0E0D0E08091050290910602B4
:10FC30001816190678F405E011E00E94D27CF8014C
:10FC400081938F0121968091050290910602C81739
:10FC5000D90798F30E94D27C803209F06DCF809151
:10FC6000080280FFB6C0C0E0D0E0209105023091CC
:10FC7000060212161306B8F4E0910301F091040194
:10FC8000A5E0B1E0F999FECFF2BDE1BD8D9180BD57
:10FC9000FA9AF99A31962196C217D30798F3F093FE
:10FCA0000401E093030184E175CF80910802816033
:10FCB00080930802AFCF84E00E94407D80E087CF30
:10FCC0000E94D27C809303010E94D27C8093040125
:10FCD0000E94087D06CF0E94D27C803209F02CCF92
:10FCE00084E10E94007D8EE10E94007D86E90E94F1
:10FCF000007D89E04FCF0E94087D88E080936000FE
:10FD0000FFCF0E94D27C809306020E94D27C809317
:10FD100005020E94D27C853409F449C08091080212
:10FD20008E7F809308028091030190910401880FD7
:10FD3000991F90930401809303010E94D27C80322A
:10FD400009F0CFCE84E10E94007DC0E0D0E0209198
:10FD50000502309106021216130608F01DCFE0913D
:10FD60000301F09104018091080280FF96C0F99987
:10FD7000FECFF2BDE1BDF89A80B50E94007DE09112
:10FD80000301F09104013196F0930401E093030123
:10FD900020910502309106022196C217D30718F36D
:10FDA000FBCEE0910001F0910101099586CE809192
:10FDB0000802816080930802C0CF80E10E94217D0B
:10FDC00090CE81E00E94217D8CCE82E00E94217D38
:10FDD00088CE8091030190910401880F991F909320
:10FDE0000401809303018091050280FF09C0809186
:10FDF00005029091060201969093060280930502F7
:10FE0000F999FECF1127E0910301F0910401C5E0BB
:10FE1000D1E08091050290910602103091F400919A
:10FE2000570001700130D9F303E000935700E895C3
:10FE30000091570001700130D9F301E100935700A0
:10FE4000E895099019900091570001700130D9F39D
:10FE500001E000935700E8951395103898F01127AA
:10FE60000091570001700130D9F305E0009357006D
:10FE7000E8950091570001700130D9F301E100933A
:10FE80005700E8953296029709F0C7CF103011F06D
:10FE90000296E5CF112484E17DCE869580FF06C0D1
:10FEA0003196F0930401E093030176CF84910E9490
:10FEB000007D2091050230910602E0910301F0914E
:10FEC0000401EECF1F93CF930E94D27CC82F0E94D3
:10FED000007D0E94D27C182F0E94007DC1362CF03C
:10FEE000C75511363CF0175508C0C033D4F3C05382
:10FEF0001136CCF710330CF01053C295C07FC10FF0
:10FF00008C2F992787FD9095CF911F910895CF93BE
:10FF1000282F992787FD9095807F907095958795DC
:10FF20009595879595958795959587958A303CF019
:10FF3000895AC22FCF70CA303CF0C95A06C0805DC2
:10FF4000C22FCF70CA30CCF7C05D0E94007D8C2FCD
:0AFF50000E94007DCF910895FFCFBD
:040000030000F80001
:00000001FF

@ -0,0 +1,121 @@
:10F800000C943E7C0C945B7C0C945B7C0C945B7C39
:10F810000C945B7C0C945B7C0C945B7C0C945B7C0C
:10F820000C945B7C0C945B7C0C945B7C0C945B7CFC
:10F830000C945B7C0C945B7C0C945B7C0C945B7CEC
:10F840000C945B7C0C945B7C0C945B7C0C945B7CDC
:10F850000C945B7C0C945B7C0C945B7C0C945B7CCC
:10F860000C945B7C0C945B7C0C945B7C0C945B7CBC
:10F870000C945B7C0C945B7C0C945B7C11241FBE11
:10F88000CFEFD0E1DEBFCDBF11E0A0E0B1E0E6E612
:10F89000FFEF02C005900D92A030B107D9F712E03A
:10F8A000A0E0B1E001C01D92A930B107E1F70E94CC
:10F8B000537D0C94B27F0C94007CCF93DF93CDB733
:10F8C000DEB724970FB6F894DEBF0FBECDBF8823F6
:10F8D00009F481E020E0482F55274115510509F42E
:10F8E0003DC0289A19821A821B821C820BC0898112
:10F8F0009A81AB81BC810196A11DB11D89839A8338
:10F90000AB83BC8389819A81AB81BC8180589E4343
:10F91000A040B04060F3289819821A821B821C8292
:10F920000BC089819A81AB81BC810196A11DB11D5B
:10F9300089839A83AB83BC8389819A81AB81BC81A3
:10F9400080509A4FA040B04060F32F5F822F9927DC
:10F9500087FD9095841795070CF4C3CF19821A82FE
:10F960001B821C8289819A81AB81BC818050914726
:10F97000A240B040A0F489819A81AB81BC810196FC
:10F98000A11DB11D89839A83AB83BC8389819A8130
:10F99000AB81BC8180509147A240B04060F3249677
:10F9A0000FB6F894DEBF0FBECDBFDF91CF910895A3
:10F9B000EF92FF920F931F93EE24FF248701289864
:10F9C0008091C00087FD17C00894E11CF11C011D47
:10F9D000111D81E0E81689E0F8068DE3080780E054
:10F9E000180770F3E0910001F091010109958091F1
:10F9F000C00087FFE9CF289A8091C600992787FD2C
:10FA000090951F910F91FF90EF900895982F8091FE
:10FA1000C00085FFFCCF9093C60008950E94D87C5B
:10FA2000803271F0809102018F5F809302018530F6
:10FA300009F00895E0910001F09101010995089500
:10FA400084E10E94067D80E10E94067D0895CF93A7
:10FA5000C82F0E94D87C803241F0809102018F5FD4
:10FA600080930201853081F40AC084E10E94067D02
:10FA70008C2F0E94067D80E10E94067D05C0E091EA
:10FA80000001F09101010995CF910895282F90E090
:10FA900007C08091C0008823E4F78091C6009F5F73
:10FAA0009217B8F30895CFEFD0E1DEBFCDBF0000CD
:10FAB00094B714BE809160008861809360001092BA
:10FAC000600091FF74C189E18093C4001092C50069
:10FAD00088E18093C10086E08093C2005098589AD4
:10FAE000209A83E00E945D7C81E00E945D7C0E9400
:10FAF000D87C8033B9F18133C1F1803409F456C028
:10FB0000813409F45CC0823409F46EC0853409F490
:10FB100071C0803539F1813509F4F3C0823511F1B6
:10FB2000853509F4D3C0863509F4CBC0843609F491
:10FB300065C0843709F4EBC0853709F4D2C0863735
:10FB400009F44AC0809102018F5F809302018530E1
:10FB500071F6E0910001F091010109950E94D87CB5
:10FB6000803349F60E940E7DC2CF0E94D87CC82FF8
:10FB7000803241F784E10E94067D81E40E94067D87
:10FB800086E50E94067D82E50E94067D8C2F0E94FC
:10FB9000067D89E40E94067D83E50E94067D80E55E
:10FBA0000E94067D80E10E94067DA1CF0E94D87C44
:10FBB0008638C0F20E94D87C0E940E7D98CF0E94A9
:10FBC000D87C803809F407C1813809F400C1823833
:10FBD00009F4F9C0883921F080E00E94277D87CFA1
:10FBE00083E00E94277D83CF84E10E94467D0E94AE
:10FBF0000E7D7DCF85E00E94467DF9CF0E94D87CA6
:10FC0000809306020E94D87C8093050280910802AE
:10FC10008E7F809308020E94D87C853409F44BC003
:10FC2000E5E0F1E0119281E0E438F807D9F3D0F390
:10FC3000C0E0D0E0809105029091060218161906E6
:10FC400078F405E011E00E94D87CF80181938F01DF
:10FC500021968091050290910602C817D90798F362
:10FC60000E94D87C803209F06DCF8091080280FF1D
:10FC7000B6C0C0E0D0E02091050230910602121615
:10FC80001306B8F4E0910301F0910401A5E0B1E09E
:10FC9000F999FECFF2BDE1BD8D9180BDFA9AF99A36
:10FCA00031962196C217D30798F3F0930401E0939D
:10FCB000030184E175CF809108028160809308027E
:10FCC000AFCF84E00E94467D80E087CF0E94D87C41
:10FCD000809303010E94D87C809304010E940E7DD2
:10FCE00006CF0E94D87C803209F02CCF84E10E949C
:10FCF000067D8EE10E94067D86E90E94067D8AE0EF
:10FD00004FCF0E940E7D88E080936000FFCF0E945D
:10FD1000D87C809306020E94D87C809305020E94C2
:10FD2000D87C853409F449C0809108028E7F809385
:10FD300008028091030190910401880F991F90930C
:10FD40000401809303010E94D87C803209F0CFCE59
:10FD500084E10E94067DC0E0D0E020910502309150
:10FD600006021216130608F01DCFE0910301F09170
:10FD700004018091080280FF96C0F999FECFF2BD80
:10FD8000E1BDF89A80B50E94067DE0910301F091F3
:10FD900004013196F0930401E093030120910502E0
:10FDA000309106022196C217D30718F3FBCEE091DB
:10FDB0000001F0910101099586CE809108028160D1
:10FDC00080930802C0CF80E10E94277D90CE81E021
:10FDD0000E94277D8CCE82E00E94277D88CE809174
:10FDE000030190910401880F991F9093040180935F
:10FDF00003018091050280FF09C080910502909166
:10FE0000060201969093060280930502F999FECFAF
:10FE10001127E0910301F0910401C5E0D1E0809148
:10FE2000050290910602103091F400915700017084
:10FE30000130D9F303E000935700E8950091570093
:10FE400001700130D9F301E100935700E895099062
:10FE500019900091570001700130D9F301E000932F
:10FE60005700E8951395103898F011270091570026
:10FE700001700130D9F305E000935700E895009137
:10FE8000570001700130D9F301E100935700E89564
:10FE90003296029709F0C7CF103011F00296E5CFE5
:10FEA000112484E17DCE869580FF06C03196F093C3
:10FEB0000401E093030176CF84910E94067D209196
:10FEC000050230910602E0910301F0910401EECFAA
:10FED0001F93CF930E94D87CC82F0E94067D0E945A
:10FEE000D87C182F0E94067DC1362CF0C7551136DC
:10FEF0003CF0175508C0C033D4F3C0531136CCF7CB
:10FF000010330CF01053C295C07FC10F8C2F99276E
:10FF100087FD9095CF911F910895CF93282F992712
:10FF200087FD9095807F907095958795959587959D
:10FF300095958795959587958A303CF0895AC22F7B
:10FF4000CF70CA303CF0C95A06C0805DC22FCF7056
:10FF5000CA30CCF7C05D0E94067D8C2F0E94067DC2
:06FF6000CF910895FFCFD0
:040000030000F80001
:00000001FF

@ -0,0 +1,56 @@
# Makefile for ATmegaBOOT
# E.Lins, 18.7.2005
# $Id$
# program name should not be changed...
PROGRAM = ATmegaBOOT_644P
# enter the target CPU frequency
AVR_FREQ = 16000000L
MCU_TARGET = atmega644p
LDSECTION = --section-start=.text=0xF800
OBJ = $(PROGRAM).o
OPTIMIZE = -O2
DEFS =
LIBS =
CC = avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -DF_CPU=$(AVR_FREQ) $(DEFS)
override LDFLAGS = -Wl,$(LDSECTION)
#override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: CFLAGS += '-DMAX_TIME_COUNT=8000000L>>1' -DADABOOT
all: $(PROGRAM).hex
$(PROGRAM).hex: $(PROGRAM).elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
$(OBJ): ATmegaBOOT.c
avr-gcc $(CFLAGS) $(LDFLAGS) -c -g -O2 -Wall -mmcu=$(MCU_TARGET) ATmegaBOOT.c -o $(PROGRAM).o
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@
clean:
rm -rf *.o *.elf *.lst *.map *.sym *.lss *.eep *.srec *.bin *.hex

@ -0,0 +1,3 @@
Note: This bootloader support ATmega644, ATmega644P and ATmega324P.
To build, set PROGRAM and MCU_TARGET in the Makefile according to your target device.

@ -0,0 +1,135 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#ifndef Wiring_h
#define Wiring_h
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,187 @@
/*
HardwareSerial.cpp - Hardware serial library for 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
Modified 23 November 2006 by David A. Mellis
Modified 28 September 2010 by Mark Sproul
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "wiring.h"
#include "wiring_private.h"
// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)
#include "HardwareSerial.h"
// Define constants and variables for buffering incoming serial data. We're
// using a ring buffer (I think), in which rx_buffer_head is the index of the
// location to which to write the next incoming character and rx_buffer_tail
// is the index of the location from which to read.
#define RX_BUFFER_SIZE 128
struct ring_buffer
{
unsigned char buffer[RX_BUFFER_SIZE];
int head;
int tail;
};
ring_buffer rx_buffer = { { 0 }, 0, 0 };
inline void store_char(unsigned char c, ring_buffer *rx_buffer)
{
int i = (unsigned int)(rx_buffer->head + 1) & (RX_BUFFER_SIZE -1);
// if we should be storing the received character into the location
// just before the tail (meaning that the head would advance to the
// current location of the tail), we're about to overflow the buffer
// and so we don't write the character or advance the head.
if (i != rx_buffer->tail) {
rx_buffer->buffer[rx_buffer->head] = c;
rx_buffer->head = i;
}
}
// fixed by Mark Sproul this is on the 644/644p
//SIGNAL(SIG_USART_RECV)
SIGNAL(USART0_RX_vect)
{
unsigned char c = UDR0;
store_char(c, &rx_buffer);
}
// Constructors ////////////////////////////////////////////////////////////////
HardwareSerial::HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x)
{
_rx_buffer = rx_buffer;
_ubrrh = ubrrh;
_ubrrl = ubrrl;
_ucsra = ucsra;
_ucsrb = ucsrb;
_udr = udr;
_rxen = rxen;
_txen = txen;
_rxcie = rxcie;
_udre = udre;
_u2x = u2x;
}
// Public Methods //////////////////////////////////////////////////////////////
void HardwareSerial::begin(long baud)
{
uint16_t baud_setting;
bool use_u2x = true;
#if F_CPU == 16000000UL
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
if (baud == 57600) {
use_u2x = false;
}
#endif
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
sbi(*_ucsrb, _rxen);
sbi(*_ucsrb, _txen);
sbi(*_ucsrb, _rxcie);
}
void HardwareSerial::end()
{
cbi(*_ucsrb, _rxen);
cbi(*_ucsrb, _txen);
cbi(*_ucsrb, _rxcie);
}
int HardwareSerial::available(void)
{
return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) & (RX_BUFFER_SIZE-1);
}
int HardwareSerial::peek(void)
{
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
return _rx_buffer->buffer[_rx_buffer->tail];
}
}
int HardwareSerial::read(void)
{
// if the head isn't ahead of the tail, we don't have any characters
if (_rx_buffer->head == _rx_buffer->tail) {
return -1;
} else {
unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) & (RX_BUFFER_SIZE-1);
return c;
}
}
void HardwareSerial::flush()
{
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// don't reverse this or there may be problems if the RX interrupt
// occurs after reading the value of rx_buffer_head but before writing
// the value to rx_buffer_tail; the previous value of rx_buffer_head
// may be written to rx_buffer_tail, making it appear as if the buffer
// were full, not empty.
_rx_buffer->head = _rx_buffer->tail;
}
void HardwareSerial::write(uint8_t c)
{
while (!((*_ucsra) & (1 << _udre)))
;
*_udr = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////
HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0);
#endif // whole file

@ -0,0 +1,76 @@
/*
HardwareSerial.h - Hardware serial library for 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
Modified 28 September 2010 by Mark Sproul
*/
#ifndef HardwareSerial_h
#define HardwareSerial_h
#include <inttypes.h>
#include "Stream.h"
struct ring_buffer;
class HardwareSerial : public Stream
{
private:
ring_buffer *_rx_buffer;
volatile uint8_t *_ubrrh;
volatile uint8_t *_ubrrl;
volatile uint8_t *_ucsra;
volatile uint8_t *_ucsrb;
volatile uint8_t *_udr;
uint8_t _rxen;
uint8_t _txen;
uint8_t _rxcie;
uint8_t _udre;
uint8_t _u2x;
public:
HardwareSerial(ring_buffer *rx_buffer,
volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
volatile uint8_t *udr,
uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udre, uint8_t u2x);
void begin(long);
void end();
virtual int available(void);
virtual int peek(void);
virtual int read(void);
virtual void flush(void);
virtual void write(uint8_t);
using Print::write; // pull in write(str) and write(buf, size) from Print
};
#if defined(UBRRH) || defined(UBRR0H)
extern HardwareSerial Serial;
#elif defined(USBCON)
#include "usb_api.h"
#endif
#if defined(UBRR1H)
extern HardwareSerial Serial1;
#endif
#if defined(UBRR2H)
extern HardwareSerial Serial2;
#endif
#if defined(UBRR3H)
extern HardwareSerial Serial3;
#endif
#endif

@ -0,0 +1,220 @@
/*
Print.cpp - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 23 November 2006 by David A. Mellis
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "wiring.h"
#include "Print.h"
// Public Methods //////////////////////////////////////////////////////////////
/* default implementation: may be overridden */
void Print::write(const char *str)
{
while (*str)
write(*str++);
}
/* default implementation: may be overridden */
void Print::write(const uint8_t *buffer, size_t size)
{
while (size--)
write(*buffer++);
}
void Print::print(const String &s)
{
for (int i = 0; i < s.length(); i++) {
write(s[i]);
}
}
void Print::print(const char str[])
{
write(str);
}
void Print::print(char c, int base)
{
print((long) c, base);
}
void Print::print(unsigned char b, int base)
{
print((unsigned long) b, base);
}
void Print::print(int n, int base)
{
print((long) n, base);
}
void Print::print(unsigned int n, int base)
{
print((unsigned long) n, base);
}
void Print::print(long n, int base)
{
if (base == 0) {
write(n);
} else if (base == 10) {
if (n < 0) {
print('-');
n = -n;
}
printNumber(n, 10);
} else {
printNumber(n, base);
}
}
void Print::print(unsigned long n, int base)
{
if (base == 0) write(n);
else printNumber(n, base);
}
void Print::print(double n, int digits)
{
printFloat(n, digits);
}
void Print::println(void)
{
print('\r');
print('\n');
}
void Print::println(const String &s)
{
print(s);
println();
}
void Print::println(const char c[])
{
print(c);
println();
}
void Print::println(char c, int base)
{
print(c, base);
println();
}
void Print::println(unsigned char b, int base)
{
print(b, base);
println();
}
void Print::println(int n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned int n, int base)
{
print(n, base);
println();
}
void Print::println(long n, int base)
{
print(n, base);
println();
}
void Print::println(unsigned long n, int base)
{
print(n, base);
println();
}
void Print::println(double n, int digits)
{
print(n, digits);
println();
}
// Private Methods /////////////////////////////////////////////////////////////
void Print::printNumber(unsigned long n, uint8_t base)
{
unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
unsigned long i = 0;
if (n == 0) {
print('0');
return;
}
while (n > 0) {
buf[i++] = n % base;
n /= base;
}
for (; i > 0; i--)
print((char) (buf[i - 1] < 10 ?
'0' + buf[i - 1] :
'A' + buf[i - 1] - 10));
}
void Print::printFloat(double number, uint8_t digits)
{
// Handle negative numbers
if (number < 0.0)
{
print('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
for (uint8_t i=0; i<digits; ++i)
rounding /= 10.0;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
print(int_part);
// Print the decimal point, but only if there are digits beyond
if (digits > 0)
print(".");
// Extract digits from the remainder one at a time
while (digits-- > 0)
{
remainder *= 10.0;
int toPrint = int(remainder);
print(toPrint);
remainder -= toPrint;
}
}

@ -0,0 +1,66 @@
/*
Print.h - Base class that provides print() and println()
Copyright (c) 2008 David A. Mellis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef Print_h
#define Print_h
#include <inttypes.h>
#include <stdio.h> // for size_t
#include "WString.h"
#define DEC 10
#define HEX 16
#define OCT 8
#define BIN 2
#define BYTE 0
class Print
{
private:
void printNumber(unsigned long, uint8_t);
void printFloat(double, uint8_t);
public:
virtual void write(uint8_t) = 0;
virtual void write(const char *str);
virtual void write(const uint8_t *buffer, size_t size);
void print(const String &);
void print(const char[]);
void print(char, int = BYTE);
void print(unsigned char, int = BYTE);
void print(int, int = DEC);
void print(unsigned int, int = DEC);
void print(long, int = DEC);
void print(unsigned long, int = DEC);
void print(double, int = 2);
void println(const String &s);
void println(const char[]);
void println(char, int = BYTE);
void println(unsigned char, int = BYTE);
void println(int, int = DEC);
void println(unsigned int, int = DEC);
void println(long, int = DEC);
void println(unsigned long, int = DEC);
void println(double, int = 2);
void println(void);
};
#endif

@ -0,0 +1,35 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 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 Stream_h
#define Stream_h
#include <inttypes.h>
#include "Print.h"
class Stream : public Print
{
public:
virtual int available() = 0;
virtual int read() = 0;
virtual int peek() = 0;
virtual void flush() = 0;
};
#endif

@ -0,0 +1,601 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
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
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
*************************************************/
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "wiring.h"
#include "pins_arduino.h"
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#endif
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
#if !defined(__AVR_ATmega8__)
volatile long timer0_toggle_count;
volatile uint8_t *timer0_pin_port;
volatile uint8_t timer0_pin_mask;
#endif
volatile long timer1_toggle_count;
volatile uint8_t *timer1_pin_port;
volatile uint8_t timer1_pin_mask;
volatile long timer2_toggle_count;
volatile uint8_t *timer2_pin_port;
volatile uint8_t timer2_pin_mask;
#if defined(TIMSK3)
volatile long timer3_toggle_count;
volatile uint8_t *timer3_pin_port;
volatile uint8_t timer3_pin_mask;
#endif
#if defined(TIMSK4)
volatile long timer4_toggle_count;
volatile uint8_t *timer4_pin_port;
volatile uint8_t timer4_pin_mask;
#endif
#if defined(TIMSK5)
volatile long timer5_toggle_count;
volatile uint8_t *timer5_pin_port;
volatile uint8_t timer5_pin_mask;
#endif
// MLS: This does not make sense, the 3 options are the same
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
#elif defined(__AVR_ATmega8__)
#define AVAILABLE_TONE_PINS 1
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
#else
#define AVAILABLE_TONE_PINS 1
// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
#endif
static int8_t toneBegin(uint8_t _pin)
{
int8_t _timer = -1;
// if we're already using the pin, the timer should be configured.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
return pgm_read_byte(tone_pin_to_timer_PGM + i);
}
}
// search for an unused timer.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == 255) {
tone_pins[i] = _pin;
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
break;
}
}
if (_timer != -1)
{
// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch (_timer)
{
#if defined(TCCR0A) && defined(TCCR0B)
case 0:
// 8 bit timer
TCCR0A = 0;
TCCR0B = 0;
bitWrite(TCCR0A, WGM01, 1);
bitWrite(TCCR0B, CS00, 1);
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer0_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
case 1:
// 16 bit timer
TCCR1A = 0;
TCCR1B = 0;
bitWrite(TCCR1B, WGM12, 1);
bitWrite(TCCR1B, CS10, 1);
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer1_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR2A) && defined(TCCR2B)
case 2:
// 8 bit timer
TCCR2A = 0;
TCCR2B = 0;
bitWrite(TCCR2A, WGM21, 1);
bitWrite(TCCR2B, CS20, 1);
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer2_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
case 3:
// 16 bit timer
TCCR3A = 0;
TCCR3B = 0;
bitWrite(TCCR3B, WGM32, 1);
bitWrite(TCCR3B, CS30, 1);
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer3_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
case 4:
// 16 bit timer
TCCR4A = 0;
TCCR4B = 0;
#if defined(WGM42)
bitWrite(TCCR4B, WGM42, 1);
#elif defined(CS43)
#warning this may not be correct
// atmega32u4
bitWrite(TCCR4B, CS43, 1);
#endif
bitWrite(TCCR4B, CS40, 1);
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer4_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
case 5:
// 16 bit timer
TCCR5A = 0;
TCCR5B = 0;
bitWrite(TCCR5B, WGM52, 1);
bitWrite(TCCR5B, CS50, 1);
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer5_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
}
}
return _timer;
}
// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
uint8_t prescalarbits = 0b001;
long toggle_count = 0;
uint32_t ocr = 0;
int8_t _timer;
_timer = toneBegin(_pin);
if (_timer >= 0)
{
// Set the pinMode as OUTPUT
pinMode(_pin, OUTPUT);
// if we are using an 8 bit timer, scan through prescalars to find the best fit
if (_timer == 0 || _timer == 2)
{
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001; // ck/1: same for both timers
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 8 - 1;
prescalarbits = 0b010; // ck/8: same for both timers
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 32 - 1;
prescalarbits = 0b011;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = _timer == 0 ? 0b011 : 0b100;
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 128 - 1;
prescalarbits = 0b101;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 256 - 1;
prescalarbits = _timer == 0 ? 0b100 : 0b110;
if (ocr > 255)
{
// can't do any better than /1024
ocr = F_CPU / frequency / 2 / 1024 - 1;
prescalarbits = _timer == 0 ? 0b101 : 0b111;
}
}
}
}
#if defined(TCCR0B)
if (_timer == 0)
{
TCCR0B = prescalarbits;
}
else
#endif
#if defined(TCCR2B)
{
TCCR2B = prescalarbits;
}
#else
{
// dummy place holder to make the above ifdefs work
}
#endif
}
else
{
// two choices for the 16 bit timers: ck/1 or ck/64
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001;
if (ocr > 0xffff)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = 0b011;
}
if (_timer == 1)
{
#if defined(TCCR1B)
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
#endif
}
#if defined(TCCR3B)
else if (_timer == 3)
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR4B)
else if (_timer == 4)
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR5B)
else if (_timer == 5)
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
#endif
}
// Calculate the toggle count
if (duration > 0)
{
toggle_count = 2 * frequency * duration / 1000;
}
else
{
toggle_count = -1;
}
// Set the OCR for the given timer,
// set the toggle count,
// then turn on the interrupts
switch (_timer)
{
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
case 0:
OCR0A = ocr;
timer0_toggle_count = toggle_count;
bitWrite(TIMSK0, OCIE0A, 1);
break;
#endif
case 1:
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK1, OCIE1A, 1);
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
// this combination is for at least the ATmega32
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK, OCIE1A, 1);
#endif
break;
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
case 2:
OCR2A = ocr;
timer2_toggle_count = toggle_count;
bitWrite(TIMSK2, OCIE2A, 1);
break;
#endif
#if defined(TIMSK3)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
bitWrite(TIMSK3, OCIE3A, 1);
break;
#endif
#if defined(TIMSK4)
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
bitWrite(TIMSK4, OCIE4A, 1);
break;
#endif
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
case 5:
OCR5A = ocr;
timer5_toggle_count = toggle_count;
bitWrite(TIMSK5, OCIE5A, 1);
break;
#endif
}
}
}
// XXX: this function only works properly for timer 2 (the only one we use
// currently). for the others, it should end the tone, but won't restore
// proper PWM functionality for the timer.
void disableTimer(uint8_t _timer)
{
switch (_timer)
{
case 0:
#if defined(TIMSK0)
TIMSK0 = 0;
#elif defined(TIMSK)
TIMSK = 0; // atmega32
#endif
break;
#if defined(TIMSK1) && defined(OCIE1A)
case 1:
bitWrite(TIMSK1, OCIE1A, 0);
break;
#endif
case 2:
#if defined(TIMSK2) && defined(OCIE2A)
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
#endif
#if defined(TCCR2A) && defined(WGM20)
TCCR2A = (1 << WGM20);
#endif
#if defined(TCCR2B) && defined(CS22)
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
#endif
#if defined(OCR2A)
OCR2A = 0;
#endif
break;
#if defined(TIMSK3)
case 3:
TIMSK3 = 0;
break;
#endif
#if defined(TIMSK4)
case 4:
TIMSK4 = 0;
break;
#endif
#if defined(TIMSK5)
case 5:
TIMSK5 = 0;
break;
#endif
}
}
void noTone(uint8_t _pin)
{
int8_t _timer = -1;
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
tone_pins[i] = 255;
}
}
disableTimer(_timer);
digitalWrite(_pin, 0);
}
#if 0
#if !defined(__AVR_ATmega8__)
ISR(TIMER0_COMPA_vect)
{
if (timer0_toggle_count != 0)
{
// toggle the pin
*timer0_pin_port ^= timer0_pin_mask;
if (timer0_toggle_count > 0)
timer0_toggle_count--;
}
else
{
disableTimer(0);
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER1_COMPA_vect)
{
if (timer1_toggle_count != 0)
{
// toggle the pin
*timer1_pin_port ^= timer1_pin_mask;
if (timer1_toggle_count > 0)
timer1_toggle_count--;
}
else
{
disableTimer(1);
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
}
}
#endif
ISR(TIMER2_COMPA_vect)
{
if (timer2_toggle_count != 0)
{
// toggle the pin
*timer2_pin_port ^= timer2_pin_mask;
if (timer2_toggle_count > 0)
timer2_toggle_count--;
}
else
{
// need to call noTone() so that the tone_pins[] entry is reset, so the
// timer gets initialized next time we call tone().
// XXX: this assumes timer 2 is always the first one used.
noTone(tone_pins[0]);
// disableTimer(2);
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
}
}
//#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#if 0
ISR(TIMER3_COMPA_vect)
{
if (timer3_toggle_count != 0)
{
// toggle the pin
*timer3_pin_port ^= timer3_pin_mask;
if (timer3_toggle_count > 0)
timer3_toggle_count--;
}
else
{
disableTimer(3);
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
}
}
ISR(TIMER4_COMPA_vect)
{
if (timer4_toggle_count != 0)
{
// toggle the pin
*timer4_pin_port ^= timer4_pin_mask;
if (timer4_toggle_count > 0)
timer4_toggle_count--;
}
else
{
disableTimer(4);
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
}
}
ISR(TIMER5_COMPA_vect)
{
if (timer5_toggle_count != 0)
{
// toggle the pin
*timer5_pin_port ^= timer5_pin_mask;
if (timer5_toggle_count > 0)
timer5_toggle_count--;
}
else
{
disableTimer(5);
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
}
}
#endif

@ -0,0 +1,168 @@
/*
WCharacter.h - Character utility functions for Wiring & Arduino
Copyright (c) 2010 Hernando Barragan. 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 Character_h
#define Character_h
#include <ctype.h>
// WCharacter.h prototypes
inline boolean isAlphaNumeric(int c) __attribute__((always_inline));
inline boolean isAlpha(int c) __attribute__((always_inline));
inline boolean isAscii(int c) __attribute__((always_inline));
inline boolean isWhitespace(int c) __attribute__((always_inline));
inline boolean isControl(int c) __attribute__((always_inline));
inline boolean isDigit(int c) __attribute__((always_inline));
inline boolean isGraph(int c) __attribute__((always_inline));
inline boolean isLowerCase(int c) __attribute__((always_inline));
inline boolean isPrintable(int c) __attribute__((always_inline));
inline boolean isPunct(int c) __attribute__((always_inline));
inline boolean isSpace(int c) __attribute__((always_inline));
inline boolean isUpperCase(int c) __attribute__((always_inline));
inline boolean isHexadecimalDigit(int c) __attribute__((always_inline));
inline int toAscii(int c) __attribute__((always_inline));
inline int toLowerCase(int c) __attribute__((always_inline));
inline int toUpperCase(int c)__attribute__((always_inline));
// Checks for an alphanumeric character.
// It is equivalent to (isalpha(c) || isdigit(c)).
inline boolean isAlphaNumeric(int c)
{
return ( isalnum(c) == 0 ? false : true);
}
// Checks for an alphabetic character.
// It is equivalent to (isupper(c) || islower(c)).
inline boolean isAlpha(int c)
{
return ( isalpha(c) == 0 ? false : true);
}
// Checks whether c is a 7-bit unsigned char value
// that fits into the ASCII character set.
inline boolean isAscii(int c)
{
return ( isascii (c) == 0 ? false : true);
}
// Checks for a blank character, that is, a space or a tab.
inline boolean isWhitespace(int c)
{
return ( isblank (c) == 0 ? false : true);
}
// Checks for a control character.
inline boolean isControl(int c)
{
return ( iscntrl (c) == 0 ? false : true);
}
// Checks for a digit (0 through 9).
inline boolean isDigit(int c)
{
return ( isdigit (c) == 0 ? false : true);
}
// Checks for any printable character except space.
inline boolean isGraph(int c)
{
return ( isgraph (c) == 0 ? false : true);
}
// Checks for a lower-case character.
inline boolean isLowerCase(int c)
{
return (islower (c) == 0 ? false : true);
}
// Checks for any printable character including space.
inline boolean isPrintable(int c)
{
return ( isprint (c) == 0 ? false : true);
}
// Checks for any printable character which is not a space
// or an alphanumeric character.
inline boolean isPunct(int c)
{
return ( ispunct (c) == 0 ? false : true);
}
// Checks for white-space characters. For the avr-libc library,
// these are: space, formfeed ('\f'), newline ('\n'), carriage
// return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
inline boolean isSpace(int c)
{
return ( isspace (c) == 0 ? false : true);
}
// Checks for an uppercase letter.
inline boolean isUpperCase(int c)
{
return ( isupper (c) == 0 ? false : true);
}
// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7
// 8 9 a b c d e f A B C D E F.
inline boolean isHexadecimalDigit(int c)
{
return ( isxdigit (c) == 0 ? false : true);
}
// Converts c to a 7-bit unsigned char value that fits into the
// ASCII character set, by clearing the high-order bits.
inline int toAscii(int c)
{
return toascii (c);
}
// Warning:
// Many people will be unhappy if you use this function.
// This function will convert accented letters into random
// characters.
// Converts the letter c to lower case, if possible.
inline int toLowerCase(int c)
{
return tolower (c);
}
// Converts the letter c to upper case, if possible.
inline int toUpperCase(int c)
{
return toupper (c);
}
#endif

@ -0,0 +1,249 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.uniandes.edu.co
Copyright (c) 2004-05 Hernando Barragan
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 24 November 2006 by David A. Mellis
Modified 1 August 2010 by Mark Sproul
*/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <stdio.h>
#include "WConstants.h"
#include "wiring_private.h"
volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS];
// volatile static voidFuncPtr twiIntFunc;
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
intFunc[interruptNum] = userFunc;
// Configure the interrupt mode (trigger on low input, any change, rising
// edge, or falling edge). The mode constants were chosen to correspond
// to the configuration bits in the hardware register, so we simply shift
// the mode into place.
// Enable the interrupt.
switch (interruptNum) {
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
break;
case 3:
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
break;
case 4:
EICRA = (EICRA & ~((1 << ISC20) | (1 << ISC21))) | (mode << ISC20);
EIMSK |= (1 << INT2);
break;
case 5:
EICRA = (EICRA & ~((1 << ISC30) | (1 << ISC31))) | (mode << ISC30);
EIMSK |= (1 << INT3);
break;
case 0:
EICRB = (EICRB & ~((1 << ISC40) | (1 << ISC41))) | (mode << ISC40);
EIMSK |= (1 << INT4);
break;
case 1:
EICRB = (EICRB & ~((1 << ISC50) | (1 << ISC51))) | (mode << ISC50);
EIMSK |= (1 << INT5);
break;
case 6:
EICRB = (EICRB & ~((1 << ISC60) | (1 << ISC61))) | (mode << ISC60);
EIMSK |= (1 << INT6);
break;
case 7:
EICRB = (EICRB & ~((1 << ISC70) | (1 << ISC71))) | (mode << ISC70);
EIMSK |= (1 << INT7);
break;
#else
case 0:
#if defined(EICRA) && defined(ISC00) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
EIMSK |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GICR |= (1 << INT0);
#elif defined(MCUCR) && defined(ISC00) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC00) | (1 << ISC01))) | (mode << ISC00);
GIMSK |= (1 << INT0);
#else
#error attachInterrupt not finished for this CPU (case 0)
#endif
break;
case 1:
#if defined(EICRA) && defined(ISC10) && defined(ISC11) && defined(EIMSK)
EICRA = (EICRA & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
EIMSK |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(ISC11) && defined(GICR)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GICR |= (1 << INT1);
#elif defined(MCUCR) && defined(ISC10) && defined(GIMSK) && defined(GIMSK)
MCUCR = (MCUCR & ~((1 << ISC10) | (1 << ISC11))) | (mode << ISC10);
GIMSK |= (1 << INT1);
#else
#warning attachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
}
}
void detachInterrupt(uint8_t interruptNum) {
if(interruptNum < EXTERNAL_NUM_INTERRUPTS) {
// Disable the interrupt. (We can't assume that interruptNum is equal
// to the number of the EIMSK bit to clear, as this isn't true on the
// ATmega8. There, INT0 is 6 and INT1 is 7.)
switch (interruptNum) {
#if defined(EICRA) && defined(EICRB) && defined(EIMSK)
case 2:
EIMSK &= ~(1 << INT0);
break;
case 3:
EIMSK &= ~(1 << INT1);
break;
case 4:
EIMSK &= ~(1 << INT2);
break;
case 5:
EIMSK &= ~(1 << INT3);
break;
case 0:
EIMSK &= ~(1 << INT4);
break;
case 1:
EIMSK &= ~(1 << INT5);
break;
case 6:
EIMSK &= ~(1 << INT6);
break;
case 7:
EIMSK &= ~(1 << INT7);
break;
#else
case 0:
#if defined(EIMSK) && defined(INT0)
EIMSK &= ~(1 << INT0);
#elif defined(GICR) && defined(ISC00)
GICR &= ~(1 << INT0); // atmega32
#elif defined(GIMSK) && defined(INT0)
GIMSK &= ~(1 << INT0);
#else
#error detachInterrupt not finished for this cpu
#endif
break;
case 1:
#if defined(EIMSK) && defined(INT1)
EIMSK &= ~(1 << INT1);
#elif defined(GICR) && defined(INT1)
GICR &= ~(1 << INT1); // atmega32
#elif defined(GIMSK) && defined(INT1)
GIMSK &= ~(1 << INT1);
#else
#warning detachInterrupt may need some more work for this cpu (case 1)
#endif
break;
#endif
}
intFunc[interruptNum] = 0;
}
}
/*
void attachInterruptTwi(void (*userFunc)(void) ) {
twiIntFunc = userFunc;
}
*/
#if defined(EICRA) && defined(EICRB)
SIGNAL(INT0_vect) {
if(intFunc[EXTERNAL_INT_2])
intFunc[EXTERNAL_INT_2]();
}
SIGNAL(INT1_vect) {
if(intFunc[EXTERNAL_INT_3])
intFunc[EXTERNAL_INT_3]();
}
SIGNAL(INT2_vect) {
if(intFunc[EXTERNAL_INT_4])
intFunc[EXTERNAL_INT_4]();
}
SIGNAL(INT3_vect) {
if(intFunc[EXTERNAL_INT_5])
intFunc[EXTERNAL_INT_5]();
}
SIGNAL(INT4_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
SIGNAL(INT5_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
SIGNAL(INT6_vect) {
if(intFunc[EXTERNAL_INT_6])
intFunc[EXTERNAL_INT_6]();
}
SIGNAL(INT7_vect) {
if(intFunc[EXTERNAL_INT_7])
intFunc[EXTERNAL_INT_7]();
}
#else
SIGNAL(INT0_vect) {
if(intFunc[EXTERNAL_INT_0])
intFunc[EXTERNAL_INT_0]();
}
SIGNAL(INT1_vect) {
if(intFunc[EXTERNAL_INT_1])
intFunc[EXTERNAL_INT_1]();
}
#endif
/*
SIGNAL(SIG_2WIRE_SERIAL) {
if(twiIntFunc)
twiIntFunc();
}
*/

@ -0,0 +1,60 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Wiring project - http://wiring.org.co
Copyright (c) 2004-06 Hernando Barragan
Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
extern "C" {
#include "stdlib.h"
}
void randomSeed(unsigned int seed)
{
if (seed != 0) {
srandom(seed);
}
}
long random(long howbig)
{
if (howbig == 0) {
return 0;
}
return random() % howbig;
}
long random(long howsmall, long howbig)
{
if (howsmall >= howbig) {
return howsmall;
}
long diff = howbig - howsmall;
return random(diff) + howsmall;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
unsigned int makeWord(unsigned int w) { return w; }
unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }

@ -0,0 +1,63 @@
#ifndef WProgram_h
#define WProgram_h
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/interrupt.h>
#include "wiring.h"
#ifdef __cplusplus
#include "WCharacter.h"
#include "WString.h"
#include "HardwareSerial.h"
uint16_t makeWord(uint16_t w);
uint16_t makeWord(byte h, byte l);
#define word(...) makeWord(__VA_ARGS__)
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
// WMath prototypes
long random(long);
long random(long, long);
void randomSeed(unsigned int);
long map(long, long, long, long, long);
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
const static uint8_t A0 = 54;
const static uint8_t A1 = 55;
const static uint8_t A2 = 56;
const static uint8_t A3 = 57;
const static uint8_t A4 = 58;
const static uint8_t A5 = 59;
const static uint8_t A6 = 60;
const static uint8_t A7 = 61;
const static uint8_t A8 = 62;
const static uint8_t A9 = 63;
const static uint8_t A10 = 64;
const static uint8_t A11 = 65;
const static uint8_t A12 = 66;
const static uint8_t A13 = 67;
const static uint8_t A14 = 68;
const static uint8_t A15 = 69;
#else
const static uint8_t A0 = 14;
const static uint8_t A1 = 15;
const static uint8_t A2 = 16;
const static uint8_t A3 = 17;
const static uint8_t A4 = 18;
const static uint8_t A5 = 19;
const static uint8_t A6 = 20;
const static uint8_t A7 = 21;
#endif
#endif
#endif

@ -0,0 +1,443 @@
/*
WString.cpp - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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.
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
*/
#include <stdlib.h>
#include "WProgram.h"
#include "WString.h"
String::String( const char *value )
{
if ( value == NULL )
value = "";
getBuffer( _length = strlen( value ) );
if ( _buffer != NULL )
strcpy( _buffer, value );
}
String::String( const String &value )
{
getBuffer( _length = value._length );
if ( _buffer != NULL )
strcpy( _buffer, value._buffer );
}
String::String( const char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL ) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const unsigned char value )
{
_length = 1;
getBuffer(1);
if ( _buffer != NULL) {
_buffer[0] = value;
_buffer[1] = 0;
}
}
String::String( const int value, const int base )
{
char buf[33];
itoa((signed long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned int value, const int base )
{
char buf[33];
ultoa((unsigned long)value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const long value, const int base )
{
char buf[33];
ltoa(value, buf, base);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
String::String( const unsigned long value, const int base )
{
char buf[33];
ultoa(value, buf, 10);
getBuffer( _length = strlen(buf) );
if ( _buffer != NULL )
strcpy( _buffer, buf );
}
char String::charAt( unsigned int loc ) const
{
return operator[]( loc );
}
void String::setCharAt( unsigned int loc, const char aChar )
{
if(_buffer == NULL) return;
if(_length > loc) {
_buffer[loc] = aChar;
}
}
int String::compareTo( const String &s2 ) const
{
return strcmp( _buffer, s2._buffer );
}
const String & String::concat( const String &s2 )
{
return (*this) += s2;
}
const String & String::operator=( const String &rhs )
{
if ( this == &rhs )
return *this;
if ( rhs._length > _length )
{
free(_buffer);
getBuffer( rhs._length );
}
if ( _buffer != NULL ) {
_length = rhs._length;
strcpy( _buffer, rhs._buffer );
}
return *this;
}
//const String & String::operator+=( const char aChar )
//{
// if ( _length == _capacity )
// doubleBuffer();
//
// _buffer[ _length++ ] = aChar;
// _buffer[ _length ] = '\0';
// return *this;
//}
const String & String::operator+=( const String &other )
{
_length += other._length;
if ( _length > _capacity )
{
char *temp = (char *)realloc(_buffer, _length + 1);
if ( temp != NULL ) {
_buffer = temp;
_capacity = _length;
} else {
_length -= other._length;
return *this;
}
}
strcat( _buffer, other._buffer );
return *this;
}
int String::operator==( const String &rhs ) const
{
return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 );
}
int String::operator!=( const String &rhs ) const
{
return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 );
}
int String::operator<( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) < 0;
}
int String::operator>( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) > 0;
}
int String::operator<=( const String &rhs ) const
{
return strcmp( _buffer, rhs._buffer ) <= 0;
}
int String::operator>=( const String & rhs ) const
{
return strcmp( _buffer, rhs._buffer ) >= 0;
}
char & String::operator[]( unsigned int index )
{
static char dummy_writable_char;
if (index >= _length || !_buffer) {
dummy_writable_char = 0;
return dummy_writable_char;
}
return _buffer[ index ];
}
char String::operator[]( unsigned int index ) const
{
// need to check for valid index, to do later
return _buffer[ index ];
}
boolean String::endsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0;
}
boolean String::equals( const String &s2 ) const
{
return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 );
}
boolean String::equalsIgnoreCase( const String &s2 ) const
{
if ( this == &s2 )
return true; //1;
else if ( _length != s2._length )
return false; //0;
return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0;
}
String String::replace( char findChar, char replaceChar )
{
if ( _buffer == NULL ) return *this;
String theReturn = _buffer;
char* temp = theReturn._buffer;
while( (temp = strchr( temp, findChar )) != 0 )
*temp = replaceChar;
return theReturn;
}
String String::replace( const String& match, const String& replace )
{
if ( _buffer == NULL ) return *this;
String temp = _buffer, newString;
int loc;
while ( (loc = temp.indexOf( match )) != -1 )
{
newString += temp.substring( 0, loc );
newString += replace;
temp = temp.substring( loc + match._length );
}
newString += temp;
return newString;
}
int String::indexOf( char temp ) const
{
return indexOf( temp, 0 );
}
int String::indexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char* temp = strchr( &_buffer[fromIndex], ch );
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::indexOf( const String &s2 ) const
{
return indexOf( s2, 0 );
}
int String::indexOf( const String &s2, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer );
if ( theFind == NULL )
return -1;
return theFind - _buffer; // pointer subtraction
}
int String::lastIndexOf( char theChar ) const
{
return lastIndexOf( theChar, _length - 1 );
}
int String::lastIndexOf( char ch, unsigned int fromIndex ) const
{
if ( fromIndex >= _length )
return -1;
char tempchar = _buffer[fromIndex + 1];
_buffer[fromIndex + 1] = '\0';
char* temp = strrchr( _buffer, ch );
_buffer[fromIndex + 1] = tempchar;
if ( temp == NULL )
return -1;
return temp - _buffer;
}
int String::lastIndexOf( const String &s2 ) const
{
return lastIndexOf( s2, _length - s2._length );
}
int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const
{
// check for empty strings
if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length )
return -1;
// matching first character
char temp = s2[ 0 ];
for ( int i = fromIndex; i >= 0; i-- )
{
if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) )
return i;
}
return -1;
}
boolean String::startsWith( const String &s2 ) const
{
if ( _length < s2._length )
return 0;
return startsWith( s2, 0 );
}
boolean String::startsWith( const String &s2, unsigned int offset ) const
{
if ( offset > _length - s2._length )
return 0;
return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0;
}
String String::substring( unsigned int left ) const
{
return substring( left, _length );
}
String String::substring( unsigned int left, unsigned int right ) const
{
if ( left > right )
{
int temp = right;
right = left;
left = temp;
}
if ( right > _length )
{
right = _length;
}
char temp = _buffer[ right ]; // save the replaced character
_buffer[ right ] = '\0';
String outPut = ( _buffer + left ); // pointer arithmetic
_buffer[ right ] = temp; //restore character
return outPut;
}
String String::toLowerCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] );
return temp;
}
String String::toUpperCase() const
{
String temp = _buffer;
for ( unsigned int i = 0; i < _length; i++ )
temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] );
return temp;
}
String String::trim() const
{
if ( _buffer == NULL ) return *this;
String temp = _buffer;
unsigned int i,j;
for ( i = 0; i < _length; i++ )
{
if ( !isspace(_buffer[i]) )
break;
}
for ( j = temp._length - 1; j > i; j-- )
{
if ( !isspace(_buffer[j]) )
break;
}
return temp.substring( i, j + 1);
}
void String::getBytes(unsigned char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy((char *)buf, _buffer, len);
buf[len] = 0;
}
void String::toCharArray(char *buf, unsigned int bufsize)
{
if (!bufsize || !buf) return;
unsigned int len = bufsize - 1;
if (len > _length) len = _length;
strncpy(buf, _buffer, len);
buf[len] = 0;
}
long String::toInt() {
return atol(_buffer);
}

@ -0,0 +1,112 @@
/*
WString.h - String library for Wiring & Arduino
Copyright (c) 2009-10 Hernando Barragan. 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 String_h
#define String_h
//#include "WProgram.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
class String
{
public:
// constructors
String( const char *value = "" );
String( const String &value );
String( const char );
String( const unsigned char );
String( const int, const int base=10);
String( const unsigned int, const int base=10 );
String( const long, const int base=10 );
String( const unsigned long, const int base=10 );
~String() { free(_buffer); _length = _capacity = 0;} //added _length = _capacity = 0;
// operators
const String & operator = ( const String &rhs );
const String & operator +=( const String &rhs );
//const String & operator +=( const char );
int operator ==( const String &rhs ) const;
int operator !=( const String &rhs ) const;
int operator < ( const String &rhs ) const;
int operator > ( const String &rhs ) const;
int operator <=( const String &rhs ) const;
int operator >=( const String &rhs ) const;
char operator []( unsigned int index ) const;
char& operator []( unsigned int index );
//operator const char *() const { return _buffer; }
// general methods
char charAt( unsigned int index ) const;
int compareTo( const String &anotherString ) const;
unsigned char endsWith( const String &suffix ) const;
unsigned char equals( const String &anObject ) const;
unsigned char equalsIgnoreCase( const String &anotherString ) const;
int indexOf( char ch ) const;
int indexOf( char ch, unsigned int fromIndex ) const;
int indexOf( const String &str ) const;
int indexOf( const String &str, unsigned int fromIndex ) const;
int lastIndexOf( char ch ) const;
int lastIndexOf( char ch, unsigned int fromIndex ) const;
int lastIndexOf( const String &str ) const;
int lastIndexOf( const String &str, unsigned int fromIndex ) const;
const unsigned int length( ) const { return _length; }
void setCharAt(unsigned int index, const char ch);
unsigned char startsWith( const String &prefix ) const;
unsigned char startsWith( const String &prefix, unsigned int toffset ) const;
String substring( unsigned int beginIndex ) const;
String substring( unsigned int beginIndex, unsigned int endIndex ) const;
String toLowerCase( ) const;
String toUpperCase( ) const;
String trim( ) const;
void getBytes(unsigned char *buf, unsigned int bufsize);
void toCharArray(char *buf, unsigned int bufsize);
long toInt( );
const String& concat( const String &str );
String replace( char oldChar, char newChar );
String replace( const String& match, const String& replace );
friend String operator + ( String lhs, const String &rhs );
protected:
char *_buffer; // the actual char array
unsigned int _capacity; // the array length minus one (for the '\0')
unsigned int _length; // the String length (not counting the '\0')
void getBuffer(unsigned int maxStrLen);
private:
};
// allocate buffer space
inline void String::getBuffer(unsigned int maxStrLen)
{
_capacity = maxStrLen;
_buffer = (char *) malloc(_capacity + 1);
if (_buffer == NULL) _length = _capacity = 0;
}
inline String operator+( String lhs, const String &rhs )
{
return lhs += rhs;
}
#endif

@ -0,0 +1,515 @@
#ifndef Binary_h
#define Binary_h
#define B0 0
#define B00 0
#define B000 0
#define B0000 0
#define B00000 0
#define B000000 0
#define B0000000 0
#define B00000000 0
#define B1 1
#define B01 1
#define B001 1
#define B0001 1
#define B00001 1
#define B000001 1
#define B0000001 1
#define B00000001 1
#define B10 2
#define B010 2
#define B0010 2
#define B00010 2
#define B000010 2
#define B0000010 2
#define B00000010 2
#define B11 3
#define B011 3
#define B0011 3
#define B00011 3
#define B000011 3
#define B0000011 3
#define B00000011 3
#define B100 4
#define B0100 4
#define B00100 4
#define B000100 4
#define B0000100 4
#define B00000100 4
#define B101 5
#define B0101 5
#define B00101 5
#define B000101 5
#define B0000101 5
#define B00000101 5
#define B110 6
#define B0110 6
#define B00110 6
#define B000110 6
#define B0000110 6
#define B00000110 6
#define B111 7
#define B0111 7
#define B00111 7
#define B000111 7
#define B0000111 7
#define B00000111 7
#define B1000 8
#define B01000 8
#define B001000 8
#define B0001000 8
#define B00001000 8
#define B1001 9
#define B01001 9
#define B001001 9
#define B0001001 9
#define B00001001 9
#define B1010 10
#define B01010 10
#define B001010 10
#define B0001010 10
#define B00001010 10
#define B1011 11
#define B01011 11
#define B001011 11
#define B0001011 11
#define B00001011 11
#define B1100 12
#define B01100 12
#define B001100 12
#define B0001100 12
#define B00001100 12
#define B1101 13
#define B01101 13
#define B001101 13
#define B0001101 13
#define B00001101 13
#define B1110 14
#define B01110 14
#define B001110 14
#define B0001110 14
#define B00001110 14
#define B1111 15
#define B01111 15
#define B001111 15
#define B0001111 15
#define B00001111 15
#define B10000 16
#define B010000 16
#define B0010000 16
#define B00010000 16
#define B10001 17
#define B010001 17
#define B0010001 17
#define B00010001 17
#define B10010 18
#define B010010 18
#define B0010010 18
#define B00010010 18
#define B10011 19
#define B010011 19
#define B0010011 19
#define B00010011 19
#define B10100 20
#define B010100 20
#define B0010100 20
#define B00010100 20
#define B10101 21
#define B010101 21
#define B0010101 21
#define B00010101 21
#define B10110 22
#define B010110 22
#define B0010110 22
#define B00010110 22
#define B10111 23
#define B010111 23
#define B0010111 23
#define B00010111 23
#define B11000 24
#define B011000 24
#define B0011000 24
#define B00011000 24
#define B11001 25
#define B011001 25
#define B0011001 25
#define B00011001 25
#define B11010 26
#define B011010 26
#define B0011010 26
#define B00011010 26
#define B11011 27
#define B011011 27
#define B0011011 27
#define B00011011 27
#define B11100 28
#define B011100 28
#define B0011100 28
#define B00011100 28
#define B11101 29
#define B011101 29
#define B0011101 29
#define B00011101 29
#define B11110 30
#define B011110 30
#define B0011110 30
#define B00011110 30
#define B11111 31
#define B011111 31
#define B0011111 31
#define B00011111 31
#define B100000 32
#define B0100000 32
#define B00100000 32
#define B100001 33
#define B0100001 33
#define B00100001 33
#define B100010 34
#define B0100010 34
#define B00100010 34
#define B100011 35
#define B0100011 35
#define B00100011 35
#define B100100 36
#define B0100100 36
#define B00100100 36
#define B100101 37
#define B0100101 37
#define B00100101 37
#define B100110 38
#define B0100110 38
#define B00100110 38
#define B100111 39
#define B0100111 39
#define B00100111 39
#define B101000 40
#define B0101000 40
#define B00101000 40
#define B101001 41
#define B0101001 41
#define B00101001 41
#define B101010 42
#define B0101010 42
#define B00101010 42
#define B101011 43
#define B0101011 43
#define B00101011 43
#define B101100 44
#define B0101100 44
#define B00101100 44
#define B101101 45
#define B0101101 45
#define B00101101 45
#define B101110 46
#define B0101110 46
#define B00101110 46
#define B101111 47
#define B0101111 47
#define B00101111 47
#define B110000 48
#define B0110000 48
#define B00110000 48
#define B110001 49
#define B0110001 49
#define B00110001 49
#define B110010 50
#define B0110010 50
#define B00110010 50
#define B110011 51
#define B0110011 51
#define B00110011 51
#define B110100 52
#define B0110100 52
#define B00110100 52
#define B110101 53
#define B0110101 53
#define B00110101 53
#define B110110 54
#define B0110110 54
#define B00110110 54
#define B110111 55
#define B0110111 55
#define B00110111 55
#define B111000 56
#define B0111000 56
#define B00111000 56
#define B111001 57
#define B0111001 57
#define B00111001 57
#define B111010 58
#define B0111010 58
#define B00111010 58
#define B111011 59
#define B0111011 59
#define B00111011 59
#define B111100 60
#define B0111100 60
#define B00111100 60
#define B111101 61
#define B0111101 61
#define B00111101 61
#define B111110 62
#define B0111110 62
#define B00111110 62
#define B111111 63
#define B0111111 63
#define B00111111 63
#define B1000000 64
#define B01000000 64
#define B1000001 65
#define B01000001 65
#define B1000010 66
#define B01000010 66
#define B1000011 67
#define B01000011 67
#define B1000100 68
#define B01000100 68
#define B1000101 69
#define B01000101 69
#define B1000110 70
#define B01000110 70
#define B1000111 71
#define B01000111 71
#define B1001000 72
#define B01001000 72
#define B1001001 73
#define B01001001 73
#define B1001010 74
#define B01001010 74
#define B1001011 75
#define B01001011 75
#define B1001100 76
#define B01001100 76
#define B1001101 77
#define B01001101 77
#define B1001110 78
#define B01001110 78
#define B1001111 79
#define B01001111 79
#define B1010000 80
#define B01010000 80
#define B1010001 81
#define B01010001 81
#define B1010010 82
#define B01010010 82
#define B1010011 83
#define B01010011 83
#define B1010100 84
#define B01010100 84
#define B1010101 85
#define B01010101 85
#define B1010110 86
#define B01010110 86
#define B1010111 87
#define B01010111 87
#define B1011000 88
#define B01011000 88
#define B1011001 89
#define B01011001 89
#define B1011010 90
#define B01011010 90
#define B1011011 91
#define B01011011 91
#define B1011100 92
#define B01011100 92
#define B1011101 93
#define B01011101 93
#define B1011110 94
#define B01011110 94
#define B1011111 95
#define B01011111 95
#define B1100000 96
#define B01100000 96
#define B1100001 97
#define B01100001 97
#define B1100010 98
#define B01100010 98
#define B1100011 99
#define B01100011 99
#define B1100100 100
#define B01100100 100
#define B1100101 101
#define B01100101 101
#define B1100110 102
#define B01100110 102
#define B1100111 103
#define B01100111 103
#define B1101000 104
#define B01101000 104
#define B1101001 105
#define B01101001 105
#define B1101010 106
#define B01101010 106
#define B1101011 107
#define B01101011 107
#define B1101100 108
#define B01101100 108
#define B1101101 109
#define B01101101 109
#define B1101110 110
#define B01101110 110
#define B1101111 111
#define B01101111 111
#define B1110000 112
#define B01110000 112
#define B1110001 113
#define B01110001 113
#define B1110010 114
#define B01110010 114
#define B1110011 115
#define B01110011 115
#define B1110100 116
#define B01110100 116
#define B1110101 117
#define B01110101 117
#define B1110110 118
#define B01110110 118
#define B1110111 119
#define B01110111 119
#define B1111000 120
#define B01111000 120
#define B1111001 121
#define B01111001 121
#define B1111010 122
#define B01111010 122
#define B1111011 123
#define B01111011 123
#define B1111100 124
#define B01111100 124
#define B1111101 125
#define B01111101 125
#define B1111110 126
#define B01111110 126
#define B1111111 127
#define B01111111 127
#define B10000000 128
#define B10000001 129
#define B10000010 130
#define B10000011 131
#define B10000100 132
#define B10000101 133
#define B10000110 134
#define B10000111 135
#define B10001000 136
#define B10001001 137
#define B10001010 138
#define B10001011 139
#define B10001100 140
#define B10001101 141
#define B10001110 142
#define B10001111 143
#define B10010000 144
#define B10010001 145
#define B10010010 146
#define B10010011 147
#define B10010100 148
#define B10010101 149
#define B10010110 150
#define B10010111 151
#define B10011000 152
#define B10011001 153
#define B10011010 154
#define B10011011 155
#define B10011100 156
#define B10011101 157
#define B10011110 158
#define B10011111 159
#define B10100000 160
#define B10100001 161
#define B10100010 162
#define B10100011 163
#define B10100100 164
#define B10100101 165
#define B10100110 166
#define B10100111 167
#define B10101000 168
#define B10101001 169
#define B10101010 170
#define B10101011 171
#define B10101100 172
#define B10101101 173
#define B10101110 174
#define B10101111 175
#define B10110000 176
#define B10110001 177
#define B10110010 178
#define B10110011 179
#define B10110100 180
#define B10110101 181
#define B10110110 182
#define B10110111 183
#define B10111000 184
#define B10111001 185
#define B10111010 186
#define B10111011 187
#define B10111100 188
#define B10111101 189
#define B10111110 190
#define B10111111 191
#define B11000000 192
#define B11000001 193
#define B11000010 194
#define B11000011 195
#define B11000100 196
#define B11000101 197
#define B11000110 198
#define B11000111 199
#define B11001000 200
#define B11001001 201
#define B11001010 202
#define B11001011 203
#define B11001100 204
#define B11001101 205
#define B11001110 206
#define B11001111 207
#define B11010000 208
#define B11010001 209
#define B11010010 210
#define B11010011 211
#define B11010100 212
#define B11010101 213
#define B11010110 214
#define B11010111 215
#define B11011000 216
#define B11011001 217
#define B11011010 218
#define B11011011 219
#define B11011100 220
#define B11011101 221
#define B11011110 222
#define B11011111 223
#define B11100000 224
#define B11100001 225
#define B11100010 226
#define B11100011 227
#define B11100100 228
#define B11100101 229
#define B11100110 230
#define B11100111 231
#define B11101000 232
#define B11101001 233
#define B11101010 234
#define B11101011 235
#define B11101100 236
#define B11101101 237
#define B11101110 238
#define B11101111 239
#define B11110000 240
#define B11110001 241
#define B11110010 242
#define B11110011 243
#define B11110100 244
#define B11110101 245
#define B11110110 246
#define B11110111 247
#define B11111000 248
#define B11111001 249
#define B11111010 250
#define B11111011 251
#define B11111100 252
#define B11111101 253
#define B11111110 254
#define B11111111 255
#endif

@ -0,0 +1,14 @@
#include <WProgram.h>
int main(void)
{
init();
setup();
for (;;)
loop();
return 0;
}

@ -0,0 +1,200 @@
/*
pins_arduino.c - pin definitions for the Arduino board
Part of Arduino / Wiring Lite
Copyright (c) 2005 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: pins_arduino.c 254 2007-04-20 23:17:38Z mellis $
*/
#include <avr/io.h>
#include "wiring_private.h"
#include "pins_arduino.h"
// On the Sanguino board, digital pins are also used
// for the analog output (software PWM). Analog input
// pins are a separate set.
// ATMEL ATMEGA644P / SANGUINO
//
// +---\/---+
// INT0 (D 0) PB0 1| |40 PA0 (AI 0 / D31)
// INT1 (D 1) PB1 2| |39 PA1 (AI 1 / D30)
// INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
// PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
// PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
// MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
// MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
// SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
// RST 9| |32 AREF
// VCC 10| |31 GND
// GND 11| |30 AVCC
// XTAL2 12| |29 PC7 (D 23)
// XTAL1 13| |28 PC6 (D 22)
// RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
// TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
// RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
// TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
// PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
// PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
// PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
// +--------+
//
#define PA 1
#define PB 2
#define PC 3
#define PD 4
// these arrays map port names (e.g. port B) to the
// appropriate addresses for various functions (e.g. reading
// and writing)
const uint8_t PROGMEM port_to_mode_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &DDRA,
(uint8_t) (uint16_t) &DDRB,
(uint8_t) (uint16_t) &DDRC,
(uint8_t) (uint16_t) &DDRD,
};
const uint8_t PROGMEM port_to_output_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &PORTA,
(uint8_t) (uint16_t) &PORTB,
(uint8_t) (uint16_t) &PORTC,
(uint8_t) (uint16_t) &PORTD,
};
const uint8_t PROGMEM port_to_input_PGM[] =
{
NOT_A_PORT,
(uint8_t) (uint16_t) &PINA,
(uint8_t) (uint16_t) &PINB,
(uint8_t) (uint16_t) &PINC,
(uint8_t) (uint16_t) &PIND,
};
const uint8_t PROGMEM digital_pin_to_port_PGM[] =
{
PB, /* 0 */
PB,
PB,
PB,
PB,
PB,
PB,
PB,
PD, /* 8 */
PD,
PD,
PD,
PD,
PD,
PD,
PD,
PC, /* 16 */
PC,
PC,
PC,
PC,
PC,
PC,
PC,
PA, /* 24 */
PA,
PA,
PA,
PA,
PA,
PA,
PA /* 31 */
};
const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] =
{
_BV(0), /* 0, port B */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 8, port D */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(0), /* 16, port C */
_BV(1),
_BV(2),
_BV(3),
_BV(4),
_BV(5),
_BV(6),
_BV(7),
_BV(7), /* 24, port A */
_BV(6),
_BV(5),
_BV(4),
_BV(3),
_BV(2),
_BV(1),
_BV(0)
};
const uint8_t PROGMEM digital_pin_to_timer_PGM[] =
{
NOT_ON_TIMER, /* 0 - PB0 */
NOT_ON_TIMER, /* 1 - PB1 */
NOT_ON_TIMER, /* 2 - PB2 */
TIMER0A, /* 3 - PB3 */
TIMER0B, /* 4 - PB4 */
NOT_ON_TIMER, /* 5 - PB5 */
NOT_ON_TIMER, /* 6 - PB6 */
NOT_ON_TIMER, /* 7 - PB7 */
NOT_ON_TIMER, /* 8 - PD0 */
NOT_ON_TIMER, /* 9 - PD1 */
NOT_ON_TIMER, /* 10 - PD2 */
NOT_ON_TIMER, /* 11 - PD3 */
TIMER1B, /* 12 - PD4 */
TIMER1A, /* 13 - PD5 */
TIMER2B, /* 14 - PD6 */
TIMER2A, /* 15 - PD7 */
NOT_ON_TIMER, /* 16 - PC0 */
NOT_ON_TIMER, /* 17 - PC1 */
NOT_ON_TIMER, /* 18 - PC2 */
NOT_ON_TIMER, /* 19 - PC3 */
NOT_ON_TIMER, /* 20 - PC4 */
NOT_ON_TIMER, /* 21 - PC5 */
NOT_ON_TIMER, /* 22 - PC6 */
NOT_ON_TIMER, /* 23 - PC7 */
NOT_ON_TIMER, /* 24 - PA0 */
NOT_ON_TIMER, /* 25 - PA1 */
NOT_ON_TIMER, /* 26 - PA2 */
NOT_ON_TIMER, /* 27 - PA3 */
NOT_ON_TIMER, /* 28 - PA4 */
NOT_ON_TIMER, /* 29 - PA5 */
NOT_ON_TIMER, /* 30 - PA6 */
NOT_ON_TIMER /* 31 - PA7 */
};

@ -0,0 +1,65 @@
/*
pins_arduino.h - Pin definition functions for Arduino
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2007 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 249 2007-02-03 16:52:51Z mellis $
*/
#ifndef Pins_Arduino_h
#define Pins_Arduino_h
#include <avr/pgmspace.h>
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER2 5
#define TIMER2A 6
#define TIMER2B 7
extern const uint8_t PROGMEM port_to_mode_PGM[];
extern const uint8_t PROGMEM port_to_input_PGM[];
extern const uint8_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
// Get the bit location within the hardware port of the given virtual pin.
// This comes from the pins_*.c file for the active board configuration.
//
// These perform slightly better as macros compared to inline functions
//
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( (uint16_t) pgm_read_byte( port_to_mode_PGM + (P))) )
#endif

@ -0,0 +1,289 @@
/*
wiring.c - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#include "wiring_private.h"
// the prescaler is set so that timer0 ticks every 64 clock cycles, and the
// the overflow handler is called every 256 ticks.
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256))
// the whole number of milliseconds per timer0 overflow
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000)
// the fractional number of milliseconds per timer0 overflow. we shift right
// by three to fit these numbers into a byte. (for the clock speeds we care
// about - 8 and 16 MHz - this doesn't lose precision.)
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3)
#define FRACT_MAX (1000 >> 3)
volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
SIGNAL(TIMER0_OVF_vect)
{
// copy these to local variables so they can be stored in registers
// (volatile variables must be read from memory on every access)
unsigned long m = timer0_millis;
unsigned char f = timer0_fract;
m += MILLIS_INC;
f += FRACT_INC;
if (f >= FRACT_MAX) {
f -= FRACT_MAX;
m += 1;
}
timer0_fract = f;
timer0_millis = m;
timer0_overflow_count++;
}
unsigned long millis()
{
unsigned long m;
uint8_t oldSREG = SREG;
// disable interrupts while we read timer0_millis or we might get an
// inconsistent value (e.g. in the middle of a write to timer0_millis)
cli();
m = timer0_millis;
SREG = oldSREG;
return m;
}
unsigned long micros() {
unsigned long m;
uint8_t oldSREG = SREG, t;
cli();
m = timer0_overflow_count;
#if defined(TCNT0)
t = TCNT0;
#elif defined(TCNT0L)
t = TCNT0L;
#else
#error TIMER 0 not defined
#endif
#ifdef TIFR0
if ((TIFR0 & _BV(TOV0)) && (t < 255))
m++;
#else
if ((TIFR & _BV(TOV0)) && (t < 255))
m++;
#endif
SREG = oldSREG;
return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond());
}
void delay(unsigned long ms)
{
uint16_t start = (uint16_t)micros();
while (ms > 0) {
if (((uint16_t)micros() - start) >= 1000) {
ms--;
start += 1000;
}
}
}
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return. the overhead of
// the function calls takes more than two microseconds. can't just
// subtract two, since us is unsigned; we'd overflow.
if (--us == 0)
return;
if (--us == 0)
return;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}
void init()
{
// this needs to be called before setup() or some functions won't
// work there
sei();
// on the ATmega168, timer 0 is also used for fast hardware pwm
// (using phase-correct PWM would mean that timer 0 overflowed half as often
// resulting in different millis() behavior on the ATmega8 and ATmega168)
#if defined(TCCR0A) && defined(WGM01)
sbi(TCCR0A, WGM01);
sbi(TCCR0A, WGM00);
#endif
// set timer 0 prescale factor to 64
#if defined(__AVR_ATmega128__)
// CPU specific: different values for the ATmega128
sbi(TCCR0, CS02);
#elif defined(TCCR0) && defined(CS01) && defined(CS00)
// this combination is for the standard atmega8
sbi(TCCR0, CS01);
sbi(TCCR0, CS00);
#elif defined(TCCR0B) && defined(CS01) && defined(CS00)
// this combination is for the standard 168/328/1280/2560
sbi(TCCR0B, CS01);
sbi(TCCR0B, CS00);
#elif defined(TCCR0A) && defined(CS01) && defined(CS00)
// this combination is for the __AVR_ATmega645__ series
sbi(TCCR0A, CS01);
sbi(TCCR0A, CS00);
#else
#error Timer 0 prescale factor 64 not set correctly
#endif
// enable timer 0 overflow interrupt
#if defined(TIMSK) && defined(TOIE0)
sbi(TIMSK, TOIE0);
#elif defined(TIMSK0) && defined(TOIE0)
sbi(TIMSK0, TOIE0);
#else
#error Timer 0 overflow interrupt not set correctly
#endif
// timers 1 and 2 are used for phase-correct hardware pwm
// this is better for motors as it ensures an even waveform
// note, however, that fast pwm mode can achieve a frequency of up
// 8 MHz (with a 16 MHz clock) at 50% duty cycle
TCCR1B = 0;
// set timer 1 prescale factor to 64
#if defined(TCCR1B) && defined(CS11) && defined(CS10)
sbi(TCCR1B, CS11);
sbi(TCCR1B, CS10);
#elif defined(TCCR1) && defined(CS11) && defined(CS10)
sbi(TCCR1, CS11);
sbi(TCCR1, CS10);
#endif
// put timer 1 in 8-bit phase correct pwm mode
#if defined(TCCR1A) && defined(WGM10)
sbi(TCCR1A, WGM10);
#elif defined(TCCR1)
#warning this needs to be finished
#endif
// set timer 2 prescale factor to 64
#if defined(TCCR2) && defined(CS22)
sbi(TCCR2, CS22);
#elif defined(TCCR2B) && defined(CS22)
sbi(TCCR2B, CS22);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
// configure timer 2 for phase correct pwm (8-bit)
#if defined(TCCR2) && defined(WGM20)
sbi(TCCR2, WGM20);
#elif defined(TCCR2A) && defined(WGM20)
sbi(TCCR2A, WGM20);
#else
#warning Timer 2 not finished (may not be present on this CPU)
#endif
#if defined(TCCR3B) && defined(CS31) && defined(WGM30)
sbi(TCCR3B, CS31); // set timer 3 prescale factor to 64
sbi(TCCR3B, CS30);
sbi(TCCR3A, WGM30); // put timer 3 in 8-bit phase correct pwm mode
#endif
#if defined(TCCR4B) && defined(CS41) && defined(WGM40)
sbi(TCCR4B, CS41); // set timer 4 prescale factor to 64
sbi(TCCR4B, CS40);
sbi(TCCR4A, WGM40); // put timer 4 in 8-bit phase correct pwm mode
#endif
#if defined(TCCR5B) && defined(CS51) && defined(WGM50)
sbi(TCCR5B, CS51); // set timer 5 prescale factor to 64
sbi(TCCR5B, CS50);
sbi(TCCR5A, WGM50); // put timer 5 in 8-bit phase correct pwm mode
#endif
#if defined(ADCSRA)
// set a2d prescale factor to 128
// 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
// XXX: this will not work properly for other clock speeds, and
// this code should use F_CPU to determine the prescale factor.
sbi(ADCSRA, ADPS2);
sbi(ADCSRA, ADPS1);
sbi(ADCSRA, ADPS0);
// enable a2d conversions
sbi(ADCSRA, ADEN);
#endif
// the bootloader connects pins 0 and 1 to the USART; disconnect them
// here so they can be used as normal digital i/o; they will be
// reconnected in Serial.begin()
#if defined(UCSRB)
UCSRB = 0;
#elif defined(UCSR0B)
UCSR0B = 0;
#endif
}

@ -0,0 +1,136 @@
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#ifndef Wiring_h
#define Wiring_h
#include <math.h>
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,259 @@
/*
wiring_analog.c - analog input and output
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 28 September 2010 by Mark Sproul
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
uint8_t analog_reference = DEFAULT;
void analogReference(uint8_t mode)
{
// can't actually set the register here because the default setting
// will connect AVCC and the AREF pin, which would cause a short if
// there's something connected to AREF.
analog_reference = mode;
}
int analogRead(uint8_t pin)
{
uint8_t low, high;
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#else
if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif
#if defined(ADCSRB) && defined(MUX5)
// the MUX5 bit of ADCSRB selects whether we're reading from channels
// 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
// set the analog reference (high two bits of ADMUX) and select the
// channel (low 4 bits). this also sets ADLAR (left-adjust result)
// to 0 (the default).
#if defined(ADMUX)
ADMUX = (analog_reference << 6) | (pin & 0x07);
#endif
// without a delay, we seem to read from the wrong channel
//delay(1);
#if defined(ADCSRA) && defined(ADCL)
// start the conversion
sbi(ADCSRA, ADSC);
// ADSC is cleared when the conversion finishes
while (bit_is_set(ADCSRA, ADSC));
// we have to read ADCL first; doing so locks both ADCL
// and ADCH until ADCH is read. reading ADCL second would
// cause the results of each conversion to be discarded,
// as ADCL and ADCH would be locked when it completed.
low = ADCL;
high = ADCH;
#else
// we dont have an ADC, return 0
low = 0;
high = 0;
#endif
// combine the two bytes
return (high << 8) | low;
}
// Right now, PWM output only works on the pins with
// hardware support. These are defined in the appropriate
// pins_*.c file. For the rest of the pins, we default
// to digital output.
void analogWrite(uint8_t pin, int val)
{
// We need to make sure the PWM output is enabled for those pins
// that support it, as we turn it off when digitally reading or
// writing with them. Also, make sure the pin is in output mode
// for consistenty with Wiring, which doesn't require a pinMode
// call for the analog output pins.
pinMode(pin, OUTPUT);
if (val == 0)
{
digitalWrite(pin, LOW);
}
else if (val == 255)
{
digitalWrite(pin, HIGH);
}
else
{
switch(digitalPinToTimer(pin))
{
// XXX fix needed for atmega8
#if defined(TCCR0) && defined(COM00) && !defined(__AVR_ATmega8__)
case TIMER0A:
// connect pwm to pin on timer 0
sbi(TCCR0, COM00);
OCR0 = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A:
// connect pwm to pin on timer 0, channel A
sbi(TCCR0A, COM0A1);
OCR0A = val; // set pwm duty
break;
#endif
#if defined(TCCR0A) && defined(COM0B1)
case TIMER0B:
// connect pwm to pin on timer 0, channel B
sbi(TCCR0A, COM0B1);
OCR0B = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A:
// connect pwm to pin on timer 1, channel A
sbi(TCCR1A, COM1A1);
OCR1A = val; // set pwm duty
break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B:
// connect pwm to pin on timer 1, channel B
sbi(TCCR1A, COM1B1);
OCR1B = val; // set pwm duty
break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2:
// connect pwm to pin on timer 2
sbi(TCCR2, COM21);
OCR2 = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A:
// connect pwm to pin on timer 2, channel A
sbi(TCCR2A, COM2A1);
OCR2A = val; // set pwm duty
break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B:
// connect pwm to pin on timer 2, channel B
sbi(TCCR2A, COM2B1);
OCR2B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A:
// connect pwm to pin on timer 3, channel A
sbi(TCCR3A, COM3A1);
OCR3A = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B:
// connect pwm to pin on timer 3, channel B
sbi(TCCR3A, COM3B1);
OCR3B = val; // set pwm duty
break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C:
// connect pwm to pin on timer 3, channel C
sbi(TCCR3A, COM3C1);
OCR3C = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4A1)
case TIMER4A:
// connect pwm to pin on timer 4, channel A
sbi(TCCR4A, COM4A1);
OCR4A = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B:
// connect pwm to pin on timer 4, channel B
sbi(TCCR4A, COM4B1);
OCR4B = val; // set pwm duty
break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C:
// connect pwm to pin on timer 4, channel C
sbi(TCCR4A, COM4C1);
OCR4C = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5A1)
case TIMER5A:
// connect pwm to pin on timer 5, channel A
sbi(TCCR5A, COM5A1);
OCR5A = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5B1)
case TIMER5B:
// connect pwm to pin on timer 5, channel B
sbi(TCCR5A, COM5B1);
OCR5B = val; // set pwm duty
break;
#endif
#if defined(TCCR5A) && defined(COM5C1)
case TIMER5C:
// connect pwm to pin on timer 5, channel C
sbi(TCCR5A, COM5C1);
OCR5C = val; // set pwm duty
break;
#endif
case NOT_ON_TIMER:
default:
if (val < 128) {
digitalWrite(pin, LOW);
} else {
digitalWrite(pin, HIGH);
}
}
}
}

@ -0,0 +1,166 @@
/*
wiring_digital.c - digital input and output functions
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
Modified 28 September 2010 by Mark Sproul
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
void pinMode(uint8_t pin, uint8_t mode)
{
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *reg;
if (port == NOT_A_PIN) return;
// JWS: can I let the optimizer do this?
reg = portModeRegister(port);
if (mode == INPUT) {
uint8_t oldSREG = SREG;
cli();
*reg &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*reg |= bit;
SREG = oldSREG;
}
}
// Forcing this inline keeps the callers from having to push their own stuff
// on the stack. It is a good performance win and only takes 1 more byte per
// user than calling. (It will take more bytes on the 168.)
//
// But shouldn't this be moved into pinMode? Seems silly to check and do on
// each digitalread or write.
//
// Mark Sproul:
// - Removed inline. Save 170 bytes on atmega1280
// - changed to a switch statment; added 32 bytes but much easier to read and maintain.
// - Added more #ifdefs, now compiles for atmega645
//
//static inline void turnOffPWM(uint8_t timer) __attribute__ ((always_inline));
//static inline void turnOffPWM(uint8_t timer)
static void turnOffPWM(uint8_t timer)
{
switch (timer)
{
#if defined(TCCR1A) && defined(COM1A1)
case TIMER1A: cbi(TCCR1A, COM1A1); break;
#endif
#if defined(TCCR1A) && defined(COM1B1)
case TIMER1B: cbi(TCCR1A, COM1B1); break;
#endif
#if defined(TCCR2) && defined(COM21)
case TIMER2: cbi(TCCR2, COM21); break;
#endif
#if defined(TCCR0A) && defined(COM0A1)
case TIMER0A: cbi(TCCR0A, COM0A1); break;
#endif
#if defined(TIMER0B) && defined(COM0B1)
case TIMER0B: cbi(TCCR0A, COM0B1); break;
#endif
#if defined(TCCR2A) && defined(COM2A1)
case TIMER2A: cbi(TCCR2A, COM2A1); break;
#endif
#if defined(TCCR2A) && defined(COM2B1)
case TIMER2B: cbi(TCCR2A, COM2B1); break;
#endif
#if defined(TCCR3A) && defined(COM3A1)
case TIMER3A: cbi(TCCR3A, COM3A1); break;
#endif
#if defined(TCCR3A) && defined(COM3B1)
case TIMER3B: cbi(TCCR3A, COM3B1); break;
#endif
#if defined(TCCR3A) && defined(COM3C1)
case TIMER3C: cbi(TCCR3A, COM3C1); break;
#endif
#if defined(TCCR4A) && defined(COM4A1)
case TIMER4A: cbi(TCCR4A, COM4A1); break;
#endif
#if defined(TCCR4A) && defined(COM4B1)
case TIMER4B: cbi(TCCR4A, COM4B1); break;
#endif
#if defined(TCCR4A) && defined(COM4C1)
case TIMER4C: cbi(TCCR4A, COM4C1); break;
#endif
#if defined(TCCR5A)
case TIMER5A: cbi(TCCR5A, COM5A1); break;
case TIMER5B: cbi(TCCR5A, COM5B1); break;
case TIMER5C: cbi(TCCR5A, COM5C1); break;
#endif
}
}
void digitalWrite(uint8_t pin, uint8_t val)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
volatile uint8_t *out;
if (port == NOT_A_PIN) return;
// If the pin that support PWM output, we need to turn it off
// before doing a digital write.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
out = portOutputRegister(port);
if (val == LOW) {
uint8_t oldSREG = SREG;
cli();
*out &= ~bit;
SREG = oldSREG;
} else {
uint8_t oldSREG = SREG;
cli();
*out |= bit;
SREG = oldSREG;
}
}
int digitalRead(uint8_t pin)
{
uint8_t timer = digitalPinToTimer(pin);
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
if (port == NOT_A_PIN) return LOW;
// If the pin that support PWM output, we need to turn it off
// before getting a digital reading.
if (timer != NOT_ON_TIMER) turnOffPWM(timer);
if (*portInputRegister(port) & bit) return HIGH;
return LOW;
}

@ -0,0 +1,68 @@
/*
wiring_private.h - Internal header file.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.h 239 2007-01-12 17:58:39Z mellis $
*/
#ifndef WiringPrivate_h
#define WiringPrivate_h
#include <math.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdarg.h>
#include "wiring.h"
#ifdef __cplusplus
extern "C"{
#endif
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define EXTERNAL_INT_0 0
#define EXTERNAL_INT_1 1
#define EXTERNAL_INT_2 2
#define EXTERNAL_INT_3 3
#define EXTERNAL_INT_4 4
#define EXTERNAL_INT_5 5
#define EXTERNAL_INT_6 6
#define EXTERNAL_INT_7 7
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define EXTERNAL_NUM_INTERRUPTS 8
#else
#define EXTERNAL_NUM_INTERRUPTS 2
#endif
typedef void (*voidFuncPtr)(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,69 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
#include "pins_arduino.h"
/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
* or LOW, the type of pulse to measure. Works on pulses from 2-3 microseconds
* to 3 minutes in length, but must be called at least a few dozen microseconds
* before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
// cache the port and bit of the pin in order to speed up the
// pulse width measuring loop and achieve finer resolution. calling
// digitalRead() instead yields much coarser resolution.
uint8_t bit = digitalPinToBitMask(pin);
uint8_t port = digitalPinToPort(pin);
uint8_t stateMask = (state ? bit : 0);
unsigned long width = 0; // keep initialization out of time critical area
// convert the timeout from microseconds to a number of times through
// the initial loop; it takes 16 clock cycles per iteration.
unsigned long numloops = 0;
unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
// wait for any previous pulse to end
while ((*portInputRegister(port) & bit) == stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to start
while ((*portInputRegister(port) & bit) != stateMask)
if (numloops++ == maxloops)
return 0;
// wait for the pulse to stop
while ((*portInputRegister(port) & bit) == stateMask) {
if (numloops++ == maxloops)
return 0;
width++;
}
// convert the reading to microseconds. The loop has been determined
// to be 20 clock cycles long and have about 16 clocks between the edge
// and the start of the loop. There will be some error introduced by
// the interrupt handlers.
return clockCyclesToMicroseconds(width * 21 + 16);
}

@ -0,0 +1,55 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id: wiring.c 248 2007-02-03 15:36:30Z mellis $
*/
#include "wiring_private.h"
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {
uint8_t value = 0;
uint8_t i;
for (i = 0; i < 8; ++i) {
digitalWrite(clockPin, HIGH);
if (bitOrder == LSBFIRST)
value |= digitalRead(dataPin) << i;
else
value |= digitalRead(dataPin) << (7 - i);
digitalWrite(clockPin, LOW);
}
return value;
}
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (bitOrder == LSBFIRST)
digitalWrite(dataPin, !!(val & (1 << i)));
else
digitalWrite(dataPin, !!(val & (1 << (7 - i))));
digitalWrite(clockPin, HIGH);
digitalWrite(clockPin, LOW);
}
}

@ -0,0 +1,20 @@
avrisp.name=AVR ISP
avrisp.communication=serial
avrisp.protocol=stk500v1
avrispmkii.name=AVRISP mkII
avrispmkii.communication=usb
avrispmkii.protocol=stk500v2
usbtinyisp.name=USBtinyISP
usbtinyisp.protocol=usbtiny
parallel.name=Parallel Programmer
parallel.protocol=dapa
parallel.force=true
# parallel.delay=200
arduinoisp.name=Arduino as ISP
arduinoisp.communication=serial
arduinoisp.protocol=stk500v1
arduinoisp.speed=19200

@ -0,0 +1,641 @@
/* 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 "Marlin.h"
#ifdef SDSUPPORT
#include "Sd2Card.h"
//------------------------------------------------------------------------------
#ifndef SOFTWARE_SPI
// functions for hardware SPI
//------------------------------------------------------------------------------
// make sure SPCR rate is in expected bits
#if (SPR0 != 0 || SPR1 != 1)
#error unexpected SPCR bits
#endif
/**
* Initialize hardware SPI
* Set SCK rate to F_CPU/pow(2, 1 + spiRate) for spiRate [0,6]
*/
static void spiInit(uint8_t spiRate) {
// See avr processor documentation
SPCR = (1 << SPE) | (1 << MSTR) | (spiRate >> 1);
SPSR = spiRate & 1 || spiRate == 6 ? 0 : 1 << SPI2X;
}
//------------------------------------------------------------------------------
/** SPI receive a byte */
static uint8_t spiRec() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF)));
return SPDR;
}
//------------------------------------------------------------------------------
/** SPI read data - only one call so force inline */
static inline __attribute__((always_inline))
void spiRead(uint8_t* buf, uint16_t nbyte) {
if (nbyte-- == 0) return;
SPDR = 0XFF;
for (uint16_t i = 0; i < nbyte; i++) {
while (!(SPSR & (1 << SPIF)));
buf[i] = SPDR;
SPDR = 0XFF;
}
while (!(SPSR & (1 << SPIF)));
buf[nbyte] = SPDR;
}
//------------------------------------------------------------------------------
/** SPI send a byte */
static void spiSend(uint8_t b) {
SPDR = b;
while (!(SPSR & (1 << SPIF)));
}
//------------------------------------------------------------------------------
/** SPI send block - only one call so force inline */
static inline __attribute__((always_inline))
void spiSendBlock(uint8_t token, const uint8_t* buf) {
SPDR = token;
for (uint16_t i = 0; i < 512; i += 2) {
while (!(SPSR & (1 << SPIF)));
SPDR = buf[i];
while (!(SPSR & (1 << SPIF)));
SPDR = buf[i + 1];
}
while (!(SPSR & (1 << SPIF)));
}
//------------------------------------------------------------------------------
#else // SOFTWARE_SPI
//------------------------------------------------------------------------------
/** nop to tune soft SPI timing */
#define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------
/** Soft SPI receive byte */
static uint8_t spiRec() {
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 read data */
static void spiRead(uint8_t* buf, uint16_t nbyte) {
for (uint16_t i = 0; i < nbyte; i++) {
buf[i] = spiRec();
}
}
//------------------------------------------------------------------------------
/** Soft SPI send byte */
static 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();
}
//------------------------------------------------------------------------------
/** Soft SPI send block */
void spiSendBlock(uint8_t token, const uint8_t* buf) {
spiSend(token);
for (uint16_t i = 0; i < 512; i++) {
spiSend(buf[i]);
}
}
#endif // SOFTWARE_SPI
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t Sd2Card::cardCommand(uint8_t cmd, uint32_t arg) {
// 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);
// skip stuff byte for stop read
if (cmd == CMD12) spiRec();
// 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() {
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() {
digitalWrite(chipSelectPin_, HIGH);
}
//------------------------------------------------------------------------------
void Sd2Card::chipSelectLow() {
#ifndef SOFTWARE_SPI
spiInit(spiRate_);
#endif // SOFTWARE_SPI
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.
*/
bool Sd2Card::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) goto fail;
// check for single block erase
if (!csd.v1.erase_blk_en) {
// erase size mask
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area
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.
*/
bool Sd2Card::eraseSingleBlockEnable() {
csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
}
//------------------------------------------------------------------------------
/**
* 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().
*/
bool Sd2Card::init(uint8_t sckRateID, uint8_t chipSelectPin) {
errorCode_ = 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);
// set SS high - may be chip select for another SPI device
#if SET_SPI_SS_HIGH
digitalWrite(SS_PIN, HIGH);
#endif // SET_SPI_SS_HIGH
// set SCK rate for initialization commands
spiRate_ = SPI_SD_INIT_RATE;
spiInit(spiRate_);
#endif // SOFTWARE_SPI
// must supply min of 74 clock cycles with CS high.
for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
// 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;
}
//------------------------------------------------------------------------------
/**
* Read a 512 byte block from an SD card.
*
* \param[in] blockNumber 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.
*/
bool Sd2Card::readBlock(uint32_t blockNumber, uint8_t* dst) {
// use address if not SDHC card
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD17, blockNumber)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
return readData(dst, 512);
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Read one data block in a multiple block read sequence
*
* \param[in] dst Pointer to the location for the data to be read.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool Sd2Card::readData(uint8_t *dst) {
chipSelectLow();
return readData(dst, 512);
}
//------------------------------------------------------------------------------
bool Sd2Card::readData(uint8_t* dst, uint16_t count) {
// wait for start block token
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;
}
// transfer data
spiRead(dst, count);
// discard CRC
spiRec();
spiRec();
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
bool 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;
}
return readData(dst, 16);
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** Start a read multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool Sd2Card::readStart(uint32_t blockNumber) {
if (type()!= SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (cardCommand(CMD18, blockNumber)) {
error(SD_CARD_ERROR_CMD18);
goto fail;
}
chipSelectHigh();
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** End a read multiple blocks sequence.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool Sd2Card::readStop() {
chipSelectLow();
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
goto fail;
}
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.
*/
bool Sd2Card::setSckRate(uint8_t sckRateID) {
if (sckRateID > 6) {
error(SD_CARD_ERROR_SCK_RATE);
return false;
}
spiRate_ = sckRateID;
return true;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
bool Sd2Card::waitNotBusy(uint16_t timeoutMillis) {
uint16_t t0 = millis();
while (spiRec() != 0XFF) {
if (((uint16_t)millis() - t0) >= timeoutMillis) goto fail;
}
return true;
fail:
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.
*/
bool Sd2Card::writeBlock(uint32_t blockNumber, const uint8_t* src) {
// 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
* \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.
*/
bool Sd2Card::writeData(const uint8_t* src) {
chipSelectLow();
// wait for previous write to finish
if (!waitNotBusy(SD_WRITE_TIMEOUT)) goto fail;
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) goto fail;
chipSelectHigh();
return true;
fail:
error(SD_CARD_ERROR_WRITE_MULTIPLE);
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
bool Sd2Card::writeData(uint8_t token, const uint8_t* src) {
spiSendBlock(token, src);
spiSend(0xff); // dummy crc
spiSend(0xff); // dummy crc
status_ = spiRec();
if ((status_ & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE);
goto fail;
}
return true;
fail:
chipSelectHigh();
return false;
}
//------------------------------------------------------------------------------
/** 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.
*/
bool Sd2Card::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
// 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;
}
chipSelectHigh();
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.
*/
bool Sd2Card::writeStop() {
chipSelectLow();
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;
}
#endif

@ -0,0 +1,241 @@
/* 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 "Marlin.h"
#ifdef SDSUPPORT
#ifndef Sd2Card_h
#define Sd2Card_h
/**
* \file
* \brief Sd2Card class for V2 SD/SDHC cards
*/
#include "SdFatConfig.h"
#include "Sd2PinMap.h"
#include "SdInfo.h"
//------------------------------------------------------------------------------
// SPI speed is F_CPU/2^(1 + index), 0 <= index <= 6
/** 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. See Sd2Card::setSckRate(). */
uint8_t const SPI_QUARTER_SPEED = 2;
/** Set SCK rate to F_CPU/16. See Sd2Card::setSckRate(). */
uint8_t const SPI_EIGHTH_SPEED = 3;
/** Set SCK rate to F_CPU/32. See Sd2Card::setSckRate(). */
uint8_t const SPI_SIXTEENTH_SPEED = 4;
//------------------------------------------------------------------------------
/** 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 (initialize card in SPI mode) */
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 CMD12 (write stop) */
uint8_t const SD_CARD_ERROR_CMD12 = 0X3;
/** card returned an error response for CMD17 (read block) */
uint8_t const SD_CARD_ERROR_CMD17 = 0X4;
/** card returned an error response for CMD18 (read multiple block) */
uint8_t const SD_CARD_ERROR_CMD18 = 0X5;
/** card returned an error response for CMD24 (write block) */
uint8_t const SD_CARD_ERROR_CMD24 = 0X6;
/** WRITE_MULTIPLE_BLOCKS command failed */
uint8_t const SD_CARD_ERROR_CMD25 = 0X7;
/** card returned an error response for CMD58 (read OCR) */
uint8_t const SD_CARD_ERROR_CMD58 = 0X8;
/** SET_WR_BLK_ERASE_COUNT failed */
uint8_t const SD_CARD_ERROR_ACMD23 = 0X9;
/** ACMD41 initialization process timeout */
uint8_t const SD_CARD_ERROR_ACMD41 = 0XA;
/** card returned a bad CSR version field */
uint8_t const SD_CARD_ERROR_BAD_CSD = 0XB;
/** erase block group command failed */
uint8_t const SD_CARD_ERROR_ERASE = 0XC;
/** card not capable of single block erase */
uint8_t const SD_CARD_ERROR_ERASE_SINGLE_BLOCK = 0XD;
/** Erase sequence timed out */
uint8_t const SD_CARD_ERROR_ERASE_TIMEOUT = 0XE;
/** card returned an error token instead of read data */
uint8_t const SD_CARD_ERROR_READ = 0XF;
/** read CID or CSD failed */
uint8_t const SD_CARD_ERROR_READ_REG = 0X10;
/** timeout while waiting for start of read data */
uint8_t const SD_CARD_ERROR_READ_TIMEOUT = 0X11;
/** card did not accept STOP_TRAN_TOKEN */
uint8_t const SD_CARD_ERROR_STOP_TRAN = 0X12;
/** card returned an error token as a response to a write operation */
uint8_t const SD_CARD_ERROR_WRITE = 0X13;
/** attempt to write protected block zero */
uint8_t const SD_CARD_ERROR_WRITE_BLOCK_ZERO = 0X14; // REMOVE - not used
/** card did not go ready for a multiple block write */
uint8_t const SD_CARD_ERROR_WRITE_MULTIPLE = 0X15;
/** card returned an error to a CMD13 status check after a write */
uint8_t const SD_CARD_ERROR_WRITE_PROGRAMMING = 0X16;
/** timeout occurred during write programming */
uint8_t const SD_CARD_ERROR_WRITE_TIMEOUT = 0X17;
/** incorrect rate selected */
uint8_t const SD_CARD_ERROR_SCK_RATE = 0X18;
/** init() not called */
uint8_t const SD_CARD_ERROR_INIT_NOT_CALLED = 0X19;
//------------------------------------------------------------------------------
// 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;
/**
* define SOFTWARE_SPI to use bit-bang SPI
*/
//------------------------------------------------------------------------------
#if MEGA_SOFT_SPI && (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__))
#define SOFTWARE_SPI
#elif USE_SOFTWARE_SPI
#define SOFTWARE_SPI
#endif // MEGA_SOFT_SPI
//------------------------------------------------------------------------------
// SPI pin definitions - do not edit here - change in SdFatConfig.h
//
#ifndef SOFTWARE_SPI
// hardware pin defs
/** 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;
#else // SOFTWARE_SPI
/** SPI chip select pin */
uint8_t const SD_CHIP_SELECT_PIN = SOFT_SPI_CS_PIN;
/** SPI Master Out Slave In pin */
uint8_t const SPI_MOSI_PIN = SOFT_SPI_MOSI_PIN;
/** SPI Master In Slave Out pin */
uint8_t const SPI_MISO_PIN = SOFT_SPI_MISO_PIN;
/** SPI Clock pin */
uint8_t const SPI_SCK_PIN = SOFT_SPI_SCK_PIN;
#endif // SOFTWARE_SPI
//------------------------------------------------------------------------------
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC flash memory cards.
*/
class Sd2Card {
public:
/** Construct an instance of Sd2Card. */
Sd2Card() : errorCode_(SD_CARD_ERROR_INIT_NOT_CALLED), type_(0) {}
uint32_t cardSize();
bool erase(uint32_t firstBlock, uint32_t lastBlock);
bool eraseSingleBlockEnable();
/**
* Set SD error code.
* \param[in] code value for error code.
*/
void error(uint8_t code) {errorCode_ = code;}
/**
* \return error code for last error. See Sd2Card.h for a list of error codes.
*/
int errorCode() const {return errorCode_;}
/** \return error data for last error. */
int errorData() 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).
*
* \return true for success or false for failure.
*/
bool init(uint8_t sckRateID = SPI_FULL_SPEED,
uint8_t chipSelectPin = SD_CHIP_SELECT_PIN);
bool readBlock(uint32_t block, uint8_t* dst);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
bool readData(uint8_t *dst);
bool readStart(uint32_t blockNumber);
bool readStop();
bool setSckRate(uint8_t sckRateID);
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
int type() const {return type_;}
bool writeBlock(uint32_t blockNumber, const uint8_t* src);
bool writeData(const uint8_t* src);
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
bool writeStop();
private:
//----------------------------------------------------------------------------
uint8_t chipSelectPin_;
uint8_t errorCode_;
uint8_t spiRate_;
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);
bool readData(uint8_t* dst, uint16_t count);
bool readRegister(uint8_t cmd, void* buf);
void chipSelectHigh();
void chipSelectLow();
void type(uint8_t value) {type_ = value;}
bool waitNotBusy(uint16_t timeoutMillis);
bool writeData(uint8_t token, const uint8_t* src);
};
#endif // Sd2Card_h
#endif

@ -0,0 +1,368 @@
/* 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.
#include "Marlin.h"
#ifdef SDSUPPORT
#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; // D1
uint8_t const SCL_PIN = 21; // D0
#undef MOSI_PIN
#undef MISO_PIN
// SPI port
uint8_t const SS_PIN = 53; // B0
uint8_t const MOSI_PIN = 51; // B2
uint8_t const MISO_PIN = 50; // B3
uint8_t const SCK_PIN = 52; // B1
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__)\
|| defined(__AVR_ATmega1284P__)
// Sanguino
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 17; // C1
uint8_t const SCL_PIN = 18; // C2
// SPI port
uint8_t const SS_PIN = 4; // B4
uint8_t const MOSI_PIN = 5; // B5
uint8_t const MISO_PIN = 6; // B6
uint8_t const SCK_PIN = 7; // B7
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; // D1
uint8_t const SCL_PIN = 5; // D0
// SPI port
uint8_t const SS_PIN = 0; // B0
uint8_t const MOSI_PIN = 2; // B2
uint8_t const MISO_PIN = 3; // B3
uint8_t const SCK_PIN = 1; // B1
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; // D1
uint8_t const SCL_PIN = 0; // D0
// SPI port
uint8_t const SS_PIN = 20; // B0
uint8_t const MOSI_PIN = 22; // B2
uint8_t const MISO_PIN = 23; // B3
uint8_t const SCK_PIN = 21; // B1
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
};
//------------------------------------------------------------------------------
#elif defined(__AVR_ATmega168__)\
||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos
// Two Wire (aka I2C) ports
uint8_t const SDA_PIN = 18; // C4
uint8_t const SCL_PIN = 19; // C5
// SPI port
uint8_t const SS_PIN = 10; // B2
uint8_t const MOSI_PIN = 11; // B3
uint8_t const MISO_PIN = 12; // B4
uint8_t const SCK_PIN = 13; // B5
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
};
#else // defined(__AVR_ATmega1280__)
#error unknown chip
#endif // defined(__AVR_ATmega1280__)
//------------------------------------------------------------------------------
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))
bool 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))
bool 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
#endif

@ -0,0 +1,1825 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#include "SdBaseFile.h"
//------------------------------------------------------------------------------
// pointer to cwd directory
SdBaseFile* SdBaseFile::cwd_ = 0;
// callback function for date/time
void (*SdBaseFile::dateTime_)(uint16_t* date, uint16_t* time) = 0;
//------------------------------------------------------------------------------
// add a cluster to a file
bool SdBaseFile::addCluster() {
if (!vol_->allocContiguous(1, &curCluster_)) goto fail;
// if first cluster of file link to directory entry
if (firstCluster_ == 0) {
firstCluster_ = curCluster_;
flags_ |= F_FILE_DIR_DIRTY;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// Add a cluster to a directory file and zero the cluster.
// return with first block of cluster in the cache
bool SdBaseFile::addDirCluster() {
uint32_t block;
// max folder size
if (fileSize_/sizeof(dir_t) >= 0XFFFF) goto fail;
if (!addCluster()) goto fail;
if (!vol_->cacheFlush()) goto fail;
block = vol_->clusterStartBlock(curCluster_);
// set cache to first block of cluster
vol_->cacheSetBlockNumber(block, true);
// zero first block of cluster
memset(vol_->cacheBuffer_.data, 0, 512);
// zero rest of cluster
for (uint8_t i = 1; i < vol_->blocksPerCluster_; i++) {
if (!vol_->writeBlock(block + i, vol_->cacheBuffer_.data)) goto fail;
}
// Increase directory file size by cluster size
fileSize_ += 512UL << vol_->clusterSizeShift_;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// cache a file's directory entry
// return pointer to cached entry or null for failure
dir_t* SdBaseFile::cacheDirEntry(uint8_t action) {
if (!vol_->cacheRawBlock(dirBlock_, action)) goto fail;
return vol_->cache()->dir + dirIndex_;
fail:
return 0;
}
//------------------------------------------------------------------------------
/** Close a file and force cached data and directory information
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include no file is open or an I/O error.
*/
bool SdBaseFile::close() {
bool rtn = sync();
type_ = FAT_FILE_TYPE_CLOSED;
return rtn;
}
//------------------------------------------------------------------------------
/** Check for contiguous file and return its raw block range.
*
* \param[out] bgnBlock the first block address for the file.
* \param[out] endBlock the last block address for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is not contiguous, file has zero length
* or an I/O error occurred.
*/
bool SdBaseFile::contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock) {
// error if no blocks
if (firstCluster_ == 0) goto fail;
for (uint32_t c = firstCluster_; ; c++) {
uint32_t next;
if (!vol_->fatGet(c, &next)) goto fail;
// check for contiguous
if (next != (c + 1)) {
// error if not end of chain
if (!vol_->isEOC(next)) goto fail;
*bgnBlock = vol_->clusterStartBlock(firstCluster_);
*endBlock = vol_->clusterStartBlock(c)
+ vol_->blocksPerCluster_ - 1;
return true;
}
}
fail:
return false;
}
//------------------------------------------------------------------------------
/** Create and open a new contiguous file of a specified size.
*
* \note This function only supports short DOS 8.3 names.
* See open() for more information.
*
* \param[in] dirFile The directory where the file will be created.
* \param[in] path A path with a valid DOS 8.3 file name.
* \param[in] size The desired file size.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include \a path contains
* an invalid DOS 8.3 file name, the FAT volume has not been initialized,
* a file is already open, the file already exists, the root
* directory is full or an I/O error.
*
*/
bool SdBaseFile::createContiguous(SdBaseFile* dirFile,
const char* path, uint32_t size) {
uint32_t count;
// don't allow zero length file
if (size == 0) goto fail;
if (!open(dirFile, path, O_CREAT | O_EXCL | O_RDWR)) goto fail;
// calculate number of clusters needed
count = ((size - 1) >> (vol_->clusterSizeShift_ + 9)) + 1;
// allocate clusters
if (!vol_->allocContiguous(count, &firstCluster_)) {
remove();
goto fail;
}
fileSize_ = size;
// insure sync() will update dir entry
flags_ |= F_FILE_DIR_DIRTY;
return sync();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Return a file's directory entry.
*
* \param[out] dir Location for return of the file's directory entry.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::dirEntry(dir_t* dir) {
dir_t* p;
// make sure fields on SD are correct
if (!sync()) goto fail;
// read entry
p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
if (!p) goto fail;
// copy to caller's struct
memcpy(dir, p, sizeof(dir_t));
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
/** Format the name field of \a dir into the 13 byte array
* \a name in standard 8.3 short name format.
*
* \param[in] dir The directory structure containing the name.
* \param[out] name A 13 byte char array for the formatted name.
*/
void SdBaseFile::dirName(const dir_t& dir, char* name) {
uint8_t j = 0;
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) name[j++] = '.';
name[j++] = dir.name[i];
}
name[j] = 0;
}
//------------------------------------------------------------------------------
/** Test for the existence of a file in a directory
*
* \param[in] name Name of the file to be tested for.
*
* The calling instance must be an open directory file.
*
* dirFile.exists("TOFIND.TXT") searches for "TOFIND.TXT" in the directory
* dirFile.
*
* \return true if the file exists else false.
*/
bool SdBaseFile::exists(const char* name) {
SdBaseFile file;
return file.open(this, name, O_READ);
}
//------------------------------------------------------------------------------
/**
* Get a string from a file.
*
* fgets() reads bytes from a file into the array pointed to by \a str, until
* \a num - 1 bytes are read, or a delimiter is read and transferred to \a str,
* or end-of-file is encountered. The string is then terminated
* with a null byte.
*
* fgets() deletes CR, '\\r', from the string. This insures only a '\\n'
* terminates the string for Windows text files which use CRLF for newline.
*
* \param[out] str Pointer to the array where the string is stored.
* \param[in] num Maximum number of characters to be read
* (including the final null byte). Usually the length
* of the array \a str is used.
* \param[in] delim Optional set of delimiters. The default is "\n".
*
* \return For success fgets() returns the length of the string in \a str.
* If no data is read, fgets() returns zero for EOF or -1 if an error occurred.
**/
int16_t SdBaseFile::fgets(char* str, int16_t num, char* delim) {
char ch;
int16_t n = 0;
int16_t r = -1;
while ((n + 1) < num && (r = read(&ch, 1)) == 1) {
// delete CR
if (ch == '\r') continue;
str[n++] = ch;
if (!delim) {
if (ch == '\n') break;
} else {
if (strchr(delim, ch)) break;
}
}
if (r < 0) {
// read error
return -1;
}
str[n] = '\0';
return n;
}
//------------------------------------------------------------------------------
/** Get a file's name
*
* \param[out] name An array of 13 characters for the file's name.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::getFilename(char* name) {
if (!isOpen()) return false;
if (isRoot()) {
name[0] = '/';
name[1] = '\0';
return true;
}
// cache entry
dir_t* p = cacheDirEntry(SdVolume::CACHE_FOR_READ);
if (!p) return false;
// format name
dirName(*p, name);
return true;
}
//------------------------------------------------------------------------------
void SdBaseFile::getpos(fpos_t* pos) {
pos->position = curPosition_;
pos->cluster = curCluster_;
}
//------------------------------------------------------------------------------
/** List directory contents.
*
* \param[in] pr Print stream for list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \param[in] indent Amount of space before file name. Used for recursive
* list to indicate subdirectory level.
*/
void SdBaseFile::ls(uint8_t flags, uint8_t indent) {
rewind();
int8_t status;
while ((status = lsPrintNext( flags, indent))) {
if (status > 1 && (flags & LS_R)) {
uint16_t index = curPosition()/32 - 1;
SdBaseFile s;
if (s.open(this, index, O_READ)) s.ls( flags, indent + 2);
seekSet(32 * (index + 1));
}
}
}
//------------------------------------------------------------------------------
// saves 32 bytes on stack for ls recursion
// return 0 - EOF, 1 - normal file, or 2 - directory
int8_t SdBaseFile::lsPrintNext( uint8_t flags, uint8_t indent) {
dir_t dir;
uint8_t w = 0;
while (1) {
if (read(&dir, sizeof(dir)) != sizeof(dir)) return 0;
if (dir.name[0] == DIR_NAME_FREE) return 0;
// skip deleted entry and entries for . and ..
if (dir.name[0] != DIR_NAME_DELETED && dir.name[0] != '.'
&& DIR_IS_FILE_OR_SUBDIR(&dir)) break;
}
// indent for dir level
for (uint8_t i = 0; i < indent; i++) MYSERIAL.write(' ');
// print name
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) {
MYSERIAL.write('.');
w++;
}
MYSERIAL.write(dir.name[i]);
w++;
}
if (DIR_IS_SUBDIR(&dir)) {
MYSERIAL.write('/');
w++;
}
if (flags & (LS_DATE | LS_SIZE)) {
while (w++ < 14) MYSERIAL.write(' ');
}
// print modify date/time if requested
if (flags & LS_DATE) {
MYSERIAL.write(' ');
printFatDate( dir.lastWriteDate);
MYSERIAL.write(' ');
printFatTime( dir.lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(&dir) && (flags & LS_SIZE)) {
MYSERIAL.write(' ');
MYSERIAL.print(dir.fileSize);
}
MYSERIAL.println();
return DIR_IS_FILE(&dir) ? 1 : 2;
}
//------------------------------------------------------------------------------
// format directory name field from a 8.3 name string
bool SdBaseFile::make83Name(const char* str, uint8_t* name, const char** ptr) {
uint8_t c;
uint8_t n = 7; // max index for part before dot
uint8_t i = 0;
// blank fill name and extension
while (i < 11) name[i++] = ' ';
i = 0;
while (*str != '\0' && *str != '/') {
c = *str++;
if (c == '.') {
if (n == 10) goto fail; // only one dot allowed
n = 10; // max index for full 8.3 name
i = 8; // place for extension
} else {
// illegal FAT characters
PGM_P p = PSTR("|<>^+=?/[];,*\"\\");
uint8_t b;
while ((b = pgm_read_byte(p++))) if (b == c) goto fail;
// check size and only allow ASCII printable characters
if (i > n || c < 0X21 || c > 0X7E)goto fail;
// only upper case allowed in 8.3 names - convert lower to upper
name[i++] = c < 'a' || c > 'z' ? c : c + ('A' - 'a');
}
}
*ptr = str;
// must have a file name, extension is optional
return name[0] != ' ';
fail:
return false;
}
//------------------------------------------------------------------------------
/** Make a new directory.
*
* \param[in] parent An open SdFat instance for the directory that will contain
* the new directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the new directory.
*
* \param[in] pFlag Create missing parent directories if true.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this file is already open, \a parent is not a
* directory, \a path is invalid or already exists in \a parent.
*/
bool SdBaseFile::mkdir(SdBaseFile* parent, const char* path, bool pFlag) {
uint8_t dname[11];
SdBaseFile dir1, dir2;
SdBaseFile* sub = &dir1;
SdBaseFile* start = parent;
if (!parent || isOpen()) goto fail;
if (*path == '/') {
while (*path == '/') path++;
if (!parent->isRoot()) {
if (!dir2.openRoot(parent->vol_)) goto fail;
parent = &dir2;
}
}
while (1) {
if (!make83Name(path, dname, &path)) goto fail;
while (*path == '/') path++;
if (!*path) break;
if (!sub->open(parent, dname, O_READ)) {
if (!pFlag || !sub->mkdir(parent, dname)) {
goto fail;
}
}
if (parent != start) parent->close();
parent = sub;
sub = parent != &dir1 ? &dir1 : &dir2;
}
return mkdir(parent, dname);
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdBaseFile::mkdir(SdBaseFile* parent, const uint8_t dname[11]) {
uint32_t block;
dir_t d;
dir_t* p;
if (!parent->isDir()) goto fail;
// create a normal file
if (!open(parent, dname, O_CREAT | O_EXCL | O_RDWR)) goto fail;
// convert file to directory
flags_ = O_READ;
type_ = FAT_FILE_TYPE_SUBDIR;
// allocate and zero first cluster
if (!addDirCluster())goto fail;
// force entry to SD
if (!sync()) goto fail;
// cache entry - should already be in cache due to sync() call
p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!p) goto fail;
// change directory entry attribute
p->attributes = DIR_ATT_DIRECTORY;
// make entry for '.'
memcpy(&d, p, sizeof(d));
d.name[0] = '.';
for (uint8_t i = 1; i < 11; i++) d.name[i] = ' ';
// cache block for '.' and '..'
block = vol_->clusterStartBlock(firstCluster_);
if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail;
// copy '.' to block
memcpy(&vol_->cache()->dir[0], &d, sizeof(d));
// make entry for '..'
d.name[1] = '.';
if (parent->isRoot()) {
d.firstClusterLow = 0;
d.firstClusterHigh = 0;
} else {
d.firstClusterLow = parent->firstCluster_ & 0XFFFF;
d.firstClusterHigh = parent->firstCluster_ >> 16;
}
// copy '..' to block
memcpy(&vol_->cache()->dir[1], &d, sizeof(d));
// write first block
return vol_->cacheFlush();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Open a file in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::open(const char* path, uint8_t oflag) {
return open(cwd_, path, oflag);
}
//------------------------------------------------------------------------------
/** Open a file or directory by name.
*
* \param[in] dirFile An open SdFat instance for the directory containing the
* file to be opened.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags from the following list
*
* O_READ - Open for reading.
*
* O_RDONLY - Same as O_READ.
*
* O_WRITE - Open for writing.
*
* O_WRONLY - Same as O_WRITE.
*
* O_RDWR - Open for reading and writing.
*
* O_APPEND - If set, the file offset shall be set to the end of the
* file prior to each write.
*
* O_AT_END - Set the initial position at the end of the file.
*
* O_CREAT - If the file exists, this flag has no effect except as noted
* under O_EXCL below. Otherwise, the file shall be created
*
* O_EXCL - If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
*
* O_SYNC - Call sync() after each write. This flag should not be used with
* write(uint8_t), write_P(PGM_P), writeln_P(PGM_P), or the Arduino Print class.
* These functions do character at a time writes so sync() will be called
* after each byte.
*
* O_TRUNC - If the file exists and is a regular file, and the file is
* successfully opened and is not read only, its length shall be truncated to 0.
*
* WARNING: A given file must not be opened by more than one SdBaseFile object
* of file corruption may occur.
*
* \note Directory files must be opened read only. Write and truncation is
* not allowed for directory files.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include this file is already open, \a dirFile is not
* a directory, \a path is invalid, the file does not exist
* or can't be opened in the access mode specified by oflag.
*/
bool SdBaseFile::open(SdBaseFile* dirFile, const char* path, uint8_t oflag) {
uint8_t dname[11];
SdBaseFile dir1, dir2;
SdBaseFile *parent = dirFile;
SdBaseFile *sub = &dir1;
if (!dirFile) goto fail;
// error if already open
if (isOpen()) goto fail;
if (*path == '/') {
while (*path == '/') path++;
if (!dirFile->isRoot()) {
if (!dir2.openRoot(dirFile->vol_)) goto fail;
parent = &dir2;
}
}
while (1) {
if (!make83Name(path, dname, &path)) goto fail;
while (*path == '/') path++;
if (!*path) break;
if (!sub->open(parent, dname, O_READ)) goto fail;
if (parent != dirFile) parent->close();
parent = sub;
sub = parent != &dir1 ? &dir1 : &dir2;
}
return open(parent, dname, oflag);
fail:
return false;
}
//------------------------------------------------------------------------------
// open with filename in dname
bool SdBaseFile::open(SdBaseFile* dirFile,
const uint8_t dname[11], uint8_t oflag) {
bool emptyFound = false;
bool fileFound = false;
uint8_t index;
dir_t* p;
vol_ = dirFile->vol_;
dirFile->rewind();
// search for file
while (dirFile->curPosition_ < dirFile->fileSize_) {
index = 0XF & (dirFile->curPosition_ >> 5);
p = dirFile->readDirCache();
if (!p) goto fail;
if (p->name[0] == DIR_NAME_FREE || p->name[0] == DIR_NAME_DELETED) {
// remember first empty slot
if (!emptyFound) {
dirBlock_ = dirFile->vol_->cacheBlockNumber();
dirIndex_ = index;
emptyFound = true;
}
// done if no entries follow
if (p->name[0] == DIR_NAME_FREE) break;
} else if (!memcmp(dname, p->name, 11)) {
fileFound = true;
break;
}
}
if (fileFound) {
// don't open existing file if O_EXCL
if (oflag & O_EXCL) goto fail;
} else {
// don't create unless O_CREAT and O_WRITE
if (!(oflag & O_CREAT) || !(oflag & O_WRITE)) goto fail;
if (emptyFound) {
index = dirIndex_;
p = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!p) goto fail;
} else {
if (dirFile->type_ == FAT_FILE_TYPE_ROOT_FIXED) goto fail;
// add and zero cluster for dirFile - first cluster is in cache for write
if (!dirFile->addDirCluster()) goto fail;
// use first entry in cluster
p = dirFile->vol_->cache()->dir;
index = 0;
}
// initialize as empty file
memset(p, 0, sizeof(dir_t));
memcpy(p->name, dname, 11);
// set timestamps
if (dateTime_) {
// call user date/time function
dateTime_(&p->creationDate, &p->creationTime);
} else {
// use default date/time
p->creationDate = FAT_DEFAULT_DATE;
p->creationTime = FAT_DEFAULT_TIME;
}
p->lastAccessDate = p->creationDate;
p->lastWriteDate = p->creationDate;
p->lastWriteTime = p->creationTime;
// write entry to SD
if (!dirFile->vol_->cacheFlush()) goto fail;
}
// open entry in cache
return openCachedEntry(index, oflag);
fail:
return false;
}
//------------------------------------------------------------------------------
/** Open a file by index.
*
* \param[in] dirFile An open SdFat instance for the directory.
*
* \param[in] index The \a index of the directory entry for the file to be
* opened. The value for \a index is (directory file position)/32.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
*
* See open() by path for definition of flags.
* \return true for success or false for failure.
*/
bool SdBaseFile::open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag) {
dir_t* p;
vol_ = dirFile->vol_;
// error if already open
if (isOpen() || !dirFile) goto fail;
// don't open existing file if O_EXCL - user call error
if (oflag & O_EXCL) goto fail;
// seek to location of entry
if (!dirFile->seekSet(32 * index)) goto fail;
// read entry into cache
p = dirFile->readDirCache();
if (!p) goto fail;
// error if empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_FREE ||
p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
goto fail;
}
// open cached entry
return openCachedEntry(index & 0XF, oflag);
fail:
return false;
}
//------------------------------------------------------------------------------
// open a cached directory entry. Assumes vol_ is initialized
bool SdBaseFile::openCachedEntry(uint8_t dirIndex, uint8_t oflag) {
// location of entry in cache
dir_t* p = &vol_->cache()->dir[dirIndex];
// write or truncate is an error for a directory or read-only file
if (p->attributes & (DIR_ATT_READ_ONLY | DIR_ATT_DIRECTORY)) {
if (oflag & (O_WRITE | O_TRUNC)) goto fail;
}
// remember location of directory entry on SD
dirBlock_ = vol_->cacheBlockNumber();
dirIndex_ = dirIndex;
// copy first cluster number for directory fields
firstCluster_ = (uint32_t)p->firstClusterHigh << 16;
firstCluster_ |= p->firstClusterLow;
// make sure it is a normal file or subdirectory
if (DIR_IS_FILE(p)) {
fileSize_ = p->fileSize;
type_ = FAT_FILE_TYPE_NORMAL;
} else if (DIR_IS_SUBDIR(p)) {
if (!vol_->chainSize(firstCluster_, &fileSize_)) goto fail;
type_ = FAT_FILE_TYPE_SUBDIR;
} else {
goto fail;
}
// save open flags for read/write
flags_ = oflag & F_OFLAG;
// set to start of file
curCluster_ = 0;
curPosition_ = 0;
if ((oflag & O_TRUNC) && !truncate(0)) return false;
return oflag & O_AT_END ? seekEnd(0) : true;
fail:
type_ = FAT_FILE_TYPE_CLOSED;
return false;
}
//------------------------------------------------------------------------------
/** Open the next file or subdirectory in a directory.
*
* \param[in] dirFile An open SdFat instance for the directory containing the
* file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
*
* See open() by path for definition of flags.
* \return true for success or false for failure.
*/
bool SdBaseFile::openNext(SdBaseFile* dirFile, uint8_t oflag) {
dir_t* p;
uint8_t index;
if (!dirFile) goto fail;
// error if already open
if (isOpen()) goto fail;
vol_ = dirFile->vol_;
while (1) {
index = 0XF & (dirFile->curPosition_ >> 5);
// read entry into cache
p = dirFile->readDirCache();
if (!p) goto fail;
// done if last entry
if (p->name[0] == DIR_NAME_FREE) goto fail;
// skip empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') {
continue;
}
// must be file or dir
if (DIR_IS_FILE_OR_SUBDIR(p)) {
return openCachedEntry(index, oflag);
}
}
fail:
return false;
}
//------------------------------------------------------------------------------
/** Open a directory's parent directory.
*
* \param[in] dir Parent of this directory will be opened. Must not be root.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::openParent(SdBaseFile* dir) {
dir_t entry;
dir_t* p;
SdBaseFile file;
uint32_t c;
uint32_t cluster;
uint32_t lbn;
// error if already open or dir is root or dir is not a directory
if (isOpen() || !dir || dir->isRoot() || !dir->isDir()) goto fail;
vol_ = dir->vol_;
// position to '..'
if (!dir->seekSet(32)) goto fail;
// read '..' entry
if (dir->read(&entry, sizeof(entry)) != 32) goto fail;
// verify it is '..'
if (entry.name[0] != '.' || entry.name[1] != '.') goto fail;
// start cluster for '..'
cluster = entry.firstClusterLow;
cluster |= (uint32_t)entry.firstClusterHigh << 16;
if (cluster == 0) return openRoot(vol_);
// start block for '..'
lbn = vol_->clusterStartBlock(cluster);
// first block of parent dir
if (!vol_->cacheRawBlock(lbn, SdVolume::CACHE_FOR_READ)) {
goto fail;
}
p = &vol_->cacheBuffer_.dir[1];
// verify name for '../..'
if (p->name[0] != '.' || p->name[1] != '.') goto fail;
// '..' is pointer to first cluster of parent. open '../..' to find parent
if (p->firstClusterHigh == 0 && p->firstClusterLow == 0) {
if (!file.openRoot(dir->volume())) goto fail;
} else {
if (!file.openCachedEntry(1, O_READ)) goto fail;
}
// search for parent in '../..'
do {
if (file.readDir(&entry, NULL) != 32) goto fail;
c = entry.firstClusterLow;
c |= (uint32_t)entry.firstClusterHigh << 16;
} while (c != cluster);
// open parent
return open(&file, file.curPosition()/32 - 1, O_READ);
fail:
return false;
}
//------------------------------------------------------------------------------
/** Open a volume's root directory.
*
* \param[in] vol The FAT volume containing the root directory to be opened.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is already open, the FAT volume has
* not been initialized or it a FAT12 volume.
*/
bool SdBaseFile::openRoot(SdVolume* vol) {
// error if file is already open
if (isOpen()) goto fail;
if (vol->fatType() == 16 || (FAT12_SUPPORT && vol->fatType() == 12)) {
type_ = FAT_FILE_TYPE_ROOT_FIXED;
firstCluster_ = 0;
fileSize_ = 32 * vol->rootDirEntryCount();
} else if (vol->fatType() == 32) {
type_ = FAT_FILE_TYPE_ROOT32;
firstCluster_ = vol->rootDirStart();
if (!vol->chainSize(firstCluster_, &fileSize_)) goto fail;
} else {
// volume is not initialized, invalid, or FAT12 without support
return false;
}
vol_ = vol;
// read only
flags_ = O_READ;
// set to start of file
curCluster_ = 0;
curPosition_ = 0;
// root has no directory entry
dirBlock_ = 0;
dirIndex_ = 0;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int SdBaseFile::peek() {
fpos_t pos;
getpos(&pos);
int c = read();
if (c >= 0) setpos(&pos);
return c;
}
//------------------------------------------------------------------------------
/** %Print the name field of a directory entry in 8.3 format.
* \param[in] pr Print stream for output.
* \param[in] dir The directory structure containing the name.
* \param[in] width Blank fill name if length is less than \a width.
* \param[in] printSlash Print '/' after directory names if true.
*/
void SdBaseFile::printDirName(const dir_t& dir,
uint8_t width, bool printSlash) {
uint8_t w = 0;
for (uint8_t i = 0; i < 11; i++) {
if (dir.name[i] == ' ')continue;
if (i == 8) {
MYSERIAL.write('.');
w++;
}
MYSERIAL.write(dir.name[i]);
w++;
}
if (DIR_IS_SUBDIR(&dir) && printSlash) {
MYSERIAL.write('/');
w++;
}
while (w < width) {
MYSERIAL.write(' ');
w++;
}
}
//------------------------------------------------------------------------------
// print uint8_t with width 2
static void print2u( uint8_t v) {
if (v < 10) MYSERIAL.write('0');
MYSERIAL.print(v, DEC);
}
//------------------------------------------------------------------------------
/** %Print a directory date field to Serial.
*
* Format is yyyy-mm-dd.
*
* \param[in] fatDate The date field from a directory entry.
*/
//------------------------------------------------------------------------------
/** %Print a directory date field.
*
* Format is yyyy-mm-dd.
*
* \param[in] pr Print stream for output.
* \param[in] fatDate The date field from a directory entry.
*/
void SdBaseFile::printFatDate(uint16_t fatDate) {
MYSERIAL.print(FAT_YEAR(fatDate));
MYSERIAL.write('-');
print2u( FAT_MONTH(fatDate));
MYSERIAL.write('-');
print2u( FAT_DAY(fatDate));
}
//------------------------------------------------------------------------------
/** %Print a directory time field.
*
* Format is hh:mm:ss.
*
* \param[in] pr Print stream for output.
* \param[in] fatTime The time field from a directory entry.
*/
void SdBaseFile::printFatTime( uint16_t fatTime) {
print2u( FAT_HOUR(fatTime));
MYSERIAL.write(':');
print2u( FAT_MINUTE(fatTime));
MYSERIAL.write(':');
print2u( FAT_SECOND(fatTime));
}
//------------------------------------------------------------------------------
/** Print a file's name to Serial
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::printName() {
char name[13];
if (!getFilename(name)) return false;
MYSERIAL.print(name);
return true;
}
//------------------------------------------------------------------------------
/** 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 SdBaseFile::read() {
uint8_t b;
return read(&b, 1) == 1 ? b : -1;
}
//------------------------------------------------------------------------------
/** Read data from a file starting at the current position.
*
* \param[out] buf Pointer to the location that will receive the data.
*
* \param[in] nbyte Maximum number of bytes to read.
*
* \return For success read() returns the number of bytes read.
* A value less than \a nbyte, including zero, will be returned
* if end of file is reached.
* If an error occurs, read() returns -1. Possible errors include
* read() called before a file has been opened, corrupt file system
* or an I/O error occurred.
*/
int16_t SdBaseFile::read(void* buf, uint16_t nbyte) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
uint16_t offset;
uint16_t toRead;
uint32_t block; // raw device block number
// error if not open or write only
if (!isOpen() || !(flags_ & O_READ)) goto fail;
// max bytes left in file
if (nbyte >= (fileSize_ - curPosition_)) {
nbyte = fileSize_ - curPosition_;
}
// amount left to read
toRead = nbyte;
while (toRead > 0) {
offset = curPosition_ & 0X1FF; // offset in block
if (type_ == FAT_FILE_TYPE_ROOT_FIXED) {
block = vol_->rootDirStart() + (curPosition_ >> 9);
} else {
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
if (offset == 0 && blockOfCluster == 0) {
// start of new cluster
if (curPosition_ == 0) {
// use first cluster in file
curCluster_ = firstCluster_;
} else {
// get next cluster from FAT
if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail;
}
}
block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
}
uint16_t n = toRead;
// amount to be read from current block
if (n > (512 - offset)) n = 512 - offset;
// no buffering needed if n == 512
if (n == 512 && block != vol_->cacheBlockNumber()) {
if (!vol_->readBlock(block, dst)) goto fail;
} else {
// read block to cache and copy data to caller
if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail;
uint8_t* src = vol_->cache()->data + offset;
memcpy(dst, src, n);
}
dst += n;
curPosition_ += n;
toRead -= n;
}
return nbyte;
fail:
return -1;
}
//------------------------------------------------------------------------------
/** Read the next directory entry from a directory file.
*
* \param[out] dir The dir_t struct that will receive the data.
*
* \return For success readDir() returns the number of bytes read.
* A value of zero will be returned if end of file is reached.
* If an error occurs, readDir() returns -1. Possible errors include
* readDir() called before a directory has been opened, this is not
* a directory file or an I/O error occurred.
*/
int8_t SdBaseFile::readDir(dir_t* dir, char* longFilename) {
int16_t n;
// if not a directory file or miss-positioned return an error
if (!isDir() || (0X1F & curPosition_)) return -1;
//If we have a longFilename buffer, mark it as invalid. If we find a long filename it will be filled automaticly.
if (longFilename != NULL)
{
longFilename[0] = '\0';
}
while (1) {
n = read(dir, sizeof(dir_t));
if (n != sizeof(dir_t)) return n == 0 ? 0 : -1;
// last entry if DIR_NAME_FREE
if (dir->name[0] == DIR_NAME_FREE) return 0;
// skip empty entries and entry for . and ..
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') continue;
//Fill the long filename if we have a long filename entry,
// long filename entries are stored before the actual filename.
if (DIR_IS_LONG_NAME(dir) && longFilename != NULL)
{
vfat_t *VFAT = (vfat_t*)dir;
//Sanity check the VFAT entry. The first cluster is always set to zero. And th esequence number should be higher then 0
if (VFAT->firstClusterLow == 0 && (VFAT->sequenceNumber & 0x1F) > 0 && (VFAT->sequenceNumber & 0x1F) <= MAX_VFAT_ENTRIES)
{
//TODO: Store the filename checksum to verify if a none-long filename aware system modified the file table.
n = ((VFAT->sequenceNumber & 0x1F) - 1) * 13;
longFilename[n+0] = VFAT->name1[0];
longFilename[n+1] = VFAT->name1[1];
longFilename[n+2] = VFAT->name1[2];
longFilename[n+3] = VFAT->name1[3];
longFilename[n+4] = VFAT->name1[4];
longFilename[n+5] = VFAT->name2[0];
longFilename[n+6] = VFAT->name2[1];
longFilename[n+7] = VFAT->name2[2];
longFilename[n+8] = VFAT->name2[3];
longFilename[n+9] = VFAT->name2[4];
longFilename[n+10] = VFAT->name2[5];
longFilename[n+11] = VFAT->name3[0];
longFilename[n+12] = VFAT->name3[1];
//If this VFAT entry is the last one, add a NUL terminator at the end of the string
if (VFAT->sequenceNumber & 0x40)
longFilename[n+13] = '\0';
}
}
// return if normal file or subdirectory
if (DIR_IS_FILE_OR_SUBDIR(dir)) return n;
}
}
//------------------------------------------------------------------------------
// Read next directory entry into the cache
// Assumes file is correctly positioned
dir_t* SdBaseFile::readDirCache() {
uint8_t i;
// error if not directory
if (!isDir()) goto fail;
// index of entry in cache
i = (curPosition_ >> 5) & 0XF;
// use read to locate and cache block
if (read() < 0) goto fail;
// advance to next entry
curPosition_ += 31;
// return pointer to entry
return vol_->cache()->dir + i;
fail:
return 0;
}
//------------------------------------------------------------------------------
/** Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \note This function should not be used to delete the 8.3 version of a
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file read-only, is a directory,
* or an I/O error occurred.
*/
bool SdBaseFile::remove() {
dir_t* d;
// free any clusters - will fail if read-only or directory
if (!truncate(0)) goto fail;
// cache directory entry
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
// mark entry deleted
d->name[0] = DIR_NAME_DELETED;
// set this file closed
type_ = FAT_FILE_TYPE_CLOSED;
// write entry to SD
return vol_->cacheFlush();
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
/** Remove a file.
*
* The directory entry and all data for the file are deleted.
*
* \param[in] dirFile The directory that contains the file.
* \param[in] path Path for the file to be removed.
*
* \note This function should not be used to delete the 8.3 version of a
* file that has a long name. For example if a file has the long name
* "New Text Document.txt" you should not delete the 8.3 name "NEWTEX~1.TXT".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is a directory, is read only,
* \a dirFile is not a directory, \a path is not found
* or an I/O error occurred.
*/
bool SdBaseFile::remove(SdBaseFile* dirFile, const char* path) {
SdBaseFile file;
if (!file.open(dirFile, path, O_WRITE)) goto fail;
return file.remove();
fail:
// can't set iostate - static function
return false;
}
//------------------------------------------------------------------------------
/** Rename a file or subdirectory.
*
* \param[in] dirFile Directory for the new path.
* \param[in] newPath New path name for the file/directory.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include \a dirFile is not open or is not a directory
* file, newPath is invalid or already exists, or an I/O error occurs.
*/
bool SdBaseFile::rename(SdBaseFile* dirFile, const char* newPath) {
dir_t entry;
uint32_t dirCluster = 0;
SdBaseFile file;
dir_t* d;
// must be an open file or subdirectory
if (!(isFile() || isSubDir())) goto fail;
// can't move file
if (vol_ != dirFile->vol_) goto fail;
// sync() and cache directory entry
sync();
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
// save directory entry
memcpy(&entry, d, sizeof(entry));
// mark entry deleted
d->name[0] = DIR_NAME_DELETED;
// make directory entry for new path
if (isFile()) {
if (!file.open(dirFile, newPath, O_CREAT | O_EXCL | O_WRITE)) {
goto restore;
}
} else {
// don't create missing path prefix components
if (!file.mkdir(dirFile, newPath, false)) {
goto restore;
}
// save cluster containing new dot dot
dirCluster = file.firstCluster_;
}
// change to new directory entry
dirBlock_ = file.dirBlock_;
dirIndex_ = file.dirIndex_;
// mark closed to avoid possible destructor close call
file.type_ = FAT_FILE_TYPE_CLOSED;
// cache new directory entry
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
// copy all but name field to new directory entry
memcpy(&d->attributes, &entry.attributes, sizeof(entry) - sizeof(d->name));
// update dot dot if directory
if (dirCluster) {
// get new dot dot
uint32_t block = vol_->clusterStartBlock(dirCluster);
if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_READ)) goto fail;
memcpy(&entry, &vol_->cache()->dir[1], sizeof(entry));
// free unused cluster
if (!vol_->freeChain(dirCluster)) goto fail;
// store new dot dot
block = vol_->clusterStartBlock(firstCluster_);
if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail;
memcpy(&vol_->cache()->dir[1], &entry, sizeof(entry));
}
return vol_->cacheFlush();
restore:
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
// restore entry
d->name[0] = entry.name[0];
vol_->cacheFlush();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Remove a directory file.
*
* The directory file will be removed only if it is empty and is not the
* root directory. rmdir() follows DOS and Windows and ignores the
* read-only attribute for the directory.
*
* \note This function should not be used to delete the 8.3 version of a
* directory that has a long name. For example if a directory has the
* long name "New folder" you should not delete the 8.3 name "NEWFOL~1".
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include the file is not a directory, is the root
* directory, is not empty, or an I/O error occurred.
*/
bool SdBaseFile::rmdir() {
// must be open subdirectory
if (!isSubDir()) goto fail;
rewind();
// make sure directory is empty
while (curPosition_ < fileSize_) {
dir_t* p = readDirCache();
if (!p) goto fail;
// done if past last used entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip empty slot, '.' or '..'
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// error not empty
if (DIR_IS_FILE_OR_SUBDIR(p)) goto fail;
}
// convert empty directory to normal file for remove
type_ = FAT_FILE_TYPE_NORMAL;
flags_ |= O_WRITE;
return remove();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Recursively delete a directory and all contained files.
*
* This is like the Unix/Linux 'rm -rf *' if called with the root directory
* hence the name.
*
* Warning - This will remove all contents of the directory including
* subdirectories. The directory will then be removed if it is not root.
* The read-only attribute for files will be ignored.
*
* \note This function should not be used to delete the 8.3 version of
* a directory that has a long name. See remove() and rmdir().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::rmRfStar() {
uint16_t index;
SdBaseFile f;
rewind();
while (curPosition_ < fileSize_) {
// remember position
index = curPosition_/32;
dir_t* p = readDirCache();
if (!p) goto fail;
// done if past last entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip empty slot or '.' or '..'
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// skip if part of long file name or volume label in root
if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
if (!f.open(this, index, O_READ)) goto fail;
if (f.isSubDir()) {
// recursively delete
if (!f.rmRfStar()) goto fail;
} else {
// ignore read-only
f.flags_ |= O_WRITE;
if (!f.remove()) goto fail;
}
// position to next entry if required
if (curPosition_ != (32*(index + 1))) {
if (!seekSet(32*(index + 1))) goto fail;
}
}
// don't try to delete root
if (!isRoot()) {
if (!rmdir()) goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
SdBaseFile::SdBaseFile(const char* path, uint8_t oflag) {
type_ = FAT_FILE_TYPE_CLOSED;
writeError = false;
open(path, oflag);
}
//------------------------------------------------------------------------------
/** Sets a file's position.
*
* \param[in] pos The new position in bytes from the beginning of the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::seekSet(uint32_t pos) {
uint32_t nCur;
uint32_t nNew;
// error if file not open or seek past end of file
if (!isOpen() || pos > fileSize_) goto fail;
if (type_ == FAT_FILE_TYPE_ROOT_FIXED) {
curPosition_ = pos;
goto done;
}
if (pos == 0) {
// set position to start of file
curCluster_ = 0;
curPosition_ = 0;
goto done;
}
// calculate cluster index for cur and new position
nCur = (curPosition_ - 1) >> (vol_->clusterSizeShift_ + 9);
nNew = (pos - 1) >> (vol_->clusterSizeShift_ + 9);
if (nNew < nCur || curPosition_ == 0) {
// must follow chain from first cluster
curCluster_ = firstCluster_;
} else {
// advance from curPosition
nNew -= nCur;
}
while (nNew--) {
if (!vol_->fatGet(curCluster_, &curCluster_)) goto fail;
}
curPosition_ = pos;
done:
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
void SdBaseFile::setpos(fpos_t* pos) {
curPosition_ = pos->position;
curCluster_ = pos->cluster;
}
//------------------------------------------------------------------------------
/** The sync() call causes all modified data and directory fields
* to be written to the storage device.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include a call to sync() before a file has been
* opened or an I/O error.
*/
bool SdBaseFile::sync() {
// only allow open files and directories
if (!isOpen()) goto fail;
if (flags_ & F_FILE_DIR_DIRTY) {
dir_t* d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
// check for deleted by another open file object
if (!d || d->name[0] == DIR_NAME_DELETED) goto fail;
// do not set filesize for dir files
if (!isDir()) d->fileSize = fileSize_;
// update first cluster fields
d->firstClusterLow = firstCluster_ & 0XFFFF;
d->firstClusterHigh = firstCluster_ >> 16;
// set modify time if user supplied a callback date/time function
if (dateTime_) {
dateTime_(&d->lastWriteDate, &d->lastWriteTime);
d->lastAccessDate = d->lastWriteDate;
}
// clear directory dirty
flags_ &= ~F_FILE_DIR_DIRTY;
}
return vol_->cacheFlush();
fail:
writeError = true;
return false;
}
//------------------------------------------------------------------------------
/** Copy a file's timestamps
*
* \param[in] file File to copy timestamps from.
*
* \note
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::timestamp(SdBaseFile* file) {
dir_t* d;
dir_t dir;
// get timestamps
if (!file->dirEntry(&dir)) goto fail;
// update directory fields
if (!sync()) goto fail;
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
// copy timestamps
d->lastAccessDate = dir.lastAccessDate;
d->creationDate = dir.creationDate;
d->creationTime = dir.creationTime;
d->creationTimeTenths = dir.creationTimeTenths;
d->lastWriteDate = dir.lastWriteDate;
d->lastWriteTime = dir.lastWriteTime;
// write back entry
return vol_->cacheFlush();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Set a file's timestamps in its directory entry.
*
* \param[in] flags Values for \a flags are constructed by a bitwise-inclusive
* OR of flags from the following list
*
* T_ACCESS - Set the file's last access date.
*
* T_CREATE - Set the file's creation date and time.
*
* T_WRITE - Set the file's last write/modification date and time.
*
* \param[in] year Valid range 1980 - 2107 inclusive.
*
* \param[in] month Valid range 1 - 12 inclusive.
*
* \param[in] day Valid range 1 - 31 inclusive.
*
* \param[in] hour Valid range 0 - 23 inclusive.
*
* \param[in] minute Valid range 0 - 59 inclusive.
*
* \param[in] second Valid range 0 - 59 inclusive
*
* \note It is possible to set an invalid date since there is no check for
* the number of days in a month.
*
* \note
* Modify and access timestamps may be overwritten if a date time callback
* function has been set by dateTimeCallback().
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
*/
bool SdBaseFile::timestamp(uint8_t flags, uint16_t year, uint8_t month,
uint8_t day, uint8_t hour, uint8_t minute, uint8_t second) {
uint16_t dirDate;
uint16_t dirTime;
dir_t* d;
if (!isOpen()
|| year < 1980
|| year > 2107
|| month < 1
|| month > 12
|| day < 1
|| day > 31
|| hour > 23
|| minute > 59
|| second > 59) {
goto fail;
}
// update directory entry
if (!sync()) goto fail;
d = cacheDirEntry(SdVolume::CACHE_FOR_WRITE);
if (!d) goto fail;
dirDate = FAT_DATE(year, month, day);
dirTime = FAT_TIME(hour, minute, second);
if (flags & T_ACCESS) {
d->lastAccessDate = dirDate;
}
if (flags & T_CREATE) {
d->creationDate = dirDate;
d->creationTime = dirTime;
// seems to be units of 1/100 second not 1/10 as Microsoft states
d->creationTimeTenths = second & 1 ? 100 : 0;
}
if (flags & T_WRITE) {
d->lastWriteDate = dirDate;
d->lastWriteTime = dirTime;
}
return vol_->cacheFlush();
fail:
return false;
}
//------------------------------------------------------------------------------
/** Truncate a file to a specified length. The current file position
* will be maintained if it is less than or equal to \a length otherwise
* it will be set to end of file.
*
* \param[in] length The desired length for the file.
*
* \return The value one, true, is returned for success and
* the value zero, false, is returned for failure.
* Reasons for failure include file is read only, file is a directory,
* \a length is greater than the current file size or an I/O error occurs.
*/
bool SdBaseFile::truncate(uint32_t length) {
uint32_t newPos;
// error if not a normal file or read-only
if (!isFile() || !(flags_ & O_WRITE)) goto fail;
// error if length is greater than current size
if (length > fileSize_) goto fail;
// fileSize and length are zero - nothing to do
if (fileSize_ == 0) return true;
// remember position for seek after truncation
newPos = curPosition_ > length ? length : curPosition_;
// position to last cluster in truncated file
if (!seekSet(length)) goto fail;
if (length == 0) {
// free all clusters
if (!vol_->freeChain(firstCluster_)) goto fail;
firstCluster_ = 0;
} else {
uint32_t toFree;
if (!vol_->fatGet(curCluster_, &toFree)) goto fail;
if (!vol_->isEOC(toFree)) {
// free extra clusters
if (!vol_->freeChain(toFree)) goto fail;
// current cluster is end of chain
if (!vol_->fatPutEOC(curCluster_)) goto fail;
}
}
fileSize_ = length;
// need to update directory entry
flags_ |= F_FILE_DIR_DIRTY;
if (!sync()) goto fail;
// set file to correct position
return seekSet(newPos);
fail:
return false;
}
//------------------------------------------------------------------------------
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error.
*
*/
int16_t SdBaseFile::write(const void* buf, uint16_t nbyte) {
// convert void* to uint8_t* - must be before goto statements
const uint8_t* src = reinterpret_cast<const uint8_t*>(buf);
// number of bytes left to write - must be before goto statements
uint16_t nToWrite = nbyte;
// error if not a normal file or is read-only
if (!isFile() || !(flags_ & O_WRITE)) goto fail;
// seek to end of file if append flag
if ((flags_ & O_APPEND) && curPosition_ != fileSize_) {
if (!seekEnd()) goto fail;
}
while (nToWrite > 0) {
uint8_t blockOfCluster = vol_->blockOfCluster(curPosition_);
uint16_t blockOffset = curPosition_ & 0X1FF;
if (blockOfCluster == 0 && blockOffset == 0) {
// start of new cluster
if (curCluster_ == 0) {
if (firstCluster_ == 0) {
// allocate first cluster of file
if (!addCluster()) goto fail;
} else {
curCluster_ = firstCluster_;
}
} else {
uint32_t next;
if (!vol_->fatGet(curCluster_, &next)) goto fail;
if (vol_->isEOC(next)) {
// add cluster if at end of chain
if (!addCluster()) goto fail;
} else {
curCluster_ = next;
}
}
}
// max space in block
uint16_t n = 512 - blockOffset;
// lesser of space and amount to write
if (n > nToWrite) n = nToWrite;
// block for data write
uint32_t block = vol_->clusterStartBlock(curCluster_) + blockOfCluster;
if (n == 512) {
// full block - don't need to use cache
if (vol_->cacheBlockNumber() == block) {
// invalidate cache if block is in cache
vol_->cacheSetBlockNumber(0XFFFFFFFF, false);
}
if (!vol_->writeBlock(block, src)) goto fail;
} else {
if (blockOffset == 0 && curPosition_ >= fileSize_) {
// start of new block don't need to read into cache
if (!vol_->cacheFlush()) goto fail;
// set cache dirty and SD address of block
vol_->cacheSetBlockNumber(block, true);
} else {
// rewrite part of block
if (!vol_->cacheRawBlock(block, SdVolume::CACHE_FOR_WRITE)) goto fail;
}
uint8_t* dst = vol_->cache()->data + blockOffset;
memcpy(dst, src, n);
}
curPosition_ += n;
src += n;
nToWrite -= n;
}
if (curPosition_ > fileSize_) {
// update fileSize and insure sync will update dir entry
fileSize_ = curPosition_;
flags_ |= F_FILE_DIR_DIRTY;
} else if (dateTime_ && nbyte) {
// insure sync will update modified date and time
flags_ |= F_FILE_DIR_DIRTY;
}
if (flags_ & O_SYNC) {
if (!sync()) goto fail;
}
return nbyte;
fail:
// return for write error
writeError = true;
return -1;
}
//------------------------------------------------------------------------------
// suppress cpplint warnings with NOLINT comment
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
void (*SdBaseFile::oldDateTime_)(uint16_t& date, uint16_t& time) = 0; // NOLINT
#endif // ALLOW_DEPRECATED_FUNCTIONS
#endif

@ -0,0 +1,483 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdBaseFile_h
#define SdBaseFile_h
/**
* \file
* \brief SdBaseFile class
*/
#include "Marlin.h"
#include "SdFatConfig.h"
#include "SdVolume.h"
//------------------------------------------------------------------------------
/**
* \struct fpos_t
* \brief internal type for istream
* do not use in user apps
*/
struct fpos_t {
/** stream position */
uint32_t position;
/** cluster for position */
uint32_t cluster;
fpos_t() : position(0), cluster(0) {}
};
// use the gnu style oflag in open()
/** open() oflag for reading */
uint8_t const O_READ = 0X01;
/** open() oflag - same as O_IN */
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;
/** truncate the file to zero length */
uint8_t const O_TRUNC = 0X10;
/** set the initial position at the end of the file */
uint8_t const O_AT_END = 0X20;
/** create the file if nonexistent */
uint8_t const O_CREAT = 0X40;
/** If O_CREAT and O_EXCL are set, open() shall fail if the file exists */
uint8_t const O_EXCL = 0X80;
// SdBaseFile class static and const definitions
// 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;
// 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 file has not been opened. */
uint8_t const FAT_FILE_TYPE_CLOSED = 0;
/** A normal file */
uint8_t const FAT_FILE_TYPE_NORMAL = 1;
/** A FAT12 or FAT16 root directory */
uint8_t const FAT_FILE_TYPE_ROOT_FIXED = 2;
/** A FAT32 root directory */
uint8_t const FAT_FILE_TYPE_ROOT32 = 3;
/** A subdirectory file*/
uint8_t const FAT_FILE_TYPE_SUBDIR = 4;
/** Test value for directory type */
uint8_t const FAT_FILE_TYPE_MIN_DIR = FAT_FILE_TYPE_ROOT_FIXED;
/** date field for FAT directory entry
* \param[in] year [1980,2107]
* \param[in] month [1,12]
* \param[in] day [1,31]
*
* \return Packed date for dir_t 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
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted year [1980,2107]
*/
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
return 1980 + (fatDate >> 9);
}
/** month part of FAT directory date field
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted month [1,12]
*/
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
return (fatDate >> 5) & 0XF;
}
/** day part of FAT directory date field
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted day [1,31]
*/
static inline uint8_t FAT_DAY(uint16_t fatDate) {
return fatDate & 0X1F;
}
/** time field for FAT directory entry
* \param[in] hour [0,23]
* \param[in] minute [0,59]
* \param[in] second [0,59]
*
* \return Packed time for dir_t 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
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted hour [0,23]
*/
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
return fatTime >> 11;
}
/** minute part of FAT directory time field
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted minute [0,59]
*/
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
return(fatTime >> 5) & 0X3F;
}
/** second part of FAT directory time field
* Note second/2 is stored in packed time.
*
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted second [0,58]
*/
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 SdBaseFile
* \brief Base class for SdFile with Print and C++ streams.
*/
class SdBaseFile {
public:
/** Create an instance. */
SdBaseFile() : writeError(false), type_(FAT_FILE_TYPE_CLOSED) {}
SdBaseFile(const char* path, uint8_t oflag);
~SdBaseFile() {if(isOpen()) close();}
/**
* 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;
//----------------------------------------------------------------------------
// helpers for stream classes
/** get position for streams
* \param[out] pos struct to receive position
*/
void getpos(fpos_t* pos);
/** set position for streams
* \param[out] pos struct with value for new position
*/
void setpos(fpos_t* pos);
//----------------------------------------------------------------------------
bool close();
bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
bool createContiguous(SdBaseFile* dirFile,
const char* path, uint32_t size);
/** \return The current cluster number for a file or directory. */
uint32_t curCluster() const {return curCluster_;}
/** \return The current position for a file or directory. */
uint32_t curPosition() const {return curPosition_;}
/** \return Current working directory */
static SdBaseFile* cwd() {return cwd_;}
/** 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() {dateTime_ = 0;}
bool dirEntry(dir_t* dir);
static void dirName(const dir_t& dir, char* name);
bool exists(const char* name);
int16_t fgets(char* str, int16_t num, char* delim = 0);
/** \return The total number of bytes in a file or directory. */
uint32_t fileSize() const {return fileSize_;}
/** \return The first cluster number for a file or directory. */
uint32_t firstCluster() const {return firstCluster_;}
bool getFilename(char* name);
/** \return True if this is a directory else false. */
bool isDir() const {return type_ >= FAT_FILE_TYPE_MIN_DIR;}
/** \return True if this is a normal file else false. */
bool isFile() const {return type_ == FAT_FILE_TYPE_NORMAL;}
/** \return True if this is an open file/directory else false. */
bool isOpen() const {return type_ != FAT_FILE_TYPE_CLOSED;}
/** \return True if this is a subdirectory else false. */
bool isSubDir() const {return type_ == FAT_FILE_TYPE_SUBDIR;}
/** \return True if this is the root directory. */
bool isRoot() const {
return type_ == FAT_FILE_TYPE_ROOT_FIXED || type_ == FAT_FILE_TYPE_ROOT32;
}
void ls( uint8_t flags = 0, uint8_t indent = 0);
bool mkdir(SdBaseFile* dir, const char* path, bool pFlag = true);
// alias for backward compactability
bool makeDir(SdBaseFile* dir, const char* path) {
return mkdir(dir, path, false);
}
bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
bool open(const char* path, uint8_t oflag = O_READ);
bool openNext(SdBaseFile* dirFile, uint8_t oflag);
bool openRoot(SdVolume* vol);
int peek();
static void printFatDate(uint16_t fatDate);
static void printFatTime( uint16_t fatTime);
bool printName();
int16_t read();
int16_t read(void* buf, uint16_t nbyte);
int8_t readDir(dir_t* dir, char* longFilename);
static bool remove(SdBaseFile* dirFile, const char* path);
bool remove();
/** Set the file's current position to zero. */
void rewind() {seekSet(0);}
bool rename(SdBaseFile* dirFile, const char* newPath);
bool rmdir();
// for backward compatibility
bool rmDir() {return rmdir();}
bool rmRfStar();
/** Set the files position to current position + \a pos. See seekSet().
* \param[in] offset The new position in bytes from the current position.
* \return true for success or false for failure.
*/
bool seekCur(int32_t offset) {
return seekSet(curPosition_ + offset);
}
/** Set the files position to end-of-file + \a offset. See seekSet().
* \param[in] offset The new position in bytes from end-of-file.
* \return true for success or false for failure.
*/
bool seekEnd(int32_t offset = 0) {return seekSet(fileSize_ + offset);}
bool seekSet(uint32_t pos);
bool sync();
bool timestamp(SdBaseFile* file);
bool timestamp(uint8_t flag, uint16_t year, uint8_t month, uint8_t day,
uint8_t hour, uint8_t minute, uint8_t second);
/** Type of file. You should use isFile() or isDir() instead of type()
* if possible.
*
* \return The file or directory type.
*/
uint8_t type() const {return type_;}
bool truncate(uint32_t size);
/** \return SdVolume that contains this file. */
SdVolume* volume() const {return vol_;}
int16_t write(const void* buf, uint16_t nbyte);
//------------------------------------------------------------------------------
private:
// allow SdFat to set cwd_
friend class SdFat;
// global pointer to cwd dir
static SdBaseFile* cwd_;
// data time callback function
static void (*dateTime_)(uint16_t* date, uint16_t* time);
// bits defined in flags_
// should be 0X0F
static uint8_t const F_OFLAG = (O_ACCMODE | O_APPEND | O_SYNC);
// sync of directory entry required
static uint8_t const F_FILE_DIR_DIRTY = 0X80;
// private data
uint8_t flags_; // See above for definition of flags_ bits
uint8_t fstate_; // error and eof indicator
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_; // block for this files directory entry
uint8_t dirIndex_; // index of directory entry in dirBlock
uint32_t fileSize_; // file size in bytes
uint32_t firstCluster_; // first cluster of file
SdVolume* vol_; // volume where file is located
/** experimental don't use */
bool openParent(SdBaseFile* dir);
// private functions
bool addCluster();
bool addDirCluster();
dir_t* cacheDirEntry(uint8_t action);
int8_t lsPrintNext( uint8_t flags, uint8_t indent);
static bool make83Name(const char* str, uint8_t* name, const char** ptr);
bool mkdir(SdBaseFile* parent, const uint8_t dname[11]);
bool open(SdBaseFile* dirFile, const uint8_t dname[11], uint8_t oflag);
bool openCachedEntry(uint8_t cacheIndex, uint8_t oflags);
dir_t* readDirCache();
//------------------------------------------------------------------------------
// to be deleted
static void printDirName( const dir_t& dir,
uint8_t width, bool printSlash);
//------------------------------------------------------------------------------
// Deprecated functions - suppress cpplint warnings with NOLINT comment
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
public:
/** \deprecated Use:
* bool contiguousRange(uint32_t* bgnBlock, uint32_t* endBlock);
* \param[out] bgnBlock the first block address for the file.
* \param[out] endBlock the last block address for the file.
* \return true for success or false for failure.
*/
bool contiguousRange(uint32_t& bgnBlock, uint32_t& endBlock) { // NOLINT
return contiguousRange(&bgnBlock, &endBlock);
}
/** \deprecated Use:
* bool createContiguous(SdBaseFile* dirFile,
* const char* path, uint32_t size)
* \param[in] dirFile The directory where the file will be created.
* \param[in] path A path with a valid DOS 8.3 file name.
* \param[in] size The desired file size.
* \return true for success or false for failure.
*/
bool createContiguous(SdBaseFile& dirFile, // NOLINT
const char* path, uint32_t size) {
return createContiguous(&dirFile, path, size);
}
/** \deprecated Use:
* static void dateTimeCallback(
* void (*dateTime)(uint16_t* date, uint16_t* time));
* \param[in] dateTime The user's call back function.
*/
static void dateTimeCallback(
void (*dateTime)(uint16_t& date, uint16_t& time)) { // NOLINT
oldDateTime_ = dateTime;
dateTime_ = dateTime ? oldToNew : 0;
}
/** \deprecated Use: bool dirEntry(dir_t* dir);
* \param[out] dir Location for return of the file's directory entry.
* \return true for success or false for failure.
*/
bool dirEntry(dir_t& dir) {return dirEntry(&dir);} // NOLINT
/** \deprecated Use:
* bool mkdir(SdBaseFile* dir, const char* path);
* \param[in] dir An open SdFat instance for the directory that will contain
* the new directory.
* \param[in] path A path with a valid 8.3 DOS name for the new directory.
* \return true for success or false for failure.
*/
bool mkdir(SdBaseFile& dir, const char* path) { // NOLINT
return mkdir(&dir, path);
}
/** \deprecated Use:
* bool open(SdBaseFile* dirFile, const char* path, uint8_t oflag);
* \param[in] dirFile An open SdFat instance for the directory containing the
* file to be opened.
* \param[in] path A path with a valid 8.3 DOS name for the file.
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
* \return true for success or false for failure.
*/
bool open(SdBaseFile& dirFile, // NOLINT
const char* path, uint8_t oflag) {
return open(&dirFile, path, oflag);
}
/** \deprecated Do not use in new apps
* \param[in] dirFile An open SdFat instance for the directory containing the
* file to be opened.
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
* \return true for success or false for failure.
*/
bool open(SdBaseFile& dirFile, const char* path) { // NOLINT
return open(dirFile, path, O_RDWR);
}
/** \deprecated Use:
* bool open(SdBaseFile* dirFile, uint16_t index, uint8_t oflag);
* \param[in] dirFile An open SdFat instance for the directory.
* \param[in] index The \a index of the directory entry for the file to be
* opened. The value for \a index is (directory file position)/32.
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of flags O_READ, O_WRITE, O_TRUNC, and O_SYNC.
* \return true for success or false for failure.
*/
bool open(SdBaseFile& dirFile, uint16_t index, uint8_t oflag) { // NOLINT
return open(&dirFile, index, oflag);
}
/** \deprecated Use: bool openRoot(SdVolume* vol);
* \param[in] vol The FAT volume containing the root directory to be opened.
* \return true for success or false for failure.
*/
bool openRoot(SdVolume& vol) {return openRoot(&vol);} // NOLINT
/** \deprecated Use: int8_t readDir(dir_t* dir);
* \param[out] dir The dir_t struct that will receive the data.
* \return bytes read for success zero for eof or -1 for failure.
*/
int8_t readDir(dir_t& dir, char* longFilename) {return readDir(&dir, longFilename);} // NOLINT
/** \deprecated Use:
* static uint8_t remove(SdBaseFile* dirFile, const char* path);
* \param[in] dirFile The directory that contains the file.
* \param[in] path The name of the file to be removed.
* \return true for success or false for failure.
*/
static bool remove(SdBaseFile& dirFile, const char* path) { // NOLINT
return remove(&dirFile, path);
}
//------------------------------------------------------------------------------
// 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
};
#endif // SdBaseFile_h
#endif

@ -0,0 +1,121 @@
/* 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/>.
*/
/**
* \file
* \brief configuration definitions
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdFatConfig_h
#define SdFatConfig_h
#include <stdint.h>
//------------------------------------------------------------------------------
/**
* To use multiple SD cards set USE_MULTIPLE_CARDS nonzero.
*
* Using multiple cards costs 400 - 500 bytes of flash.
*
* Each card requires about 550 bytes of SRAM so use of a Mega is recommended.
*/
#define USE_MULTIPLE_CARDS 0
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
*
* The standard for iostreams is to call flush. This is very costly for
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
*
* SdFat has a single 512 byte buffer for SD I/O so it must write the current
* data block to the SD, read the directory block from the SD, update the
* directory entry, write the directory block to the SD and read the data
* block back into the buffer.
*
* The SD flash memory controller is not designed for this many rewrites
* so performance may be reduced by more than a factor of 100.
*
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
* all data to be written to the SD.
*/
#define ENDL_CALLS_FLUSH 0
//------------------------------------------------------------------------------
/**
* Allow use of deprecated functions if ALLOW_DEPRECATED_FUNCTIONS is nonzero
*/
#define ALLOW_DEPRECATED_FUNCTIONS 1
//------------------------------------------------------------------------------
/**
* Allow FAT12 volumes if FAT12_SUPPORT is nonzero.
* FAT12 has not been well tested.
*/
#define FAT12_SUPPORT 0
//------------------------------------------------------------------------------
/**
* SPI init rate for SD initialization commands. Must be 5 (F_CPU/64)
* or 6 (F_CPU/128).
*/
#define SPI_SD_INIT_RATE 5
//------------------------------------------------------------------------------
/**
* Set the SS pin high for hardware SPI. If SS is chip select for another SPI
* device this will disable that device during the SD init phase.
*/
#define SET_SPI_SS_HIGH 1
//------------------------------------------------------------------------------
/**
* Define MEGA_SOFT_SPI nonzero 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
//------------------------------------------------------------------------------
/**
* Set USE_SOFTWARE_SPI nonzero to always use software SPI.
*/
#define USE_SOFTWARE_SPI 0
// define software SPI pins so Mega can use unmodified 168/328 shields
/** Software SPI chip select pin for the SD */
uint8_t const SOFT_SPI_CS_PIN = 10;
/** Software SPI Master Out Slave In pin */
uint8_t const SOFT_SPI_MOSI_PIN = 11;
/** Software SPI Master In Slave Out pin */
uint8_t const SOFT_SPI_MISO_PIN = 12;
/** Software SPI Clock pin */
uint8_t const SOFT_SPI_SCK_PIN = 13;
//------------------------------------------------------------------------------
/**
* The __cxa_pure_virtual function is an error handler that is invoked when
* a pure virtual function is called.
*/
#define USE_CXA_PURE_VIRTUAL 1
/**
* Defines for long (vfat) filenames
*/
/** Number of VFAT entries used. Every entry has 13 UTF-16 characters */
#define MAX_VFAT_ENTRIES (2)
/** Total size of the buffer used to store the long filenames */
#define LONG_FILENAME_LENGTH (13*MAX_VFAT_ENTRIES+1)
#endif // SdFatConfig_h
#endif

@ -0,0 +1,646 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdFatStructs_h
#define SdFatStructs_h
#define PACKED __attribute__((__packed__))
/**
* \file
* \brief 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;
/** Value for bootSignature field int FAT/FAT32 boot sector */
uint8_t const EXTENDED_BOOT_SIG = 0X29;
//------------------------------------------------------------------------------
/**
* \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;
} PACKED;
/** 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 Windows NT disk signature. May contain 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;
} PACKED;
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
/**
* \struct fat_boot
*
* \brief Boot sector for a FAT12/FAT16 volume.
*
*/
struct fat_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next nonexecutable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
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. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. The value of this field is always 1.
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
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 nonzero. 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 (nonremovable) 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 sectorsPerTrack;
/** 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 nonzero.
*/
uint32_t totalSectors32;
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
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;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A field with a value of either FAT, FAT12 or FAT16,
* depending on the disk format.
*/
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[448];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
} PACKED;
/** Type name for FAT Boot Sector */
typedef struct fat_boot fat_boot_t;
//------------------------------------------------------------------------------
/**
* \struct fat32_boot
*
* \brief Boot sector for a FAT32 volume.
*
*/
struct fat32_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next nonexecutable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
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. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. Must not be zero
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
uint8_t fatCount;
/**
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
*/
uint16_t rootDirEntryCount;
/**
* For FAT32 volumes, this field must be 0.
*/
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 (nonremovable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* 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 sectorsPerTrack;
/** 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;
/**
* Contains the total number of sectors in the FAT32 volume.
*/
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 nonzero, 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];
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
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;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A text field with a value of FAT32.
*/
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
} PACKED;
/** Type name for FAT32 Boot Sector */
typedef struct fat32_boot fat32_boot_t;
//------------------------------------------------------------------------------
/** Lead signature for a FSINFO sector */
uint32_t const FSINFO_LEAD_SIG = 0x41615252;
/** Struct signature for a FSINFO sector */
uint32_t const FSINFO_STRUCT_SIG = 0x61417272;
/**
* \struct fat32_fsinfo
*
* \brief FSINFO sector for a FAT32 volume.
*
*/
struct fat32_fsinfo {
/** must be 0X52, 0X52, 0X61, 0X41 */
uint32_t leadSignature;
/** must be zero */
uint8_t reserved1[480];
/** must be 0X72, 0X72, 0X41, 0X61 */
uint32_t structSignature;
/**
* Contains the last known free cluster count on the volume.
* If the value is 0xFFFFFFFF, then the free count is unknown
* and must be computed. Any other value can be used, but is
* not necessarily correct. It should be range checked at least
* to make sure it is <= volume cluster count.
*/
uint32_t freeCount;
/**
* This is a hint for the FAT driver. It indicates the cluster
* number at which the driver should start looking for free clusters.
* If the value is 0xFFFFFFFF, then there is no hint and the driver
* should start looking at cluster 2.
*/
uint32_t nextFree;
/** must be zero */
uint8_t reserved2[12];
/** must be 0X00, 0X00, 0X55, 0XAA */
uint8_t tailSignature[4];
} PACKED;
/** Type name for FAT32 FSINFO Sector */
typedef struct fat32_fsinfo fat32_fsinfo_t;
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT12 end of chain value used by Microsoft. */
uint16_t const FAT12EOC = 0XFFF;
/** Minimum value for FAT12 EOC. Use to test for EOC. */
uint16_t const FAT12EOC_MIN = 0XFF8;
/** 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;
//------------------------------------------------------------------------------
/**
* \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;
} PACKED;
/**
* \struct directoryVFATEntry
* \brief VFAT long filename directory entry
*
* directoryVFATEntries are found in the same list as normal directoryEntry.
* But have the attribute field set to DIR_ATT_LONG_NAME.
*
* Long filenames are saved in multiple directoryVFATEntries.
* Each entry containing 13 UTF-16 characters.
*/
struct directoryVFATEntry {
/**
* Sequence number. Consists of 2 parts:
* bit 6: indicates first long filename block for the next file
* bit 0-4: the position of this long filename block (first block is 1)
*/
uint8_t sequenceNumber;
/** First set of UTF-16 characters */
uint16_t name1[5];//UTF-16
/** attributes (at the same location as in directoryEntry), always 0x0F */
uint8_t attributes;
/** Reserved for use by Windows NT. Always 0. */
uint8_t reservedNT;
/** Checksum of the short 8.3 filename, can be used to checked if the file system as modified by a not-long-filename aware implementation. */
uint8_t checksum;
/** Second set of UTF-16 characters */
uint16_t name2[6];//UTF-16
/** firstClusterLow is always zero for longFilenames */
uint16_t firstClusterLow;
/** Third set of UTF-16 characters */
uint16_t name3[2];//UTF-16
} PACKED;
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
/** Type name for directoryVFATEntry */
typedef struct directoryVFATEntry vfat_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
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for part of a long name else false.
*/
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
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file else false.
*/
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
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a subdirectory else false.
*/
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
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file or subdirectory else false.
*/
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
#endif // SdFatStructs_h
#endif

@ -0,0 +1,79 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#include "SdFatUtil.h"
//------------------------------------------------------------------------------
/** Amount of free RAM
* \return The number of free bytes.
*/
int SdFatUtil::FreeRam() {
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.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::print_P( PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) MYSERIAL.write(c);
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory followed by a CR/LF.
*
* \param[in] pr Print object for output.
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::println_P( PGM_P str) {
print_P( str);
MYSERIAL.println();
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory to Serial.
*
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::SerialPrint_P(PGM_P str) {
print_P(str);
}
//------------------------------------------------------------------------------
/** %Print a string in flash memory to Serial followed by a CR/LF.
*
* \param[in] str Pointer to string stored in flash memory.
*/
void SdFatUtil::SerialPrintln_P(PGM_P str) {
println_P( str);
}
#endif

@ -0,0 +1,48 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdFatUtil_h
#define SdFatUtil_h
/**
* \file
* \brief Useful utility functions.
*/
#include "Marlin.h"
#include "MarlinSerial.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))
namespace SdFatUtil {
int FreeRam();
void print_P( PGM_P str);
void println_P( PGM_P str);
void SerialPrint_P(PGM_P str);
void SerialPrintln_P(PGM_P str);
}
using namespace SdFatUtil; // NOLINT
#endif // #define SdFatUtil_h
#endif

@ -0,0 +1,92 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#include "SdFile.h"
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a bitwise-inclusive
* OR of open flags. see SdBaseFile::open(SdBaseFile*, const char*, uint8_t).
*/
SdFile::SdFile(const char* path, uint8_t oflag) : SdBaseFile(path, oflag) {
}
//------------------------------------------------------------------------------
/** Write data to an open file.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] nbyte Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an I/O error.
*
*/
int16_t SdFile::write(const void* buf, uint16_t nbyte) {
return SdBaseFile::write(buf, nbyte);
}
//------------------------------------------------------------------------------
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* Use writeError to check for errors.
*/
#if ARDUINO >= 100
size_t SdFile::write(uint8_t b)
#else
void SdFile::write(uint8_t b)
#endif
{
SdBaseFile::write(&b, 1);
}
//------------------------------------------------------------------------------
/** Write a string to a file. Used by the Arduino Print class.
* \param[in] str Pointer to the string.
* Use writeError to check for errors.
*/
void SdFile::write(const char* str) {
SdBaseFile::write(str, strlen(str));
}
//------------------------------------------------------------------------------
/** Write a PROGMEM string to a file.
* \param[in] str Pointer to the PROGMEM string.
* Use writeError to check for errors.
*/
void SdFile::write_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) write(c);
}
//------------------------------------------------------------------------------
/** Write a PROGMEM string followed by CR/LF to a file.
* \param[in] str Pointer to the PROGMEM string.
* Use writeError to check for errors.
*/
void SdFile::writeln_P(PGM_P str) {
write_P(str);
write_P(PSTR("\r\n"));
}
#endif

@ -0,0 +1,54 @@
/* 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/>.
*/
/**
* \file
* \brief SdFile class
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#include "SdBaseFile.h"
#include <Print.h>
#ifndef SdFile_h
#define SdFile_h
//------------------------------------------------------------------------------
/**
* \class SdFile
* \brief SdBaseFile with Print.
*/
class SdFile : public SdBaseFile, public Print {
public:
SdFile() {}
SdFile(const char* name, uint8_t oflag);
#if ARDUINO >= 100
size_t write(uint8_t b);
#else
void write(uint8_t b);
#endif
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);
};
#endif // SdFile_h
#endif

@ -0,0 +1,280 @@
/* 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 "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdInfo_h
#define SdInfo_h
#include <stdint.h>
// Based on the document:
//
// SD Specifications
// Part 1
// Physical Layer
// Simplified Specification
// Version 3.01
// May 18, 2010
//
// http://www.sdcard.org/developers/tech/sdcard/pls/simplified_specs
//------------------------------------------------------------------------------
// 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;
/** STOP_TRANSMISSION - end multiple block read sequence */
uint8_t const CMD12 = 0X0C;
/** SEND_STATUS - read the card status register */
uint8_t const CMD13 = 0X0D;
/** READ_SINGLE_BLOCK - read a single data block from the card */
uint8_t const CMD17 = 0X11;
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
uint8_t const CMD18 = 0X12;
/** 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;
//------------------------------------------------------------------------------
/** Card IDentification (CID) register */
typedef struct CID {
// byte 0
/** Manufacturer ID */
unsigned char mid;
// byte 1-2
/** OEM/Application ID */
char oid[2];
// byte 3-7
/** Product name */
char pnm[5];
// byte 8
/** Product revision least significant digit */
unsigned char prv_m : 4;
/** Product revision most significant digit */
unsigned char prv_n : 4;
// byte 9-12
/** Product serial number */
uint32_t psn;
// byte 13
/** Manufacturing date year low digit */
unsigned char mdt_year_high : 4;
/** not used */
unsigned char reserved : 4;
// byte 14
/** Manufacturing date month */
unsigned char mdt_month : 4;
/** Manufacturing date year low digit */
unsigned char mdt_year_low :4;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** CRC7 checksum */
unsigned char crc : 7;
}cid_t;
//------------------------------------------------------------------------------
/** CSD for version 1.00 cards */
typedef struct CSDV1 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
unsigned char taac;
// byte 2
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
unsigned char c_size_high : 2;
unsigned char reserved2 : 2;
unsigned char dsr_imp : 1;
unsigned char read_blk_misalign :1;
unsigned char write_blk_misalign : 1;
unsigned char read_bl_partial : 1;
// byte 7
unsigned char c_size_mid;
// byte 8
unsigned char vdd_r_curr_max : 3;
unsigned char vdd_r_curr_min : 3;
unsigned char c_size_low :2;
// byte 9
unsigned char c_size_mult_high : 2;
unsigned char vdd_w_cur_max : 3;
unsigned char vdd_w_curr_min : 3;
// byte 10
unsigned char sector_size_high : 6;
unsigned char erase_blk_en : 1;
unsigned char c_size_mult_low : 1;
// byte 11
unsigned char wp_grp_size : 7;
unsigned char sector_size_low : 1;
// byte 12
unsigned char write_bl_len_high : 2;
unsigned char r2w_factor : 3;
unsigned char reserved3 : 2;
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved4 : 5;
unsigned char write_partial : 1;
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved5: 2;
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Indicates the file format on the card */
unsigned char file_format_grp : 1;
// byte 15
unsigned char always1 : 1;
unsigned char crc : 7;
}csd1_t;
//------------------------------------------------------------------------------
/** CSD for version 2.00 cards */
typedef struct CSDV2 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
/** fixed to 0X0E */
unsigned char taac;
// byte 2
/** fixed to 0 */
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
/** not used */
unsigned char reserved2 : 4;
unsigned char dsr_imp : 1;
/** fixed to 0 */
unsigned char read_blk_misalign :1;
/** fixed to 0 */
unsigned char write_blk_misalign : 1;
/** fixed to 0 - no partial read */
unsigned char read_bl_partial : 1;
// byte 7
/** not used */
unsigned char reserved3 : 2;
/** high part of card size */
unsigned char c_size_high : 6;
// byte 8
/** middle part of card size */
unsigned char c_size_mid;
// byte 9
/** low part of card size */
unsigned char c_size_low;
// byte 10
/** sector size is fixed at 64 KB */
unsigned char sector_size_high : 6;
/** fixed to 1 - erase single is supported */
unsigned char erase_blk_en : 1;
/** not used */
unsigned char reserved4 : 1;
// byte 11
unsigned char wp_grp_size : 7;
/** sector size is fixed at 64 KB */
unsigned char sector_size_low : 1;
// byte 12
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_high : 2;
/** fixed value of 2 */
unsigned char r2w_factor : 3;
/** not used */
unsigned char reserved5 : 2;
/** fixed value of 0 - no write protect groups */
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved6 : 5;
/** always zero - no partial block read*/
unsigned char write_partial : 1;
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved7: 2;
/** Do not use always 0 */
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Do not use always 0 */
unsigned char file_format_grp : 1;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** checksum */
unsigned char crc : 7;
}csd2_t;
//------------------------------------------------------------------------------
/** union of old and new style CSD register */
union csd_t {
csd1_t v1;
csd2_t v2;
};
#endif // SdInfo_h
#endif

@ -0,0 +1,405 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#include "SdVolume.h"
//------------------------------------------------------------------------------
#if !USE_MULTIPLE_CARDS
// raw block cache
uint32_t SdVolume::cacheBlockNumber_; // current block number
cache_t SdVolume::cacheBuffer_; // 512 byte cache for Sd2Card
Sd2Card* SdVolume::sdCard_; // pointer to SD card object
bool SdVolume::cacheDirty_; // cacheFlush() will write block if true
uint32_t SdVolume::cacheMirrorBlock_; // mirror block for second FAT
#endif // USE_MULTIPLE_CARDS
//------------------------------------------------------------------------------
// find a contiguous group of clusters
bool SdVolume::allocContiguous(uint32_t count, uint32_t* curCluster) {
// start of group
uint32_t bgnCluster;
// end of group
uint32_t endCluster;
// last cluster of FAT
uint32_t fatEnd = clusterCount_ + 1;
// flag to save place to start next search
bool setStart;
// set search start cluster
if (*curCluster) {
// try to make file contiguous
bgnCluster = *curCluster + 1;
// don't save new start location
setStart = false;
} else {
// start at likely place for free cluster
bgnCluster = allocSearchStart_;
// save next search start if one cluster
setStart = count == 1;
}
// end of group
endCluster = bgnCluster;
// search the FAT for free clusters
for (uint32_t n = 0;; n++, endCluster++) {
// can't find space checked all clusters
if (n >= clusterCount_) goto fail;
// past end - start from beginning of FAT
if (endCluster > fatEnd) {
bgnCluster = endCluster = 2;
}
uint32_t f;
if (!fatGet(endCluster, &f)) goto fail;
if (f != 0) {
// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
}
}
// mark end of chain
if (!fatPutEOC(endCluster)) goto fail;
// link clusters
while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) goto fail;
endCluster--;
}
if (*curCluster != 0) {
// connect chains
if (!fatPut(*curCluster, bgnCluster)) goto fail;
}
// return first cluster number to caller
*curCluster = bgnCluster;
// remember possible next free cluster
if (setStart) allocSearchStart_ = bgnCluster + 1;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheFlush() {
if (cacheDirty_) {
if (!sdCard_->writeBlock(cacheBlockNumber_, cacheBuffer_.data)) {
goto fail;
}
// mirror FAT tables
if (cacheMirrorBlock_) {
if (!sdCard_->writeBlock(cacheMirrorBlock_, cacheBuffer_.data)) {
goto fail;
}
cacheMirrorBlock_ = 0;
}
cacheDirty_ = 0;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool SdVolume::cacheRawBlock(uint32_t blockNumber, bool dirty) {
if (cacheBlockNumber_ != blockNumber) {
if (!cacheFlush()) goto fail;
if (!sdCard_->readBlock(blockNumber, cacheBuffer_.data)) goto fail;
cacheBlockNumber_ = blockNumber;
}
if (dirty) cacheDirty_ = true;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// return the size in bytes of a cluster chain
bool SdVolume::chainSize(uint32_t cluster, uint32_t* size) {
uint32_t s = 0;
do {
if (!fatGet(cluster, &cluster)) goto fail;
s += 512UL << clusterSizeShift_;
} while (!isEOC(cluster));
*size = s;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// Fetch a FAT entry
bool SdVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t lba;
if (cluster > (clusterCount_ + 1)) goto fail;
if (FAT12_SUPPORT && fatType_ == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = fatStartBlock_ + (index >> 9);
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
index &= 0X1FF;
uint16_t tmp = cacheBuffer_.data[index];
index++;
if (index == 512) {
if (!cacheRawBlock(lba + 1, CACHE_FOR_READ)) goto fail;
index = 0;
}
tmp |= cacheBuffer_.data[index] << 8;
*value = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
return true;
}
if (fatType_ == 16) {
lba = fatStartBlock_ + (cluster >> 8);
} else if (fatType_ == 32) {
lba = fatStartBlock_ + (cluster >> 7);
} else {
goto fail;
}
if (lba != cacheBlockNumber_) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) goto fail;
}
if (fatType_ == 16) {
*value = cacheBuffer_.fat16[cluster & 0XFF];
} else {
*value = cacheBuffer_.fat32[cluster & 0X7F] & FAT32MASK;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// Store a FAT entry
bool SdVolume::fatPut(uint32_t cluster, uint32_t value) {
uint32_t lba;
// error if reserved cluster
if (cluster < 2) goto fail;
// error if not in FAT
if (cluster > (clusterCount_ + 1)) goto fail;
if (FAT12_SUPPORT && fatType_ == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = fatStartBlock_ + (index >> 9);
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
index &= 0X1FF;
uint8_t tmp = value;
if (cluster & 1) {
tmp = (cacheBuffer_.data[index] & 0XF) | tmp << 4;
}
cacheBuffer_.data[index] = tmp;
index++;
if (index == 512) {
lba++;
index = 0;
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
}
tmp = value >> 4;
if (!(cluster & 1)) {
tmp = ((cacheBuffer_.data[index] & 0XF0)) | tmp >> 4;
}
cacheBuffer_.data[index] = tmp;
return true;
}
if (fatType_ == 16) {
lba = fatStartBlock_ + (cluster >> 8);
} else if (fatType_ == 32) {
lba = fatStartBlock_ + (cluster >> 7);
} else {
goto fail;
}
if (!cacheRawBlock(lba, CACHE_FOR_WRITE)) goto fail;
// store entry
if (fatType_ == 16) {
cacheBuffer_.fat16[cluster & 0XFF] = value;
} else {
cacheBuffer_.fat32[cluster & 0X7F] = value;
}
// mirror second FAT
if (fatCount_ > 1) cacheMirrorBlock_ = lba + blocksPerFat_;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// free a cluster chain
bool SdVolume::freeChain(uint32_t cluster) {
uint32_t next;
// clear free cluster location
allocSearchStart_ = 2;
do {
if (!fatGet(cluster, &next)) goto fail;
// free cluster
if (!fatPut(cluster, 0)) goto fail;
cluster = next;
} while (!isEOC(cluster));
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
/** Volume free space in clusters.
*
* \return Count of free clusters for success or -1 if an error occurs.
*/
int32_t SdVolume::freeClusterCount() {
uint32_t free = 0;
uint16_t n;
uint32_t todo = clusterCount_ + 2;
if (fatType_ == 16) {
n = 256;
} else if (fatType_ == 32) {
n = 128;
} else {
// put FAT12 here
return -1;
}
for (uint32_t lba = fatStartBlock_; todo; todo -= n, lba++) {
if (!cacheRawBlock(lba, CACHE_FOR_READ)) return -1;
if (todo < n) n = todo;
if (fatType_ == 16) {
for (uint16_t i = 0; i < n; i++) {
if (cacheBuffer_.fat16[i] == 0) free++;
}
} else {
for (uint16_t i = 0; i < n; i++) {
if (cacheBuffer_.fat32[i] == 0) free++;
}
}
}
return free;
}
//------------------------------------------------------------------------------
/** Initialize a FAT volume.
*
* \param[in] dev The SD card where the volume is located.
*
* \param[in] part The partition to be used. Legal values for \a part are
* 1-4 to use the corresponding partition on a device formatted with
* a MBR, Master Boot Record, or zero if the device is formatted as
* a super floppy with the FAT boot sector in block zero.
*
* \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 in the specified partition or an I/O error.
*/
bool SdVolume::init(Sd2Card* dev, uint8_t part) {
uint32_t totalBlocks;
uint32_t volumeStartBlock = 0;
fat32_boot_t* fbs;
sdCard_ = dev;
fatType_ = 0;
allocSearchStart_ = 2;
cacheDirty_ = 0; // cacheFlush() will write block if true
cacheMirrorBlock_ = 0;
cacheBlockNumber_ = 0XFFFFFFFF;
// if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table
if (part) {
if (part > 4)goto fail;
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
part_t* p = &cacheBuffer_.mbr.part[part-1];
if ((p->boot & 0X7F) !=0 ||
p->totalSectors < 100 ||
p->firstSector == 0) {
// not a valid partition
goto fail;
}
volumeStartBlock = p->firstSector;
}
if (!cacheRawBlock(volumeStartBlock, CACHE_FOR_READ)) goto fail;
fbs = &cacheBuffer_.fbs32;
if (fbs->bytesPerSector != 512 ||
fbs->fatCount == 0 ||
fbs->reservedSectorCount == 0 ||
fbs->sectorsPerCluster == 0) {
// not valid FAT volume
goto fail;
}
fatCount_ = fbs->fatCount;
blocksPerCluster_ = fbs->sectorsPerCluster;
// determine shift that is same as multiply by blocksPerCluster_
clusterSizeShift_ = 0;
while (blocksPerCluster_ != (1 << clusterSizeShift_)) {
// error if not power of 2
if (clusterSizeShift_++ > 7) goto fail;
}
blocksPerFat_ = fbs->sectorsPerFat16 ?
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
fatStartBlock_ = volumeStartBlock + fbs->reservedSectorCount;
// count for FAT16 zero for FAT32
rootDirEntryCount_ = fbs->rootDirEntryCount;
// directory start for FAT16 dataStart for FAT32
rootDirStart_ = fatStartBlock_ + fbs->fatCount * blocksPerFat_;
// data start for FAT16 and FAT32
dataStartBlock_ = rootDirStart_ + ((32 * fbs->rootDirEntryCount + 511)/512);
// total blocks for FAT16 or FAT32
totalBlocks = fbs->totalSectors16 ?
fbs->totalSectors16 : fbs->totalSectors32;
// total data blocks
clusterCount_ = totalBlocks - (dataStartBlock_ - volumeStartBlock);
// divide by cluster size to get cluster count
clusterCount_ >>= clusterSizeShift_;
// FAT type is determined by cluster count
if (clusterCount_ < 4085) {
fatType_ = 12;
if (!FAT12_SUPPORT) goto fail;
} else if (clusterCount_ < 65525) {
fatType_ = 16;
} else {
rootDirStart_ = fbs->fat32RootCluster;
fatType_ = 32;
}
return true;
fail:
return false;
}
#endif

@ -0,0 +1,214 @@
/* 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/>.
*/
#include "Marlin.h"
#ifdef SDSUPPORT
#ifndef SdVolume_h
#define SdVolume_h
/**
* \file
* \brief SdVolume class
*/
#include "SdFatConfig.h"
#include "Sd2Card.h"
#include "SdFatStructs.h"
//==============================================================================
// 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 Master Boot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
fat_boot_t fbs;
/** Used to access to a cached FAT32 boot sector. */
fat32_boot_t fbs32;
/** Used to access to a cached FAT32 FSINFO sector. */
fat32_fsinfo_t fsinfo;
};
//------------------------------------------------------------------------------
/**
* \class SdVolume
* \brief Access FAT16 and FAT32 volumes on SD and SDHC cards.
*/
class SdVolume {
public:
/** Create an instance of SdVolume */
SdVolume() : 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.
* \return A pointer to the cache buffer or zero if an error occurs.
*/
cache_t* cacheClear() {
if (!cacheFlush()) return 0;
cacheBlockNumber_ = 0XFFFFFFFF;
return &cacheBuffer_;
}
/** 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.
*/
bool init(Sd2Card* dev) { return init(dev, 1) ? true : init(dev, 0);}
bool init(Sd2Card* dev, uint8_t part);
// inline functions that return volume info
/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster() const {return blocksPerCluster_;}
/** \return The number of blocks in one FAT. */
uint32_t blocksPerFat() const {return blocksPerFat_;}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount() const {return clusterCount_;}
/** \return The shift count required to multiply by blocksPerCluster. */
uint8_t clusterSizeShift() const {return clusterSizeShift_;}
/** \return The logical block number for the start of file data. */
uint32_t dataStartBlock() const {return dataStartBlock_;}
/** \return The number of FAT structures on the volume. */
uint8_t fatCount() const {return fatCount_;}
/** \return The logical block number for the start of the first FAT. */
uint32_t fatStartBlock() const {return fatStartBlock_;}
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
uint8_t fatType() const {return fatType_;}
int32_t freeClusterCount();
/** \return The number of entries in the root directory for FAT16 volumes. */
uint32_t rootDirEntryCount() 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() const {return rootDirStart_;}
/** Sd2Card object for this volume
* \return pointer to Sd2Card object.
*/
Sd2Card* sdCard() {return sdCard_;}
/** Debug access to FAT table
*
* \param[in] n cluster number.
* \param[out] v value of entry
* \return true for success or false for failure
*/
bool dbgFat(uint32_t n, uint32_t* v) {return fatGet(n, v);}
//------------------------------------------------------------------------------
private:
// Allow SdBaseFile access to SdVolume private data.
friend class SdBaseFile;
// value for dirty argument in cacheRawBlock to indicate read from cache
static bool const CACHE_FOR_READ = false;
// value for dirty argument in cacheRawBlock to indicate write to cache
static bool const CACHE_FOR_WRITE = true;
#if USE_MULTIPLE_CARDS
cache_t cacheBuffer_; // 512 byte cache for device blocks
uint32_t cacheBlockNumber_; // Logical number of block in the cache
Sd2Card* sdCard_; // Sd2Card object for cache
bool cacheDirty_; // cacheFlush() will write block if true
uint32_t cacheMirrorBlock_; // block number for mirror FAT
#else // USE_MULTIPLE_CARDS
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 bool cacheDirty_; // cacheFlush() will write block if true
static uint32_t cacheMirrorBlock_; // block number for mirror FAT
#endif // USE_MULTIPLE_CARDS
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
//----------------------------------------------------------------------------
bool 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);}
cache_t *cache() {return &cacheBuffer_;}
uint32_t cacheBlockNumber() {return cacheBlockNumber_;}
#if USE_MULTIPLE_CARDS
bool cacheFlush();
bool cacheRawBlock(uint32_t blockNumber, bool dirty);
#else // USE_MULTIPLE_CARDS
static bool cacheFlush();
static bool cacheRawBlock(uint32_t blockNumber, bool dirty);
#endif // USE_MULTIPLE_CARDS
// used by SdBaseFile write to assign cache to SD location
void cacheSetBlockNumber(uint32_t blockNumber, bool dirty) {
cacheDirty_ = dirty;
cacheBlockNumber_ = blockNumber;
}
void cacheSetDirty() {cacheDirty_ |= CACHE_FOR_WRITE;}
bool chainSize(uint32_t beginCluster, uint32_t* size);
bool fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
}
bool freeChain(uint32_t cluster);
bool isEOC(uint32_t cluster) const {
if (FAT12_SUPPORT && fatType_ == 12) return cluster >= FAT12EOC_MIN;
if (fatType_ == 16) return cluster >= FAT16EOC_MIN;
return cluster >= FAT32EOC_MIN;
}
bool readBlock(uint32_t block, uint8_t* dst) {
return sdCard_->readBlock(block, dst);}
bool writeBlock(uint32_t block, const uint8_t* dst) {
return sdCard_->writeBlock(block, dst);
}
//------------------------------------------------------------------------------
// Deprecated functions - suppress cpplint warnings with NOLINT comment
#if ALLOW_DEPRECATED_FUNCTIONS && !defined(DOXYGEN)
public:
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev);
* \param[in] dev The SD card where the volume is located.
* \return true for success or false for failure.
*/
bool init(Sd2Card& dev) {return init(&dev);} // NOLINT
/** \deprecated Use: bool SdVolume::init(Sd2Card* dev, uint8_t vol);
* \param[in] dev The SD card where the volume is located.
* \param[in] part The partition to be used.
* \return true for success or false for failure.
*/
bool init(Sd2Card& dev, uint8_t part) { // NOLINT
return init(&dev, part);
}
#endif // ALLOW_DEPRECATED_FUNCTIONS
};
#endif // SdVolume
#endif

@ -0,0 +1,536 @@
#include "Marlin.h"
#include "cardreader.h"
#include "ultralcd.h"
#include "stepper.h"
#include "temperature.h"
#include "language.h"
#ifdef SDSUPPORT
CardReader::CardReader()
{
filesize = 0;
sdpos = 0;
sdprinting = false;
cardOK = false;
saving = false;
autostart_atmillis=0;
autostart_stilltocheck=true; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
lastnr=0;
//power to SD reader
#if SDPOWER > -1
SET_OUTPUT(SDPOWER);
WRITE(SDPOWER,HIGH);
#endif //SDPOWER
autostart_atmillis=millis()+5000;
}
char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
{
char *pos=buffer;
for (uint8_t i = 0; i < 11; i++)
{
if (p.name[i] == ' ')continue;
if (i == 8)
{
*pos++='.';
}
*pos++=p.name[i];
}
*pos++=0;
return buffer;
}
void CardReader::lsDive(const char *prepend,SdFile parent)
{
dir_t p;
uint8_t cnt=0;
while (parent.readDir(p, longFilename) > 0)
{
if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
{
char path[13*2];
char lfilename[13];
createFilename(lfilename,p);
path[0]=0;
if(strlen(prepend)==0) //avoid leading / if already in prepend
{
strcat(path,"/");
}
strcat(path,prepend);
strcat(path,lfilename);
strcat(path,"/");
//Serial.print(path);
SdFile dir;
if(!dir.open(parent,lfilename, O_READ))
{
if(lsAction==LS_SerialPrint)
{
SERIAL_ECHO_START;
SERIAL_ECHOLN(MSG_SD_CANT_OPEN_SUBDIR);
SERIAL_ECHOLN(lfilename);
}
}
lsDive(path,dir);
//close done automatically by destructor of SdFile
}
else
{
if (p.name[0] == DIR_NAME_FREE) break;
if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue;
if ( p.name[0] == '.')
{
if ( p.name[1] != '.')
continue;
}
if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
filenameIsDir=DIR_IS_SUBDIR(&p);
if(!filenameIsDir)
{
if(p.name[8]!='G') continue;
if(p.name[9]=='~') continue;
}
//if(cnt++!=nr) continue;
createFilename(filename,p);
if(lsAction==LS_SerialPrint)
{
SERIAL_PROTOCOL(prepend);
SERIAL_PROTOCOLLN(filename);
}
else if(lsAction==LS_Count)
{
nrFiles++;
}
else if(lsAction==LS_GetFilename)
{
if(cnt==nrFiles)
return;
cnt++;
}
}
}
}
void CardReader::ls()
{
lsAction=LS_SerialPrint;
if(lsAction==LS_Count)
nrFiles=0;
root.rewind();
lsDive("",root);
}
void CardReader::initsd()
{
cardOK = false;
if(root.isOpen())
root.close();
if (!card.init(SPI_FULL_SPEED,SDSS))
{
//if (!card.init(SPI_HALF_SPEED,SDSS))
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_SD_INIT_FAIL);
}
else if (!volume.init(&card))
{
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_VOL_INIT_FAIL);
}
else if (!root.openRoot(&volume))
{
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_OPENROOT_FAIL);
}
else
{
cardOK = true;
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_SD_CARD_OK);
}
workDir=root;
curDir=&root;
/*
if(!workDir.openRoot(&volume))
{
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
}
*/
}
void CardReader::setroot()
{
/*if(!workDir.openRoot(&volume))
{
SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
}*/
workDir=root;
curDir=&workDir;
}
void CardReader::release()
{
sdprinting = false;
cardOK = false;
}
void CardReader::startFileprint()
{
if(cardOK)
{
sdprinting = true;
}
}
void CardReader::pauseSDPrint()
{
if(sdprinting)
{
sdprinting = false;
}
}
void CardReader::openFile(char* name,bool read)
{
if(!cardOK)
return;
file.close();
sdprinting = false;
SdFile myDir;
curDir=&root;
char *fname=name;
char *dirname_start,*dirname_end;
if(name[0]=='/')
{
dirname_start=strchr(name,'/')+1;
while(dirname_start>0)
{
dirname_end=strchr(dirname_start,'/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
if(dirname_end>0 && dirname_end>dirname_start)
{
char subdirname[13];
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
subdirname[dirname_end-dirname_start]=0;
SERIAL_ECHOLN(subdirname);
if(!myDir.open(curDir,subdirname,O_READ))
{
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(subdirname);
SERIAL_PROTOCOLLNPGM(".");
return;
}
else
;//SERIAL_ECHOLN("dive ok");
curDir=&myDir;
dirname_start=dirname_end+1;
}
else // the reminder after all /fsa/fdsa/ is the filename
{
fname=dirname_start;
//SERIAL_ECHOLN("remaider");
//SERIAL_ECHOLN(fname);
break;
}
}
}
else //relative path
{
curDir=&workDir;
}
if(read)
{
if (file.open(curDir, fname, O_READ))
{
filesize = file.fileSize();
SERIAL_PROTOCOLPGM(MSG_SD_FILE_OPENED);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLPGM(MSG_SD_SIZE);
SERIAL_PROTOCOLLN(filesize);
sdpos = 0;
SERIAL_PROTOCOLLNPGM(MSG_SD_FILE_SELECTED);
LCD_MESSAGE(fname);
}
else
{
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
}
else
{ //write
if (!file.open(curDir, fname, O_CREAT | O_APPEND | O_WRITE | O_TRUNC))
{
SERIAL_PROTOCOLPGM(MSG_SD_OPEN_FILE_FAIL);
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
else
{
saving = true;
SERIAL_PROTOCOLPGM(MSG_SD_WRITE_TO_FILE);
SERIAL_PROTOCOLLN(name);
LCD_MESSAGE(fname);
}
}
}
void CardReader::removeFile(char* name)
{
if(!cardOK)
return;
file.close();
sdprinting = false;
SdFile myDir;
curDir=&root;
char *fname=name;
char *dirname_start,*dirname_end;
if(name[0]=='/')
{
dirname_start=strchr(name,'/')+1;
while(dirname_start>0)
{
dirname_end=strchr(dirname_start,'/');
//SERIAL_ECHO("start:");SERIAL_ECHOLN((int)(dirname_start-name));
//SERIAL_ECHO("end :");SERIAL_ECHOLN((int)(dirname_end-name));
if(dirname_end>0 && dirname_end>dirname_start)
{
char subdirname[13];
strncpy(subdirname, dirname_start, dirname_end-dirname_start);
subdirname[dirname_end-dirname_start]=0;
SERIAL_ECHOLN(subdirname);
if(!myDir.open(curDir,subdirname,O_READ))
{
SERIAL_PROTOCOLPGM("open failed, File: ");
SERIAL_PROTOCOL(subdirname);
SERIAL_PROTOCOLLNPGM(".");
return;
}
else
;//SERIAL_ECHOLN("dive ok");
curDir=&myDir;
dirname_start=dirname_end+1;
}
else // the reminder after all /fsa/fdsa/ is the filename
{
fname=dirname_start;
//SERIAL_ECHOLN("remaider");
//SERIAL_ECHOLN(fname);
break;
}
}
}
else //relative path
{
curDir=&workDir;
}
if (file.remove(curDir, fname))
{
SERIAL_PROTOCOLPGM("File deleted:");
SERIAL_PROTOCOL(fname);
sdpos = 0;
}
else
{
SERIAL_PROTOCOLPGM("Deletion failed, File: ");
SERIAL_PROTOCOL(fname);
SERIAL_PROTOCOLLNPGM(".");
}
}
void CardReader::getStatus()
{
if(cardOK){
SERIAL_PROTOCOLPGM(MSG_SD_PRINTING_BYTE);
SERIAL_PROTOCOL(sdpos);
SERIAL_PROTOCOLPGM("/");
SERIAL_PROTOCOLLN(filesize);
}
else{
SERIAL_PROTOCOLLNPGM(MSG_SD_NOT_PRINTING);
}
}
void CardReader::write_command(char *buf)
{
char* begin = buf;
char* npos = 0;
char* end = buf + strlen(buf) - 1;
file.writeError = false;
if((npos = strchr(buf, 'N')) != NULL)
{
begin = strchr(npos, ' ') + 1;
end = strchr(npos, '*') - 1;
}
end[1] = '\r';
end[2] = '\n';
end[3] = '\0';
file.write(begin);
if (file.writeError)
{
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM(MSG_SD_ERR_WRITE_TO_FILE);
}
}
void CardReader::checkautostart(bool force)
{
if(!force)
{
if(!autostart_stilltocheck)
return;
if(autostart_atmillis<millis())
return;
}
autostart_stilltocheck=false;
if(!cardOK)
{
initsd();
if(!cardOK) //fail
return;
}
char autoname[30];
sprintf(autoname,"auto%i.g",lastnr);
for(int8_t i=0;i<(int8_t)strlen(autoname);i++)
autoname[i]=tolower(autoname[i]);
dir_t p;
root.rewind();
bool found=false;
while (root.readDir(p, NULL) > 0)
{
for(int8_t i=0;i<(int8_t)strlen((char*)p.name);i++)
p.name[i]=tolower(p.name[i]);
//Serial.print((char*)p.name);
//Serial.print(" ");
//Serial.println(autoname);
if(p.name[9]!='~') //skip safety copies
if(strncmp((char*)p.name,autoname,5)==0)
{
char cmd[30];
sprintf(cmd,"M23 %s",autoname);
enquecommand(cmd);
enquecommand("M24");
found=true;
}
}
if(!found)
lastnr=-1;
else
lastnr++;
}
void CardReader::closefile()
{
file.sync();
file.close();
saving = false;
}
void CardReader::getfilename(const uint8_t nr)
{
curDir=&workDir;
lsAction=LS_GetFilename;
nrFiles=nr;
curDir->rewind();
lsDive("",*curDir);
}
uint16_t CardReader::getnrfilenames()
{
curDir=&workDir;
lsAction=LS_Count;
nrFiles=0;
curDir->rewind();
lsDive("",*curDir);
//SERIAL_ECHOLN(nrFiles);
return nrFiles;
}
void CardReader::chdir(const char * relpath)
{
SdFile newfile;
SdFile *parent=&root;
if(workDir.isOpen())
parent=&workDir;
if(!newfile.open(*parent,relpath, O_READ))
{
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_SD_CANT_ENTER_SUBDIR);
SERIAL_ECHOLN(relpath);
}
else
{
workDirParentParent=workDirParent;
workDirParent=*parent;
workDir=newfile;
}
}
void CardReader::updir()
{
if(!workDir.isRoot())
{
workDir=workDirParent;
workDirParent=workDirParentParent;
}
}
void CardReader::printingHasFinished()
{
st_synchronize();
quickStop();
sdprinting = false;
if(SD_FINISHED_STEPPERRELEASE)
{
//finishAndDisableSteppers();
enquecommand(SD_FINISHED_RELEASECOMMAND);
}
autotempShutdown();
}
#endif //SDSUPPORT

@ -0,0 +1,76 @@
#ifndef CARDREADER_H
#define CARDREADER_H
#ifdef SDSUPPORT
#include "SdFile.h"
enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename};
class CardReader
{
public:
CardReader();
void initsd();
void write_command(char *buf);
//files auto[0-9].g on the sd card are performed in a row
//this is to delay autostart and hence the initialisaiton of the sd card to some seconds after the normal init, so the device is available quick after a reset
void checkautostart(bool x);
void openFile(char* name,bool read);
void removeFile(char* name);
void closefile();
void release();
void startFileprint();
void pauseSDPrint();
void getStatus();
void printingHasFinished();
void getfilename(const uint8_t nr);
uint16_t getnrfilenames();
void ls();
void chdir(const char * relpath);
void updir();
void setroot();
FORCE_INLINE bool eof() { return sdpos>=filesize ;};
FORCE_INLINE int16_t get() { sdpos = file.curPosition();return (int16_t)file.read();};
FORCE_INLINE void setIndex(long index) {sdpos = index;file.seekSet(index);};
FORCE_INLINE uint8_t percentDone(){if(!sdprinting) return 0; if(filesize) return sdpos*100/filesize; else return 0;};
FORCE_INLINE char* getWorkDirName(){workDir.getFilename(filename);return filename;};
public:
bool saving;
bool sdprinting ;
bool cardOK ;
char filename[13];
char longFilename[LONG_FILENAME_LENGTH];
bool filenameIsDir;
int lastnr; //last number of the autostart;
private:
SdFile root,*curDir,workDir,workDirParent,workDirParentParent;
Sd2Card card;
SdVolume volume;
SdFile file;
uint32_t filesize;
//int16_t n;
unsigned long autostart_atmillis;
uint32_t sdpos ;
bool autostart_stilltocheck; //the sd start is delayed, because otherwise the serial cannot answer fast enought to make contact with the hostsoftware.
LsAction lsAction; //stored for recursion.
int16_t nrFiles; //counter for the files in the current directory and recycled as position counter for getting the nrFiles'th name in the directory.
char* diveDirName;
void lsDive(const char *prepend,SdFile parent);
};
#define IS_SD_PRINTING (card.sdprinting)
#else
#define IS_SD_PRINTING (false)
#endif //SDSUPPORT
#endif

@ -0,0 +1,127 @@
#!/usr/bin/python
#
# Creates a C code lookup table for doing ADC to temperature conversion
# on a microcontroller
# based on: http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html
"""Thermistor Value Lookup Table Generator
Generates lookup to temperature values for use in a microcontroller in C format based on:
http://hydraraptor.blogspot.com/2007/10/measuring-temperature-easy-way.html
The main use is for Arduino programs that read data from the circuit board described here:
http://make.rrrf.org/ts-1.0
Usage: python createTemperatureLookup.py [options]
Options:
-h, --help show this help
--r0=... thermistor rating where # is the ohm rating of the thermistor at t0 (eg: 10K = 10000)
--t0=... thermistor temp rating where # is the temperature in Celsuis to get r0 (from your datasheet)
--beta=... thermistor beta rating. see http://reprap.org/bin/view/Main/MeasuringThermistorBeta
--r1=... R1 rating where # is the ohm rating of R1 (eg: 10K = 10000)
--r2=... R2 rating where # is the ohm rating of R2 (eg: 10K = 10000)
--num-temps=... the number of temperature points to calculate (default: 20)
--max-adc=... the max ADC reading to use. if you use R1, it limits the top value for the thermistor circuit, and thus the possible range of ADC values
"""
from math import *
import sys
import getopt
class Thermistor:
"Class to do the thermistor maths"
def __init__(self, r0, t0, beta, r1, r2):
self.r0 = r0 # stated resistance, e.g. 10K
self.t0 = t0 + 273.15 # temperature at stated resistance, e.g. 25C
self.beta = beta # stated beta, e.g. 3500
self.vadc = 5.0 # ADC reference
self.vcc = 5.0 # supply voltage to potential divider
self.k = r0 * exp(-beta / self.t0) # constant part of calculation
if r1 > 0:
self.vs = r1 * self.vcc / (r1 + r2) # effective bias voltage
self.rs = r1 * r2 / (r1 + r2) # effective bias impedance
else:
self.vs = self.vcc # effective bias voltage
self.rs = r2 # effective bias impedance
def temp(self,adc):
"Convert ADC reading into a temperature in Celcius"
v = adc * self.vadc / 1024 # convert the 10 bit ADC value to a voltage
r = self.rs * v / (self.vs - v) # resistance of thermistor
return (self.beta / log(r / self.k)) - 273.15 # temperature
def setting(self, t):
"Convert a temperature into a ADC value"
r = self.r0 * exp(self.beta * (1 / (t + 273.15) - 1 / self.t0)) # resistance of the thermistor
v = self.vs * r / (self.rs + r) # the voltage at the potential divider
return round(v / self.vadc * 1024) # the ADC reading
def main(argv):
r0 = 10000;
t0 = 25;
beta = 3947;
r1 = 680;
r2 = 1600;
num_temps = int(20);
try:
opts, args = getopt.getopt(argv, "h", ["help", "r0=", "t0=", "beta=", "r1=", "r2="])
except getopt.GetoptError:
usage()
sys.exit(2)
for opt, arg in opts:
if opt in ("-h", "--help"):
usage()
sys.exit()
elif opt == "--r0":
r0 = int(arg)
elif opt == "--t0":
t0 = int(arg)
elif opt == "--beta":
beta = int(arg)
elif opt == "--r1":
r1 = int(arg)
elif opt == "--r2":
r2 = int(arg)
if r1:
max_adc = int(1023 * r1 / (r1 + r2));
else:
max_adc = 1023
increment = int(max_adc/(num_temps-1));
t = Thermistor(r0, t0, beta, r1, r2)
adcs = range(1, max_adc, increment);
# adcs = [1, 20, 25, 30, 35, 40, 45, 50, 60, 70, 80, 90, 100, 110, 130, 150, 190, 220, 250, 300]
first = 1
print "// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)"
print "// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)"
print "// ./createTemperatureLookup.py --r0=%s --t0=%s --r1=%s --r2=%s --beta=%s --max-adc=%s" % (r0, t0, r1, r2, beta, max_adc)
print "// r0: %s" % (r0)
print "// t0: %s" % (t0)
print "// r1: %s" % (r1)
print "// r2: %s" % (r2)
print "// beta: %s" % (beta)
print "// max adc: %s" % (max_adc)
print "#define NUMTEMPS %s" % (len(adcs))
print "short temptable[NUMTEMPS][2] = {"
counter = 0
for adc in adcs:
counter = counter +1
if counter == len(adcs):
print " {%s, %s}" % (adc, int(t.temp(adc)))
else:
print " {%s, %s}," % (adc, int(t.temp(adc)))
print "};"
def usage():
print __doc__
if __name__ == "__main__":
main(sys.argv[1:])

@ -0,0 +1,50 @@
#!/usr/bin/env python
""" Generate the stepper delay lookup table for Marlin firmware. """
import argparse
__author__ = "Ben Gamari <bgamari@gmail.com>"
__copyright__ = "Copyright 2012, Ben Gamari"
__license__ = "GPL"
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-f', '--cpu-freq', type=int, default=16, help='CPU clockrate in MHz (default=16)')
parser.add_argument('-d', '--divider', type=int, default=8, help='Timer/counter pre-scale divider (default=8)')
args = parser.parse_args()
cpu_freq = args.cpu_freq * 1000000
timer_freq = cpu_freq / args.divider
print "#ifndef SPEED_LOOKUPTABLE_H"
print "#define SPEED_LOOKUPTABLE_H"
print
print '#include "Marlin.h"'
print
print "const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {"
a = [ timer_freq / ((i*256)+(args.cpu_freq*2)) for i in range(256) ]
b = [ a[i] - a[i+1] for i in range(255) ]
b.append(b[-1])
for i in range(32):
print " ",
for j in range(8):
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
print
print "};"
print
print "const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {"
a = [ timer_freq / ((i*8)+(args.cpu_freq*2)) for i in range(256) ]
b = [ a[i] - a[i+1] for i in range(255) ]
b.append(b[-1])
for i in range(32):
print " ",
for j in range(8):
print "{%d, %d}," % (a[8*i+j], b[8*i+j]),
print
print "};"
print
print "#endif"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,498 @@
#ifndef LANGUAGE_H
#define LANGUAGE_H
// NOTE: IF YOU CHANGE THIS FILE / MERGE THIS FILE WITH CHANGES
//
// ==> ALWAYS TRY TO COMPILE MARLIN WITH/WITHOUT "ULTIPANEL" / "ULTRALCD" / "SDSUPPORT" #define IN "Configuration.h"
// ==> ALSO TRY ALL AVAILABLE "LANGUAGE_CHOICE" OPTIONS
// Languages
// 1 English
// 2 -
// 3 French (Waiting translation)
// 4 German
// 5 Spanish
// 6 Etc
#define LANGUAGE_CHOICE 1 // Pick your language from the list above
#define PROTOCOL_VERSION "1.0"
#if MOTHERBOARD == 7 || MOTHERBOARD == 71
#define MACHINE_NAME "Ultimaker"
#define FIRMWARE_URL "http://firmware.ultimaker.com"
#else
#define MACHINE_NAME "Mendel"
#define FIRMWARE_URL "http://www.mendel-parts.com"
#endif
#define STRINGIFY_(n) #n
#define STRINGIFY(n) STRINGIFY_(n)
#if LANGUAGE_CHOICE == 1
// LCD Menu Messages
#define WELCOME_MSG MACHINE_NAME " Ready."
#define MSG_SD_INSERTED "Card inserted"
#define MSG_SD_REMOVED "Card removed"
#define MSG_MAIN " Main \003"
#define MSG_AUTOSTART " Autostart"
#define MSG_DISABLE_STEPPERS " Disable Steppers"
#define MSG_AUTO_HOME " Auto Home"
#define MSG_SET_ORIGIN " Set Origin"
#define MSG_PREHEAT_PLA " Preheat PLA"
#define MSG_PREHEAT_PLA_SETTINGS " Preheat PLA Setting"
#define MSG_PREHEAT_ABS " Preheat ABS"
#define MSG_PREHEAT_ABS_SETTINGS " Preheat ABS Setting"
#define MSG_COOLDOWN " Cooldown"
#define MSG_EXTRUDE " Extrude"
#define MSG_RETRACT " Retract"
#define MSG_PREHEAT_PLA " Preheat PLA"
#define MSG_PREHEAT_ABS " Preheat ABS"
#define MSG_MOVE_AXIS " Move Axis \x7E"
#define MSG_SPEED " Speed:"
#define MSG_NOZZLE " \002Nozzle:"
#define MSG_NOZZLE1 " \002Nozzle2:"
#define MSG_NOZZLE2 " \002Nozzle3:"
#define MSG_BED " \002Bed:"
#define MSG_FAN_SPEED " Fan speed:"
#define MSG_FLOW " Flow:"
#define MSG_CONTROL " Control \003"
#define MSG_MIN " \002 Min:"
#define MSG_MAX " \002 Max:"
#define MSG_FACTOR " \002 Fact:"
#define MSG_AUTOTEMP " Autotemp:"
#define MSG_ON "On "
#define MSG_OFF "Off"
#define MSG_PID_P " PID-P: "
#define MSG_PID_I " PID-I: "
#define MSG_PID_D " PID-D: "
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
#define MSG_Z "z:"
#define MSG_E "e:"
#define MSG_VMIN " Vmin:"
#define MSG_VTRAV_MIN " VTrav min:"
#define MSG_AMAX " Amax "
#define MSG_A_RETRACT " A-retract:"
#define MSG_XSTEPS " Xsteps/mm:"
#define MSG_YSTEPS " Ysteps/mm:"
#define MSG_ZSTEPS " Zsteps/mm:"
#define MSG_ESTEPS " Esteps/mm:"
#define MSG_MAIN_WIDE " Main \003"
#define MSG_RECTRACT_WIDE " Rectract \x7E"
#define MSG_TEMPERATURE_WIDE " Temperature \x7E"
#define MSG_TEMPERATURE_RTN " Temperature \003"
#define MSG_MOTION_WIDE " Motion \x7E"
#define MSG_STORE_EPROM " Store memory"
#define MSG_LOAD_EPROM " Load memory"
#define MSG_RESTORE_FAILSAFE " Restore Failsafe"
#define MSG_REFRESH "\004Refresh"
#define MSG_WATCH " Watch \003"
#define MSG_PREPARE " Prepare \x7E"
#define MSG_PREPARE_ALT " Prepare \003"
#define MSG_CONTROL_ARROW " Control \x7E"
#define MSG_RETRACT_ARROW " Retract \x7E"
#define MSG_TUNE " Tune \x7E"
#define MSG_PAUSE_PRINT " Pause Print \x7E"
#define MSG_RESUME_PRINT " Resume Print \x7E"
#define MSG_STOP_PRINT " Stop Print \x7E"
#define MSG_CARD_MENU " Card Menu \x7E"
#define MSG_NO_CARD " No Card"
#define MSG_DWELL "Sleep..."
#define MSG_USERWAIT "Wait for user..."
#define MSG_NO_MOVE "No move."
#define MSG_PART_RELEASE "Partial Release"
#define MSG_KILLED "KILLED. "
#define MSG_STOPPED "STOPPED. "
#define MSG_STEPPER_RELEASED "Released."
#define MSG_CONTROL_RETRACT " Retract mm:"
#define MSG_CONTROL_RETRACTF " Retract F:"
#define MSG_CONTROL_RETRACT_ZLIFT " Hop mm:"
#define MSG_CONTROL_RETRACT_RECOVER " UnRet +mm:"
#define MSG_CONTROL_RETRACT_RECOVERF " UnRet F:"
#define MSG_AUTORETRACT " AutoRetr.:"
#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Something is wrong in the MenuStructure."
// Serial Console Messages
#define MSG_Enqueing "enqueing \""
#define MSG_POWERUP "PowerUp"
#define MSG_EXTERNAL_RESET " External Reset"
#define MSG_BROWNOUT_RESET " Brown out Reset"
#define MSG_WATCHDOG_RESET " Watchdog Reset"
#define MSG_SOFTWARE_RESET " Software Reset"
#define MSG_MARLIN "Marlin "
#define MSG_AUTHOR " | Author: "
#define MSG_CONFIGURATION_VER " Last Updated: "
#define MSG_FREE_MEMORY " Free Memory: "
#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
#define MSG_OK "ok"
#define MSG_FILE_SAVED "Done saving file."
#define MSG_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line:"
#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line:"
#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line:"
#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line:"
#define MSG_FILE_PRINTED "Done printing file"
#define MSG_BEGIN_FILE_LIST "Begin file list"
#define MSG_END_FILE_LIST "End file list"
#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder "
#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder "
#define MSG_ERR_NO_THERMISTORS "No thermistors - no temp"
#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder "
#define MSG_HEATING "Heating..."
#define MSG_HEATING_COMPLETE "Heating done."
#define MSG_BED_HEATING "Bed Heating."
#define MSG_BED_DONE "Bed done."
#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n"
#define MSG_COUNT_X " Count X:"
#define MSG_ERR_KILLED "Printer halted. kill() called !!"
#define MSG_ERR_STOPPED "Printer stopped deu to errors. Fix the error and use M999 to restart!. (Temperature is reset. Set it before restarting)"
#define MSG_RESEND "Resend:"
#define MSG_UNKNOWN_COMMAND "Unknown command:\""
#define MSG_ACTIVE_EXTRUDER "Active Extruder: "
#define MSG_INVALID_EXTRUDER "Invalid extruder"
#define MSG_X_MIN "x_min:"
#define MSG_X_MAX "x_max:"
#define MSG_Y_MIN "y_min:"
#define MSG_Y_MAX "y_max:"
#define MSG_Z_MIN "z_min:"
#define MSG_Z_MAX "z_max:"
#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir"
#define MSG_SD_INIT_FAIL "SD init fail"
#define MSG_SD_VOL_INIT_FAIL "volume.init failed"
#define MSG_SD_OPENROOT_FAIL "openRoot failed"
#define MSG_SD_CARD_OK "SD card ok"
#define MSG_SD_WORKDIR_FAIL "workDir open failed"
#define MSG_SD_OPEN_FILE_FAIL "open failed, File: "
#define MSG_SD_FILE_OPENED "File opened:"
#define MSG_SD_SIZE " Size:"
#define MSG_SD_FILE_SELECTED "File selected"
#define MSG_SD_WRITE_TO_FILE "Writing to file: "
#define MSG_SD_PRINTING_BYTE "SD printing byte "
#define MSG_SD_NOT_PRINTING "Not SD printing"
#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file"
#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir:"
#define MSG_STEPPER_TO_HIGH "Steprate to high : "
#define MSG_ENDSTOPS_HIT "endstops hit: "
#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
#define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
#endif
#if LANGUAGE_CHOICE == 4
// LCD Menu Messages
#define WELCOME_MSG MACHINE_NAME " Bereit."
#define MSG_SD_INSERTED "SDKarte erkannt"
#define MSG_SD_REMOVED "SDKarte entfernt"
#define MSG_MAIN " Hauptmneü \003"
#define MSG_AUTOSTART " Autostart"
#define MSG_DISABLE_STEPPERS " Stepper abschalten"
#define MSG_AUTO_HOME " Auto Nullpunkt"
#define MSG_SET_ORIGIN " Setze Nullpunkt"
#define MSG_PREHEAT_PLA " Vorwärmen PLA"
#define MSG_PREHEAT_PLA_SETTINGS " Vorwärmen PLA Einstellungen"
#define MSG_PREHEAT_ABS " Vorwärmen ABS"
#define MSG_PREHEAT_ABS_SETTINGS " Vorwärmen ABS Einstellungen"
#define MSG_COOLDOWN " Abkühlen"
#define MSG_EXTRUDE " Extrude"
#define MSG_RETRACT " Retract"
#define MSG_MOVE_AXIS " Achsen bewegen\x7E"
#define MSG_SPEED " Geschw:"
#define MSG_NOZZLE " \002Düse:"
#define MSG_NOZZLE1 " \002Düse2:"
#define MSG_NOZZLE2 " \002Düse3:"
#define MSG_BED " \002Bett:"
#define MSG_FAN_SPEED " Lüftergeschw.:"
#define MSG_FLOW " Fluß:"
#define MSG_CONTROL " Einstellungen \003"
#define MSG_MIN " \002 Min:"
#define MSG_MAX " \002 Max:"
#define MSG_FACTOR " \002 Faktor:"
#define MSG_AUTOTEMP " AutoTemp:"
#define MSG_ON "Ein "
#define MSG_OFF "Aus "
#define MSG_PID_P " PID-P: "
#define MSG_PID_I " PID-I: "
#define MSG_PID_D " PID-D: "
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
#define MSG_Z "z:"
#define MSG_E "e:"
#define MSG_VMIN " Vmin:"
#define MSG_VTRAV_MIN " VTrav min:"
#define MSG_AMAX " Amax "
#define MSG_A_RETRACT " A-Retract:"
#define MSG_XSTEPS " Xsteps/mm:"
#define MSG_YSTEPS " Ysteps/mm:"
#define MSG_ZSTEPS " Zsteps/mm:"
#define MSG_ESTEPS " Esteps/mm:"
#define MSG_MAIN_WIDE " Hauptmenü \003"
#define MSG_RECTRACT_WIDE " Rectract \x7E"
#define MSG_WATCH " Beobachten \003"
#define MSG_TEMPERATURE_WIDE " Temperatur \x7E"
#define MSG_TEMPERATURE_RTN " Temperatur \003"
#define MSG_MOTION_WIDE " Bewegung \x7E"
#define MSG_STORE_EPROM " EPROM speichern"
#define MSG_LOAD_EPROM " EPROM laden"
#define MSG_RESTORE_FAILSAFE " Standardkonfig."
#define MSG_REFRESH "\004Aktualisieren"
#define MSG_PREPARE " Vorbereitung \x7E"
#define MSG_PREPARE_ALT " Vorbereitung \003"
#define MSG_CONTROL_ARROW " Einstellungen \x7E"
#define MSG_TUNE " Justierung \x7E"
#define MSG_PAUSE_PRINT " Druck anhalten\x7E"
#define MSG_RESUME_PRINT " Druck fortsetz\x7E"
#define MSG_STOP_PRINT " Druck stoppen \x7E"
#define MSG_CARD_MENU " SDKarten Menü \x7E"
#define MSG_NO_CARD " Keine SDKarte"
#define MSG_DWELL "Warten..."
#define MSG_USERWAIT "Warte auf Nutzer..."
#define MSG_NO_MOVE "Kein Zug."
#define MSG_PART_RELEASE "Stepper tlw frei"
#define MSG_KILLED "KILLED"
#define MSG_STOPPED "GESTOPPT"
#define MSG_STEPPER_RELEASED "Stepper frei"
#define MSG_CONTROL_RETRACT " Retract mm:"
#define MSG_CONTROL_RETRACTF " Retract F:"
#define MSG_CONTROL_RETRACT_ZLIFT " Hop mm:"
#define MSG_CONTROL_RETRACT_RECOVER " UnRet +mm:"
#define MSG_CONTROL_RETRACT_RECOVERF " UnRet F:"
#define MSG_AUTORETRACT " AutoRetr.:"
#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Fehler in Menüstruktur."
// Serial Console Messages
#define MSG_Enqueing "enqueing \""
#define MSG_POWERUP "PowerUp"
#define MSG_EXTERNAL_RESET " External Reset"
#define MSG_BROWNOUT_RESET " Brown out Reset"
#define MSG_WATCHDOG_RESET " Watchdog Reset"
#define MSG_SOFTWARE_RESET " Software Reset"
#define MSG_MARLIN "Marlin: "
#define MSG_AUTHOR " | Author: "
#define MSG_CONFIGURATION_VER " Last Updated: "
#define MSG_FREE_MEMORY " Free Memory: "
#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
#define MSG_OK "ok"
#define MSG_FILE_SAVED "Done saving file."
#define MSG_ERR_LINE_NO "Line Number is not Last Line Number+1, Last Line:"
#define MSG_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line:"
#define MSG_ERR_NO_CHECKSUM "No Checksum with line number, Last Line:"
#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No Line Number with checksum, Last Line:"
#define MSG_FILE_PRINTED "Done printing file"
#define MSG_BEGIN_FILE_LIST "Begin file list"
#define MSG_END_FILE_LIST "End file list"
#define MSG_M104_INVALID_EXTRUDER "M104 Invalid extruder "
#define MSG_M105_INVALID_EXTRUDER "M105 Invalid extruder "
#define MSG_ERR_NO_THERMISTORS "No thermistors - no temp"
#define MSG_M109_INVALID_EXTRUDER "M109 Invalid extruder "
#define MSG_HEATING "Heating..."
#define MSG_HEATING_COMPLETE "Heating done."
#define MSG_BED_HEATING "Bed Heating."
#define MSG_BED_DONE "Bed done."
#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n"
#define MSG_COUNT_X " Count X:"
#define MSG_ERR_KILLED "Printer halted. kill() called !!"
#define MSG_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart!"
#define MSG_RESEND "Resend:"
#define MSG_UNKNOWN_COMMAND "Unknown command:\""
#define MSG_ACTIVE_EXTRUDER "Active Extruder: "
#define MSG_INVALID_EXTRUDER "Invalid extruder"
#define MSG_X_MIN "x_min:"
#define MSG_X_MAX "x_max:"
#define MSG_Y_MIN "y_min:"
#define MSG_Y_MAX "y_max:"
#define MSG_Z_MIN "z_min:"
#define MSG_Z_MAX "z_max:"
#define MSG_SD_CANT_OPEN_SUBDIR "Cannot open subdir"
#define MSG_SD_INIT_FAIL "SD init fail"
#define MSG_SD_VOL_INIT_FAIL "volume.init failed"
#define MSG_SD_OPENROOT_FAIL "openRoot failed"
#define MSG_SD_CARD_OK "SD card ok"
#define MSG_SD_WORKDIR_FAIL "workDir open failed"
#define MSG_SD_OPEN_FILE_FAIL "open failed, File: "
#define MSG_SD_FILE_OPENED "File opened:"
#define MSG_SD_SIZE " Size:"
#define MSG_SD_FILE_SELECTED "File selected"
#define MSG_SD_WRITE_TO_FILE "Writing to file: "
#define MSG_SD_PRINTING_BYTE "SD printing byte "
#define MSG_SD_NOT_PRINTING "Not SD printing"
#define MSG_SD_ERR_WRITE_TO_FILE "error writing to file"
#define MSG_SD_CANT_ENTER_SUBDIR "Cannot enter subdir:"
#define MSG_STEPPER_TO_HIGH "Steprate to high : "
#define MSG_ENDSTOPS_HIT "endstops hit: "
#define MSG_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
#define MSG_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
#endif
#if LANGUAGE_CHOICE == 5
// LCD Menu Messages
#define WELCOME_MSG MACHINE_NAME " Lista."
#define MSG_SD_INSERTED "Tarjeta SD Colocada"
#define MSG_SD_REMOVED "Tarjeta SD Retirada"
#define MSG_MAIN " Menu Principal \003"
#define MSG_AUTOSTART " Autostart"
#define MSG_DISABLE_STEPPERS " Apagar Motores"
#define MSG_AUTO_HOME " Llevar Ejes al Cero"
#define MSG_SET_ORIGIN " Establecer Cero"
#define MSG_COOLDOWN " Enfriar"
#define MSG_EXTRUDE " Extruir"
#define MSG_RETRACT " Retract"
#define MSG_PREHEAT_PLA " Precalentar PLA"
#define MSG_PREHEAT_PLA_SETTINGS " Precalentar PLA Setting"
#define MSG_PREHEAT_ABS " Precalentar ABS"
#define MSG_PREHEAT_ABS_SETTINGS " Precalentar ABS Setting"
#define MSG_MOVE_AXIS " Mover Ejes \x7E"
#define MSG_SPEED " Velocidad:"
#define MSG_NOZZLE " \002Nozzle:"
#define MSG_NOZZLE1 " \002Nozzle2:"
#define MSG_NOZZLE2 " \002Nozzle3:"
#define MSG_BED " \002Base:"
#define MSG_FAN_SPEED " Ventilador:"
#define MSG_FLOW " Flujo:"
#define MSG_CONTROL " Control \003"
#define MSG_MIN " \002 Min:"
#define MSG_MAX " \002 Max:"
#define MSG_FACTOR " \002 Fact:"
#define MSG_AUTOTEMP " Autotemp:"
#define MSG_ON "On "
#define MSG_OFF "Off"
#define MSG_PID_P " PID-P: "
#define MSG_PID_I " PID-I: "
#define MSG_PID_D " PID-D: "
#define MSG_PID_C " PID-C: "
#define MSG_ACC " Acc:"
#define MSG_VXY_JERK " Vxy-jerk: "
#define MSG_VMAX " Vmax "
#define MSG_X "x:"
#define MSG_Y "y:"
#define MSG_Z "z:"
#define MSG_E "e:"
#define MSG_VMIN " Vmin:"
#define MSG_VTRAV_MIN " VTrav min:"
#define MSG_AMAX " Amax "
#define MSG_A_RETRACT " A-retrac.:"
#define MSG_XSTEPS " Xpasos/mm:"
#define MSG_YSTEPS " Ypasos/mm:"
#define MSG_ZSTEPS " Zpasos/mm:"
#define MSG_ESTEPS " Epasos/mm:"
#define MSG_MAIN_WIDE " Menu Principal \003"
#define MSG_RECTRACT_WIDE " Retraer \x7E"
#define MSG_TEMPERATURE_WIDE " Temperatura \x7E"
#define MSG_TEMPERATURE_RTN " Temperatura \003"
#define MSG_MOTION_WIDE " Movimiento \x7E"
#define MSG_STORE_EPROM " Guardar Memoria"
#define MSG_LOAD_EPROM " Cargar Memoria"
#define MSG_RESTORE_FAILSAFE " Rest. de emergencia"
#define MSG_REFRESH "\004Volver a cargar"
#define MSG_WATCH " Monitorizar \003"
#define MSG_PREPARE " Preparar \x7E"
#define MSG_PREPARE_ALT " Preparar \003"
#define MSG_CONTROL_ARROW " Control \x7E"
#define MSG_RETRACT_ARROW " Control \x7E"
#define MSG_TUNE " Ajustar \x7E"
#define MSG_PAUSE_PRINT " Pause Print \x7E"
#define MSG_RESUME_PRINT " Resume Print \x7E"
#define MSG_STOP_PRINT " Detener Impresion \x7E"
#define MSG_CARD_MENU " Menu de SD \x7E"
#define MSG_NO_CARD " No hay Tarjeta SD"
#define MSG_DWELL "Reposo..."
#define MSG_USERWAIT "Esperando Ordenes..."
#define MSG_NO_MOVE "Sin movimiento"
#define MSG_PART_RELEASE "Desacople Parcial"
#define MSG_KILLED "PARADA DE EMERGENCIA. "
#define MSG_STOPPED "PARADA. "
#define MSG_STEPPER_RELEASED "Desacoplada."
#define MSG_CONTROL_RETRACT " Retraer mm:"
#define MSG_CONTROL_RETRACTF " Retraer F:"
#define MSG_CONTROL_RETRACT_ZLIFT " Levantar mm:"
#define MSG_CONTROL_RETRACT_RECOVER " DesRet +mm:"
#define MSG_CONTROL_RETRACT_RECOVERF " DesRet F:"
#define MSG_AUTORETRACT " AutoRetr.:"
#define MSG_SERIAL_ERROR_MENU_STRUCTURE "Hay un error en la estructura del menu"
// Serial Console Messages
#define MSG_Enqueing "En cola \""
#define MSG_POWERUP "PowerUp"
#define MSG_EXTERNAL_RESET " Reset Externo"
#define MSG_BROWNOUT_RESET " Reset por Voltaje Incorrecto"
#define MSG_WATCHDOG_RESET " Reset por Bloqueo"
#define MSG_SOFTWARE_RESET " Reset por Software"
#define MSG_MARLIN "Marlin "
#define MSG_AUTHOR " | Autor: "
#define MSG_CONFIGURATION_VER " Ultima actualizacion: "
#define MSG_FREE_MEMORY " Memoria libre: "
#define MSG_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
#define MSG_OK "ok"
#define MSG_FILE_SAVED "Guardado."
#define MSG_ERR_LINE_NO "El Numero de Linea no es igual al Ultimo Numero de Linea+1, Ultima Linea:"
#define MSG_ERR_CHECKSUM_MISMATCH "el checksum no coincide, Ultima Linea:"
#define MSG_ERR_NO_CHECKSUM "No se pudo hallar el Checksum con el numero de linea, Ultima Linea:"
#define MSG_ERR_NO_LINENUMBER_WITH_CHECKSUM "No se hallo el Numero de Linea con el Checksum, Ultima Linea:"
#define MSG_FILE_PRINTED "Impresion terminada"
#define MSG_BEGIN_FILE_LIST "Comienzo de la lista de archivos"
#define MSG_END_FILE_LIST "Fin de la lista de archivos"
#define MSG_M104_INVALID_EXTRUDER "M104 Extrusor Invalido "
#define MSG_M105_INVALID_EXTRUDER "M105 Extrusor Invalido "
#define MSG_ERR_NO_THERMISTORS "No hay termistores - no temp"
#define MSG_M109_INVALID_EXTRUDER "M109 Extrusor Invalido "
#define MSG_HEATING "Calentando..."
#define MSG_HEATING_COMPLETE "Calentamiento Hecho."
#define MSG_BED_HEATING "Calentando la base."
#define MSG_BED_DONE "Base Caliente."
#define MSG_M115_REPORT "FIRMWARE_NAME:Marlin V1; Sprinter/grbl mashup for gen6 FIRMWARE_URL:" FIRMWARE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) "\n"
#define MSG_COUNT_X " Cuenta X:"
#define MSG_ERR_KILLED "¡¡Impresora Parada con kill()!!"
#define MSG_ERR_STOPPED "¡Impresora parada por errores. Arregle el error y use M999 Para reiniciar!. (La temperatura se reestablece. Ajustela antes de continuar)"
#define MSG_RESEND "Reenviar:"
#define MSG_UNKNOWN_COMMAND "Comando Desconocido:\""
#define MSG_ACTIVE_EXTRUDER "Extrusor Activo: "
#define MSG_INVALID_EXTRUDER "Extrusor Invalido"
#define MSG_X_MIN "x_min:"
#define MSG_X_MAX "x_max:"
#define MSG_Y_MIN "y_min:"
#define MSG_Y_MAX "y_max:"
#define MSG_Z_MIN "z_min:"
#define MSG_Z_MAX "z_max:"
#define MSG_SD_CANT_OPEN_SUBDIR "No se pudo abrir la subcarpeta."
#define MSG_SD_INIT_FAIL "Fallo al iniciar la SD"
#define MSG_SD_VOL_INIT_FAIL "Fallo al montar el volumen"
#define MSG_SD_OPENROOT_FAIL "Fallo al abrir la carpeta raiz"
#define MSG_SD_CARD_OK "Tarjeta SD OK"
#define MSG_SD_WORKDIR_FAIL "Fallo al abrir la carpeta de trabajo"
#define MSG_SD_OPEN_FILE_FAIL "Error al abrir, Archivo: "
#define MSG_SD_FILE_OPENED "Archivo abierto:"
#define MSG_SD_SIZE " Tamaño:"
#define MSG_SD_FILE_SELECTED "Archivo Seleccionado"
#define MSG_SD_WRITE_TO_FILE "Escribiendo en el archivo: "
#define MSG_SD_PRINTING_BYTE "SD imprimiendo el byte "
#define MSG_SD_NOT_PRINTING "No se esta imprimiendo con SD"
#define MSG_SD_ERR_WRITE_TO_FILE "Error al escribir en el archivo"
#define MSG_SD_CANT_ENTER_SUBDIR "No se puede entrar en la carpeta:"
#define MSG_STEPPER_TO_HIGH "Steprate demasiado alto : "
#define MSG_ENDSTOPS_HIT "Se ha tocado el fin de carril: "
#define MSG_ERR_COLD_EXTRUDE_STOP " extrusion fria evitada"
#define MSG_ERR_LONG_EXTRUDE_STOP " extrusion demasiado larga evitada"
#endif
#endif // ifndef LANGUAGE_H

@ -0,0 +1,137 @@
/*
motion_control.c - high level interface for issuing motion commands
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Marlin.h"
#include "stepper.h"
#include "planner.h"
// The arc is approximated by generating a huge number of tiny, linear segments. The length of each
// segment is configured in settings.mm_per_arc_segment.
void mc_arc(float *position, float *target, float *offset, uint8_t axis_0, uint8_t axis_1,
uint8_t axis_linear, float feed_rate, float radius, uint8_t isclockwise, uint8_t extruder)
{
// int acceleration_manager_was_enabled = plan_is_acceleration_manager_enabled();
// plan_set_acceleration_manager_enabled(false); // disable acceleration management for the duration of the arc
float center_axis0 = position[axis_0] + offset[axis_0];
float center_axis1 = position[axis_1] + offset[axis_1];
float linear_travel = target[axis_linear] - position[axis_linear];
float extruder_travel = target[E_AXIS] - position[E_AXIS];
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
float r_axis1 = -offset[axis_1];
float rt_axis0 = target[axis_0] - center_axis0;
float rt_axis1 = target[axis_1] - center_axis1;
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if (angular_travel < 0) { angular_travel += 2*M_PI; }
if (isclockwise) { angular_travel -= 2*M_PI; }
float millimeters_of_travel = hypot(angular_travel*radius, fabs(linear_travel));
if (millimeters_of_travel < 0.001) { return; }
uint16_t segments = floor(millimeters_of_travel/MM_PER_ARC_SEGMENT);
if(segments == 0) segments = 1;
/*
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
// all segments.
if (invert_feed_rate) { feed_rate *= segments; }
*/
float theta_per_segment = angular_travel/segments;
float linear_per_segment = linear_travel/segments;
float extruder_per_segment = extruder_travel/segments;
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
and phi is the angle of rotation. Based on the solution approach by Jens Geisler.
r_T = [cos(phi) -sin(phi);
sin(phi) cos(phi] * r ;
For arc generation, the center of the circle is the axis of rotation and the radius vector is
defined from the circle center to the initial position. Each line segment is formed by successive
vector rotations. This requires only two cos() and sin() computations to form the rotation
matrix for the duration of the entire arc. Error may accumulate from numerical round-off, since
all double numbers are single precision on the Arduino. (True double precision will not have
round off issues for CNC applications.) Single precision error can accumulate to be greater than
tool precision in some cases. Therefore, arc path correction is implemented.
Small angle approximation may be used to reduce computation overhead further. This approximation
holds for everything, but very small circles and large mm_per_arc_segment values. In other words,
theta_per_segment would need to be greater than 0.1 rad and N_ARC_CORRECTION would need to be large
to cause an appreciable drift error. N_ARC_CORRECTION~=25 is more than small enough to correct for
numerical drift error. N_ARC_CORRECTION may be on the order a hundred(s) before error becomes an
issue for CNC machines with the single precision Arduino calculations.
This approximation also allows mc_arc to immediately insert a line segment into the planner
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead.
This is important when there are successive arc motions.
*/
// Vector rotation matrix values
float cos_T = 1-0.5*theta_per_segment*theta_per_segment; // Small angle approximation
float sin_T = theta_per_segment;
float arc_target[4];
float sin_Ti;
float cos_Ti;
float r_axisi;
uint16_t i;
int8_t count = 0;
// Initialize the linear axis
arc_target[axis_linear] = position[axis_linear];
// Initialize the extruder axis
arc_target[E_AXIS] = position[E_AXIS];
for (i = 1; i<segments; i++) { // Increment (segments-1)
if (count < N_ARC_CORRECTION) {
// Apply vector rotation matrix
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
r_axis1 = r_axisi;
count++;
} else {
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments.
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
cos_Ti = cos(i*theta_per_segment);
sin_Ti = sin(i*theta_per_segment);
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
count = 0;
}
// Update arc_target location
arc_target[axis_0] = center_axis0 + r_axis0;
arc_target[axis_1] = center_axis1 + r_axis1;
arc_target[axis_linear] += linear_per_segment;
arc_target[E_AXIS] += extruder_per_segment;
clamp_to_software_endstops(arc_target);
plan_buffer_line(arc_target[X_AXIS], arc_target[Y_AXIS], arc_target[Z_AXIS], arc_target[E_AXIS], feed_rate, extruder);
}
// Ensure last segment arrives at target location.
plan_buffer_line(target[X_AXIS], target[Y_AXIS], target[Z_AXIS], target[E_AXIS], feed_rate, extruder);
// plan_set_acceleration_manager_enabled(acceleration_manager_was_enabled);
}

@ -0,0 +1,32 @@
/*
motion_control.h - high level interface for issuing motion commands
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Copyright (c) 2011 Sungeun K. Jeon
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef motion_control_h
#define motion_control_h
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
// for vector transformation direction.
void mc_arc(float *position, float *target, float *offset, unsigned char axis_0, unsigned char axis_1,
unsigned char axis_linear, float feed_rate, float radius, unsigned char isclockwise, uint8_t extruder);
#endif

@ -0,0 +1,1162 @@
#ifndef PINS_H
#define PINS_H
#if MOTHERBOARD == 99
#define KNOWN_BOARD 1
#define X_STEP_PIN 2
#define X_DIR_PIN 3
#define X_ENABLE_PIN -1
#define X_MIN_PIN -1
#define X_MAX_PIN 16
#define Y_STEP_PIN 5
#define Y_DIR_PIN 6
#define Y_ENABLE_PIN -1
#define Y_MIN_PIN 67
#define Y_MAX_PIN -1
#define Z_STEP_PIN 62
#define Z_DIR_PIN 63
#define Z_ENABLE_PIN -1
#define Z_MIN_PIN 59
#define Z_MAX_PIN -1
#define E0_STEP_PIN 65
#define E0_DIR_PIN 66
#define E0_ENABLE_PIN -1
#define SDPOWER -1
#define SDSS 53
#define LED_PIN -1
#define FAN_PIN -1
#define PS_ON_PIN 9
#define KILL_PIN -1
#define HEATER_0_PIN 13
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define TEMP_0_PIN 6 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define TEMP_1_PIN -1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define TEMP_2_PIN -1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define HEATER_BED_PIN 4
#define TEMP_BED_PIN 10
#endif /* 99 */
/****************************************************************************************
* Gen7 v1.1, v1.2, v1.3, v1.4 pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 13
#define MOTHERBOARD 11
#define GEN7_VERSION 14 // v1.4
#endif
#if MOTHERBOARD == 12
#define MOTHERBOARD 11
#define GEN7_VERSION 13 // v1.3
#endif
#if MOTHERBOARD == 11
#define KNOWN_BOARD
#if !defined(__AVR_ATmega644P__) && !defined(__AVR_ATmega644__) && !defined(__AVR_ATmega1284P__)
#error Oops! Make sure you have 'Gen7' selected from the 'Tools -> Boards' menu.
#endif
#ifndef GEN7_VERSION
#define GEN7_VERSION 12 // v1.x
#endif
//x axis pins
#define X_STEP_PIN 19
#define X_DIR_PIN 18
#define X_ENABLE_PIN 24
#define X_MIN_PIN 7
#define X_MAX_PIN -1
//y axis pins
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_ENABLE_PIN 24
#define Y_MIN_PIN 5
#define Y_MAX_PIN -1
//z axis pins
#define Z_STEP_PIN 26
#define Z_DIR_PIN 25
#define Z_ENABLE_PIN 24
#define Z_MIN_PIN 1
#define Z_MAX_PIN 0
//extruder pins
#define E0_STEP_PIN 28
#define E0_DIR_PIN 27
#define E0_ENABLE_PIN 24
#define TEMP_0_PIN 1
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define TEMP_BED_PIN 2
#define HEATER_0_PIN 4
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define HEATER_BED_PIN 3
#define KILL_PIN -1
#define SDPOWER -1
#define SDSS -1 // SCL pin of I2C header
#define LED_PIN -1
#if (GEN7_VERSION >= 13)
// Gen7 v1.3 removed the fan pin
#define FAN_PIN -1
#else
#define FAN_PIN 31
#endif
#define PS_ON_PIN 15
#if (GEN7_VERSION < 14)
// Gen 1.3 and earlier supplied thermistor power via PS_ON
// Need to ignore the bad thermistor readings on those units
#define BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
#endif
//our pin for debugging.
#define DEBUG_PIN 0
//our RS485 pins
#define TX_ENABLE_PIN 12
#define RX_ENABLE_PIN 13
#endif
/*******************************************************************************
*********
* Gen7 Alfons3 pin assignment
*
********************************************************************************
********/
/* These Pins are assigned for the modified GEN7 Board from Alfons3 Please review the pins and adjust it for your needs*/
#if MOTHERBOARD == 10
#define KNOWN_BOARD
#if !defined(__AVR_ATmega644P__) && !defined(__AVR_ATmega644__) && !defined(__AVR_ATmega1284P__)
#error Oops! Make sure you have 'Gen7' selected from the 'Tools -> Boards' menu.
#endif
//x axis pins
#define X_STEP_PIN 21 //different from stanard GEN7
#define X_DIR_PIN 20 //different from stanard GEN7
#define X_ENABLE_PIN 24
#define X_MIN_PIN 0
#define X_MAX_PIN -1
//y axis pins
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_ENABLE_PIN 24
#define Y_MIN_PIN 1
#define Y_MAX_PIN -1
//z axis pins
#define Z_STEP_PIN 26
#define Z_DIR_PIN 25
#define Z_ENABLE_PIN 24
#define Z_MIN_PIN 2
#define Z_MAX_PIN -1
//extruder pins
#define E0_STEP_PIN 28
#define E0_DIR_PIN 27
#define E0_ENABLE_PIN 24
#define TEMP_0_PIN 2
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define TEMP_BED_PIN 1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed)
#define HEATER_0_PIN 4
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define HEATER_BED_PIN 3 // (bed)
#define SDPOWER -1
#define SDSS 31 // SCL pin of I2C header || CS Pin for SD Card support
#define LED_PIN -1
#define FAN_PIN -1
#define PS_ON_PIN 19
//our pin for debugging.
#define DEBUG_PIN -1
//our RS485 pins
//#define TX_ENABLE_PIN 12
//#define RX_ENABLE_PIN 13
#define BEEPER -1
#define SDCARDDETECT -1
#define SUICIDE_PIN -1 //has to be defined; otherwise Power_off doesn't work
#define KILL_PIN -1
//Pins for 4bit LCD Support
#define LCD_PINS_RS 18
#define LCD_PINS_ENABLE 17
#define LCD_PINS_D4 16
#define LCD_PINS_D5 15
#define LCD_PINS_D6 13
#define LCD_PINS_D7 14
//buttons are directly attached
#define BTN_EN1 11
#define BTN_EN2 10
#define BTN_ENC 12 //the click
#define BLEN_C 2
#define BLEN_B 1
#define BLEN_A 0
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
#endif
/****************************************************************************************
* Arduino Mega pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 3 || MOTHERBOARD == 33 || MOTHERBOARD == 34
#define KNOWN_BOARD 1
//////////////////FIX THIS//////////////
#ifndef __AVR_ATmega1280__
#ifndef __AVR_ATmega2560__
#error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu.
#endif
#endif
// uncomment one of the following lines for RAMPS v1.3 or v1.0, comment both for v1.2 or 1.1
// #define RAMPS_V_1_3
// #define RAMPS_V_1_0
#if MOTHERBOARD == 33 || MOTHERBOARD == 34
#define X_STEP_PIN 54
#define X_DIR_PIN 55
#define X_ENABLE_PIN 38
#define X_MIN_PIN 3
#define X_MAX_PIN 2 //2 //Max endstops default to disabled "-1", set to commented value to enable.
#define Y_STEP_PIN 60
#define Y_DIR_PIN 61
#define Y_ENABLE_PIN 56
#define Y_MIN_PIN 14
#define Y_MAX_PIN 15 //15
#define Z_STEP_PIN 46
#define Z_DIR_PIN 48
#define Z_ENABLE_PIN 62
#define Z_MIN_PIN 18
#define Z_MAX_PIN 19
#define Z2_STEP_PIN 36
#define Z2_DIR_PIN 34
#define Z2_ENABLE_PIN 30
#define E0_STEP_PIN 26
#define E0_DIR_PIN 28
#define E0_ENABLE_PIN 24
#define E1_STEP_PIN 36
#define E1_DIR_PIN 34
#define E1_ENABLE_PIN 30
#define SDPOWER -1
#define SDSS 53
#define LED_PIN 13
#if MOTHERBOARD == 33
#define FAN_PIN 9 // (Sprinter config)
#else
#define FAN_PIN 4 // IO pin. Buffer needed
#endif
#define PS_ON_PIN 12
#define KILL_PIN -1
#define HEATER_0_PIN 10 // EXTRUDER 1
#if MOTHERBOARD == 33
#define HEATER_1_PIN -1
#else
#define HEATER_1_PIN 9 // EXTRUDER 2 (FAN On Sprinter)
#endif
#define HEATER_2_PIN -1
#define TEMP_0_PIN 13 // ANALOG NUMBERING
#define TEMP_1_PIN 15 // ANALOG NUMBERING
#define TEMP_2_PIN -1 // ANALOG NUMBERING
#define HEATER_BED_PIN 8 // BED
#define TEMP_BED_PIN 14 // ANALOG NUMBERING
#ifdef ULTRA_LCD
#ifdef NEWPANEL
//arduino pin which triggers an piezzo beeper
#define BEEPER 33 // Beeper on AUX-4
#define LCD_PINS_RS 16
#define LCD_PINS_ENABLE 17
#define LCD_PINS_D4 23
#define LCD_PINS_D5 25
#define LCD_PINS_D6 27
#define LCD_PINS_D7 29
//buttons are directly attached using AUX-2
#define BTN_EN1 37
#define BTN_EN2 35
#define BTN_ENC 31 //the click
#define BLEN_C 2
#define BLEN_B 1
#define BLEN_A 0
#define SDCARDDETECT -1 // Ramps does not use this port
//encoder rotation values
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
#else //old style panel with shift register
//arduino pin witch triggers an piezzo beeper
#define BEEPER 33 No Beeper added
//buttons are attached to a shift register
// Not wired this yet
//#define SHIFT_CLK 38
//#define SHIFT_LD 42
//#define SHIFT_OUT 40
//#define SHIFT_EN 17
#define LCD_PINS_RS 16
#define LCD_PINS_ENABLE 17
#define LCD_PINS_D4 23
#define LCD_PINS_D5 25
#define LCD_PINS_D6 27
#define LCD_PINS_D7 29
//encoder rotation values
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
//bits in the shift register that carry the buttons for:
// left up center down right red
#define BL_LE 7
#define BL_UP 6
#define BL_MI 5
#define BL_DW 4
#define BL_RI 3
#define BL_ST 2
#define BLEN_B 1
#define BLEN_A 0
#endif
#endif //ULTRA_LCD
#else // RAMPS_V_1_1 or RAMPS_V_1_2 as default
#define X_STEP_PIN 26
#define X_DIR_PIN 28
#define X_ENABLE_PIN 24
#define X_MIN_PIN 3
#define X_MAX_PIN -1 //2
#define Y_STEP_PIN 38
#define Y_DIR_PIN 40
#define Y_ENABLE_PIN 36
#define Y_MIN_PIN 16
#define Y_MAX_PIN -1 //17
#define Z_STEP_PIN 44
#define Z_DIR_PIN 46
#define Z_ENABLE_PIN 42
#define Z_MIN_PIN 18
#define Z_MAX_PIN -1 //19
#define E0_STEP_PIN 32
#define E0_DIR_PIN 34
#define E0_ENABLE_PIN 30
#define SDPOWER 48
#define SDSS 53
#define LED_PIN 13
#define PS_ON_PIN -1
#define KILL_PIN -1
#ifdef RAMPS_V_1_0 // RAMPS_V_1_0
#define HEATER_0_PIN 12 // RAMPS 1.0
#define HEATER_BED_PIN -1 // RAMPS 1.0
#define FAN_PIN 11 // RAMPS 1.0
#else // RAMPS_V_1_1 or RAMPS_V_1_2
#define HEATER_0_PIN 10 // RAMPS 1.1
#define HEATER_BED_PIN 8 // RAMPS 1.1
#define FAN_PIN 9 // RAMPS 1.1
#endif
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define TEMP_0_PIN 2 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define TEMP_BED_PIN 1 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#endif
// SPI for Max6675 Thermocouple
#ifndef SDSUPPORT
// these pins are defined in the SD library if building with SD support
#define MAX_SCK_PIN 52
#define MAX_MISO_PIN 50
#define MAX_MOSI_PIN 51
#define MAX6675_SS 53
#else
#define MAX6675_SS 49
#endif
#endif
/****************************************************************************************
* Duemilanove w/ ATMega328P pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 4
#define KNOWN_BOARD 1
#ifndef __AVR_ATmega328P__
#error Oops! Make sure you have 'Arduino Duemilanove w/ ATMega328' selected from the 'Tools -> Boards' menu.
#endif
#define X_STEP_PIN 19
#define X_DIR_PIN 18
#define X_ENABLE_PIN -1
#define X_MIN_PIN 17
#define X_MAX_PIN -1
#define Y_STEP_PIN 10
#define Y_DIR_PIN 7
#define Y_ENABLE_PIN -1
#define Y_MIN_PIN 8
#define Y_MAX_PIN -1
#define Z_STEP_PIN 13
#define Z_DIR_PIN 3
#define Z_ENABLE_PIN 2
#define Z_MIN_PIN 4
#define Z_MAX_PIN -1
#define E0_STEP_PIN 11
#define E0_DIR_PIN 12
#define E0_ENABLE_PIN -1
#define SDPOWER -1
#define SDSS -1
#define LED_PIN -1
#define FAN_PIN 5
#define PS_ON_PIN -1
#define KILL_PIN -1
#define HEATER_0_PIN 6
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define HEATER_BED_PIN -1
#define TEMP_BED_PIN -1
#endif
/****************************************************************************************
* Gen6 pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 5 || MOTHERBOARD == 51
#define KNOWN_BOARD 1
#ifndef __AVR_ATmega644P__
#ifndef __AVR_ATmega1284P__
#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu.
#endif
#endif
//x axis pins
#define X_STEP_PIN 15
#define X_DIR_PIN 18
#define X_ENABLE_PIN 19
#define X_MIN_PIN 20
#define X_MAX_PIN -1
//y axis pins
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_ENABLE_PIN 24
#define Y_MIN_PIN 25
#define Y_MAX_PIN -1
//z axis pins
#define Z_STEP_PIN 27
#define Z_DIR_PIN 28
#define Z_ENABLE_PIN 29
#define Z_MIN_PIN 30
#define Z_MAX_PIN -1
//extruder pins
#define E0_STEP_PIN 4 //Edited @ EJE Electronics 20100715
#define E0_DIR_PIN 2 //Edited @ EJE Electronics 20100715
#define E0_ENABLE_PIN 3 //Added @ EJE Electronics 20100715
#define TEMP_0_PIN 5 //changed @ rkoeppl 20110410
#define TEMP_1_PIN -1 //changed @ rkoeppl 20110410
#define TEMP_2_PIN -1 //changed @ rkoeppl 20110410
#define HEATER_0_PIN 14 //changed @ rkoeppl 20110410
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#if MOTHERBOARD == 5
#define HEATER_BED_PIN -1 //changed @ rkoeppl 20110410
#define TEMP_BED_PIN -1 //changed @ rkoeppl 20110410
#else
#define HEATER_BED_PIN 1 //changed @ rkoeppl 20110410
#define TEMP_BED_PIN 0 //changed @ rkoeppl 20110410
#endif
#define SDPOWER -1
#define SDSS 17
#define LED_PIN -1 //changed @ rkoeppl 20110410
#define FAN_PIN -1 //changed @ rkoeppl 20110410
#define PS_ON_PIN -1 //changed @ rkoeppl 20110410
#define KILL_PIN -1 //changed @ drakelive 20120830
//our pin for debugging.
#define DEBUG_PIN 0
//our RS485 pins
#define TX_ENABLE_PIN 12
#define RX_ENABLE_PIN 13
#endif
/****************************************************************************************
* Sanguinololu pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 63
#define MELZI
#endif
#if MOTHERBOARD == 62 || MOTHERBOARD == 63
#undef MOTHERBOARD
#define MOTHERBOARD 6
#define SANGUINOLOLU_V_1_2
#endif
#if MOTHERBOARD == 6
#define KNOWN_BOARD 1
#ifndef __AVR_ATmega644P__
#ifndef __AVR_ATmega1284P__
#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu.
#endif
#endif
#define X_STEP_PIN 15
#define X_DIR_PIN 21
#if X_HOME_DIR < 0
# define X_MIN_PIN 18
# define X_MAX_PIN -1
#else
# define X_MIN_PIN -1
# define X_MAX_PIN 18
#endif
#define Y_STEP_PIN 22
#define Y_DIR_PIN 23
#if Y_HOME_DIR < 0
# define Y_MIN_PIN 19
# define Y_MAX_PIN -1
#else
# define Y_MIN_PIN -1
# define Y_MAX_PIN 19
#endif
#define Z_STEP_PIN 3
#define Z_DIR_PIN 2
#if Z_HOME_DIR < 0
# define Z_MIN_PIN 20
# define Z_MAX_PIN -1
#else
# define Z_MIN_PIN -1
# define Z_MAX_PIN 20
#endif
#define E0_STEP_PIN 1
#define E0_DIR_PIN 0
#define LED_PIN -1
#define FAN_PIN -1
#ifdef MELZI
#define LED_PIN 28
#define FAN_PIN 4
#endif
#define PS_ON_PIN -1
#define KILL_PIN -1
#define HEATER_0_PIN 13 // (extruder)
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#ifdef SANGUINOLOLU_V_1_2
#define HEATER_BED_PIN 12 // (bed)
#define X_ENABLE_PIN 14
#define Y_ENABLE_PIN 14
#define Z_ENABLE_PIN 26
#define E0_ENABLE_PIN 14
#else
#define HEATER_BED_PIN 14 // (bed)
#define X_ENABLE_PIN -1
#define Y_ENABLE_PIN -1
#define Z_ENABLE_PIN -1
#define E0_ENABLE_PIN -1
#endif
#define TEMP_0_PIN 7 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 33 extruder)
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define TEMP_BED_PIN 6 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed)
#define SDPOWER -1
#define SDSS 31
#ifdef MELZI
#define SDSS 24
#endif
#endif
#if MOTHERBOARD == 7
#define KNOWN_BOARD
/*****************************************************************
* Ultimaker pin assignment
******************************************************************/
#ifndef __AVR_ATmega1280__
#ifndef __AVR_ATmega2560__
#error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu.
#endif
#endif
#define X_STEP_PIN 25
#define X_DIR_PIN 23
#define X_MIN_PIN 22
#define X_MAX_PIN 24
#define X_ENABLE_PIN 27
#define Y_STEP_PIN 31
#define Y_DIR_PIN 33
#define Y_MIN_PIN 26
#define Y_MAX_PIN 28
#define Y_ENABLE_PIN 29
#define Z_STEP_PIN 37
#define Z_DIR_PIN 39
#define Z_MIN_PIN 30
#define Z_MAX_PIN 32
#define Z_ENABLE_PIN 35
#define HEATER_BED_PIN 4
#define TEMP_BED_PIN 10
#define HEATER_0_PIN 2
#define TEMP_0_PIN 8
#define HEATER_1_PIN 3
#define TEMP_1_PIN 9
#define HEATER_2_PIN -1
#define TEMP_2_PIN -1
#define E0_STEP_PIN 43
#define E0_DIR_PIN 45
#define E0_ENABLE_PIN 41
#define E1_STEP_PIN 49
#define E1_DIR_PIN 47
#define E1_ENABLE_PIN 48
#define SDPOWER -1
#define SDSS 53
#define LED_PIN 13
#define FAN_PIN 7
#define PS_ON_PIN 12
#define KILL_PIN -1
#define SUICIDE_PIN 54 //PIN that has to be turned on right after start, to keep power flowing.
#ifdef ULTRA_LCD
#ifdef NEWPANEL
//arduino pin witch triggers an piezzo beeper
#define BEEPER 18
#define LCD_PINS_RS 20
#define LCD_PINS_ENABLE 17
#define LCD_PINS_D4 16
#define LCD_PINS_D5 21
#define LCD_PINS_D6 5
#define LCD_PINS_D7 6
//buttons are directly attached
#define BTN_EN1 40
#define BTN_EN2 42
#define BTN_ENC 19 //the click
#define BLEN_C 2
#define BLEN_B 1
#define BLEN_A 0
#define SDCARDDETECT 38
//encoder rotation values
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
#else //old style panel with shift register
//arduino pin witch triggers an piezzo beeper
#define BEEPER 18
//buttons are attached to a shift register
#define SHIFT_CLK 38
#define SHIFT_LD 42
#define SHIFT_OUT 40
#define SHIFT_EN 17
#define LCD_PINS_RS 16
#define LCD_PINS_ENABLE 5
#define LCD_PINS_D4 6
#define LCD_PINS_D5 21
#define LCD_PINS_D6 20
#define LCD_PINS_D7 19
//encoder rotation values
#ifndef ULTIMAKERCONTROLLER
#define encrot0 0
#define encrot1 2
#define encrot2 3
#define encrot3 1
#else
#define encrot0 0
#define encrot1 1
#define encrot2 3
#define encrot3 2
#endif
#define SDCARDDETECT -1
//bits in the shift register that carry the buttons for:
// left up center down right red
#define BL_LE 7
#define BL_UP 6
#define BL_MI 5
#define BL_DW 4
#define BL_RI 3
#define BL_ST 2
#define BLEN_B 1
#define BLEN_A 0
#endif
#endif //ULTRA_LCD
#endif
#if MOTHERBOARD == 71
#define KNOWN_BOARD
/*****************************************************************
* Ultimaker pin assignment (Old electronics)
******************************************************************/
#ifndef __AVR_ATmega1280__
#ifndef __AVR_ATmega2560__
#error Oops! Make sure you have 'Arduino Mega' selected from the 'Tools -> Boards' menu.
#endif
#endif
#define X_STEP_PIN 25
#define X_DIR_PIN 23
#define X_MIN_PIN 15
#define X_MAX_PIN 14
#define X_ENABLE_PIN 27
#define Y_STEP_PIN 31
#define Y_DIR_PIN 33
#define Y_MIN_PIN 17
#define Y_MAX_PIN 16
#define Y_ENABLE_PIN 29
#define Z_STEP_PIN 37
#define Z_DIR_PIN 39
#define Z_MIN_PIN 19
#define Z_MAX_PIN 18
#define Z_ENABLE_PIN 35
#define HEATER_BED_PIN -1
#define TEMP_BED_PIN -1
#define HEATER_0_PIN 2
#define TEMP_0_PIN 8
#define HEATER_1_PIN 1
#define TEMP_1_PIN 1
#define HEATER_2_PIN -1
#define TEMP_2_PIN -1
#define E0_STEP_PIN 43
#define E0_DIR_PIN 45
#define E0_ENABLE_PIN 41
#define E1_STEP_PIN -1
#define E1_DIR_PIN -1
#define E1_ENABLE_PIN -1
#define SDPOWER -1
#define SDSS -1
#define LED_PIN -1
#define FAN_PIN -1
#define PS_ON_PIN -1
#define KILL_PIN -1
#define SUICIDE_PIN -1 //PIN that has to be turned on right after start, to keep power flowing.
#define LCD_PINS_RS 24
#define LCD_PINS_ENABLE 22
#define LCD_PINS_D4 36
#define LCD_PINS_D5 34
#define LCD_PINS_D6 32
#define LCD_PINS_D7 30
#endif
/****************************************************************************************
* Teensylu 0.7 pin assingments (ATMEGA90USB)
* Requires the Teensyduino software with Teensy2.0++ selected in arduino IDE!
****************************************************************************************/
#if MOTHERBOARD == 8
#define MOTHERBOARD 8
#define KNOWN_BOARD 1
#define X_STEP_PIN 0
#define X_DIR_PIN 1
#define X_ENABLE_PIN 39
#define X_MIN_PIN 13
#define X_MAX_PIN -1
#define Y_STEP_PIN 2
#define Y_DIR_PIN 3
#define Y_ENABLE_PIN 38
#define Y_MIN_PIN 14
#define Y_MAX_PIN -1
#define Z_STEP_PIN 4
#define Z_DIR_PIN 5
#define Z_ENABLE_PIN 23
#define Z_MIN_PIN 15
#define Z_MAX_PIN -1
#define E0_STEP_PIN 6
#define E0_DIR_PIN 7
#define E0_ENABLE_PIN 19
#define HEATER_0_PIN 21 // Extruder
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define HEATER_BED_PIN 20 // Bed
#define FAN_PIN 22 // Fan
#define TEMP_0_PIN 7 // Extruder
#define TEMP_1_PIN -1
#define TEMP_2_PIN -1
#define TEMP_BED_PIN 6 // Bed
#define SDPOWER -1
#define SDSS 8
#define LED_PIN -1
#define PS_ON_PIN -1
#define KILL_PIN -1
#define ALARM_PIN -1
#ifndef SDSUPPORT
// these pins are defined in the SD library if building with SD support
#define SCK_PIN 9
#define MISO_PIN 11
#define MOSI_PIN 10
#endif
#endif
/****************************************************************************************
* Gen3+ pin assignment
*
****************************************************************************************/
#if MOTHERBOARD == 9
#define MOTHERBOARD 6
#define KNOWN_BOARD 1
#ifndef __AVR_ATmega644P__
#ifndef __AVR_ATmega1284P__
#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu.
#endif
#endif
#define X_STEP_PIN 15
#define X_DIR_PIN 18
#define X_MIN_PIN 20
#define X_MAX_PIN -1
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_MIN_PIN 25
#define Y_MAX_PIN -1
#define Z_STEP_PIN 27
#define Z_DIR_PIN 28
#define Z_MIN_PIN 30
#define Z_MAX_PIN -1
#define E_STEP_PIN 17
#define E_DIR_PIN 21
#define LED_PIN -1
#define FAN_PIN -1
#define PS_ON_PIN 14
#define KILL_PIN -1
#define HEATER_0_PIN 12 // (extruder)
#define HEATER_1_PIN 16 // (bed)
#define X_ENABLE_PIN 19
#define Y_ENABLE_PIN 24
#define Z_ENABLE_PIN 29
#define E_ENABLE_PIN 13
#define TEMP_0_PIN 0 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 33 extruder)
#define TEMP_1_PIN 5 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!! (pin 34 bed)
#define TEMP_2_PIN -1
#define SDPOWER -1
#define SDSS 4
#define HEATER_2_PIN -1
#endif
/****************************************************************************************
* Open Motion controller with enable based extruders
*
* ATMega644
*
* +---\/---+
* (D 0) PB0 1| |40 PA0 (AI 0 / D31)
* (D 1) PB1 2| |39 PA1 (AI 1 / D30)
* INT2 (D 2) PB2 3| |38 PA2 (AI 2 / D29)
* PWM (D 3) PB3 4| |37 PA3 (AI 3 / D28)
* PWM (D 4) PB4 5| |36 PA4 (AI 4 / D27)
* MOSI (D 5) PB5 6| |35 PA5 (AI 5 / D26)
* MISO (D 6) PB6 7| |34 PA6 (AI 6 / D25)
* SCK (D 7) PB7 8| |33 PA7 (AI 7 / D24)
* RST 9| |32 AREF
* VCC 10| |31 GND
* GND 11| |30 AVCC
* XTAL2 12| |29 PC7 (D 23)
* XTAL1 13| |28 PC6 (D 22)
* RX0 (D 8) PD0 14| |27 PC5 (D 21) TDI
* TX0 (D 9) PD1 15| |26 PC4 (D 20) TDO
* INT0 RX1 (D 10) PD2 16| |25 PC3 (D 19) TMS
* INT1 TX1 (D 11) PD3 17| |24 PC2 (D 18) TCK
* PWM (D 12) PD4 18| |23 PC1 (D 17) SDA
* PWM (D 13) PD5 19| |22 PC0 (D 16) SCL
* PWM (D 14) PD6 20| |21 PD7 (D 15) PWM
* +--------+
*
****************************************************************************************/
#if MOTHERBOARD == 90 //Alpha OMCA board
#define KNOWN_BOARD 1
#ifndef __AVR_ATmega644__
#error Oops! Make sure you have 'SanguinoA' selected from the 'Tools -> Boards' menu.
#endif
#define X_STEP_PIN 21
#define X_DIR_PIN 20
#define X_ENABLE_PIN 24
#define X_MIN_PIN 0
#define X_MAX_PIN -1
#define Y_STEP_PIN 23
#define Y_DIR_PIN 22
#define Y_ENABLE_PIN 24
#define Y_MIN_PIN 1
#define Y_MAX_PIN -1
#define Z_STEP_PIN 26
#define Z_DIR_PIN 25
#define Z_ENABLE_PIN 24
#define Z_MIN_PIN 2
#define Z_MAX_PIN -1
#define E0_STEP_PIN 28
#define E0_DIR_PIN 27
#define E0_ENABLE_PIN 24
#define E1_STEP_PIN -1 // 19
#define E1_DIR_PIN -1 // 18
#define E1_ENABLE_PIN 24
#define E2_STEP_PIN -1 // 17
#define E2_DIR_PIN -1 // 16
#define E2_ENABLE_PIN 24
#define SDPOWER -1
#define SDSS 11
#define SDCARDDETECT -1 // 10 optional also used as mode pin
#define LED_PIN -1
#define FAN_PIN 3
#define PS_ON_PIN -1
#define KILL_PIN -1
#define HEATER_0_PIN 4
#define HEATER_1_PIN -1 // 12
#define HEATER_2_PIN -1 // 13
#define TEMP_0_PIN 0 //D27 // MUST USE ANALOG INPUT NUMBERING NOT DIGITAL OUTPUT NUMBERING!!!!!!!!!
#define TEMP_1_PIN -1 // 1
#define TEMP_2_PIN -1 // 2
#define HEATER_BED_PIN -1 // 14/15
#define TEMP_BED_PIN -1 // 1,2 or I2C
/* Unused (1) (2) (3) 4 5 6 7 8 9 10 11 12 13 (14) (15) (16) 17 (18) (19) (20) (21) (22) (23) 24 (25) (26) (27) 28 (29) (30) (31) */
#endif
#if MOTHERBOARD == 91 // Final OMCA board -- REF http://sanguino.cc/hardware
#define KNOWN_BOARD 1
#if !defined(__AVR_ATmega644P__) && !defined(__AVR_ATmega644__)
#error Oops! Make sure you have 'Sanguino' selected from the 'Tools -> Boards' menu. (Final OMCA board)
#endif
#define X_STEP_PIN 26
#define X_DIR_PIN 25
#define X_ENABLE_PIN 10
#define X_MIN_PIN 0
#define X_MAX_PIN -1
#define Y_STEP_PIN 28
#define Y_DIR_PIN 27
#define Y_ENABLE_PIN 10
#define Y_MIN_PIN 1
#define Y_MAX_PIN -1
#define Z_STEP_PIN 23
#define Z_DIR_PIN 22
#define Z_ENABLE_PIN 10
#define Z_MIN_PIN 2
#define Z_MAX_PIN -1
#define E0_STEP_PIN 24
#define E0_DIR_PIN 21
#define E0_ENABLE_PIN 10
/* future proofing */
#define __FS 20
#define __FD 19
#define __GS 18
#define __GD 13
#define UNUSED_PWM 14 /* PWM on LEFT connector */
#define E1_STEP_PIN -1 // 21
#define E1_DIR_PIN -1 // 20
#define E1_ENABLE_PIN -1 // 19
#define E2_STEP_PIN -1 // 21
#define E2_DIR_PIN -1 // 20
#define E2_ENABLE_PIN -1 // 18
#define SDPOWER -1
#define SDSS 11
#define SDCARDDETECT -1 // 10 optional also used as mode pin
#define LED_PIN -1
#define FAN_PIN 14 /* PWM on MIDDLE connector */
#define PS_ON_PIN -1
#define KILL_PIN -1
#define HEATER_0_PIN 3 /*DONE PWM on RIGHT connector */
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define HEATER_1_PIN -1
#define HEATER_2_PIN -1
#define TEMP_0_PIN 0 // ANALOG INPUT NUMBERING
#define TEMP_1_PIN 1 // ANALOG
#define TEMP_2_PIN -1 // 2
#define HEATER_BED_PIN 4
#define TEMP_BED_PIN 2 // 1,2 or I2C
#define I2C_SCL 16
#define I2C_SDA 17
#endif
#ifndef KNOWN_BOARD
#error Unknown MOTHERBOARD value in configuration.h
#endif
//List of pins which to ignore when asked to change by gcode, 0 and 1 are RX and TX, do not mess with those!
#define _E0_PINS E0_STEP_PIN, E0_DIR_PIN, E0_ENABLE_PIN, HEATER_0_PIN,
#if EXTRUDERS > 1
#define _E1_PINS E1_STEP_PIN, E1_DIR_PIN, E1_ENABLE_PIN, HEATER_1_PIN,
#else
#define _E1_PINS
#endif
#if EXTRUDERS > 2
#define _E2_PINS E2_STEP_PIN, E2_DIR_PIN, E2_ENABLE_PIN, HEATER_2_PIN,
#else
#define _E2_PINS
#endif
#ifdef DISABLE_MAX_ENDSTOPS
#define X_MAX_PIN -1
#define Y_MAX_PIN -1
#define Z_MAX_PIN -1
#endif
#define SENSITIVE_PINS {0, 1, X_STEP_PIN, X_DIR_PIN, X_ENABLE_PIN, X_MIN_PIN, X_MAX_PIN, Y_STEP_PIN, Y_DIR_PIN, Y_ENABLE_PIN, Y_MIN_PIN, Y_MAX_PIN, Z_STEP_PIN, Z_DIR_PIN, Z_ENABLE_PIN, Z_MIN_PIN, Z_MAX_PIN, LED_PIN, PS_ON_PIN, \
HEATER_BED_PIN, FAN_PIN, \
_E0_PINS _E1_PINS _E2_PINS \
TEMP_0_PIN, TEMP_1_PIN, TEMP_2_PIN, TEMP_BED_PIN }
#endif

@ -0,0 +1,866 @@
/*
planner.c - buffers movement commands and manages the acceleration profile plan
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
/* The ring buffer implementation gleaned from the wiring_serial library by David A. Mellis. */
/*
Reasoning behind the mathematics in this module (in the key of 'Mathematica'):
s == speed, a == acceleration, t == time, d == distance
Basic definitions:
Speed[s_, a_, t_] := s + (a*t)
Travel[s_, a_, t_] := Integrate[Speed[s, a, t], t]
Distance to reach a specific speed with a constant acceleration:
Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, d, t]
d -> (m^2 - s^2)/(2 a) --> estimate_acceleration_distance()
Speed after a given distance of travel with constant acceleration:
Solve[{Speed[s, a, t] == m, Travel[s, a, t] == d}, m, t]
m -> Sqrt[2 a d + s^2]
DestinationSpeed[s_, a_, d_] := Sqrt[2 a d + s^2]
When to start braking (di) to reach a specified destionation speed (s2) after accelerating
from initial speed s1 without ever stopping at a plateau:
Solve[{DestinationSpeed[s1, a, di] == DestinationSpeed[s2, a, d - di]}, di]
di -> (2 a d - s1^2 + s2^2)/(4 a) --> intersection_distance()
IntersectionDistance[s1_, s2_, a_, d_] := (2 a d - s1^2 + s2^2)/(4 a)
*/
#include "Marlin.h"
#include "planner.h"
#include "stepper.h"
#include "temperature.h"
#include "ultralcd.h"
#include "language.h"
//===========================================================================
//=============================public variables ============================
//===========================================================================
unsigned long minsegmenttime;
float max_feedrate[4]; // set the max speeds
float axis_steps_per_unit[4];
unsigned long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software
float minimumfeedrate;
float acceleration; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
float retract_acceleration; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
float max_z_jerk;
float max_e_jerk;
float mintravelfeedrate;
unsigned long axis_steps_per_sqr_second[NUM_AXIS];
// The current position of the tool in absolute steps
long position[4]; //rescaled from extern when axis_steps_per_unit are changed by gcode
static float previous_speed[4]; // Speed of previous path line segment
static float previous_nominal_speed; // Nominal speed of previous path line segment
extern volatile int extrudemultiply; // Sets extrude multiply factor (in percent)
#ifdef AUTOTEMP
float autotemp_max=250;
float autotemp_min=210;
float autotemp_factor=0.1;
bool autotemp_enabled=false;
#endif
//===========================================================================
//=================semi-private variables, used in inline functions =====
//===========================================================================
block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
volatile unsigned char block_buffer_head; // Index of the next block to be pushed
volatile unsigned char block_buffer_tail; // Index of the block to process now
//===========================================================================
//=============================private variables ============================
//===========================================================================
#ifdef PREVENT_DANGEROUS_EXTRUDE
bool allow_cold_extrude=false;
#endif
#ifdef XY_FREQUENCY_LIMIT
// Used for the frequency limit
static unsigned char old_direction_bits = 0; // Old direction bits. Used for speed calculations
static long x_segment_time[3]={
0,0,0}; // Segment times (in us). Used for speed calculations
static long y_segment_time[3]={
0,0,0};
#endif
// Returns the index of the next block in the ring buffer
// NOTE: Removed modulo (%) operator, which uses an expensive divide and multiplication.
static int8_t next_block_index(int8_t block_index) {
block_index++;
if (block_index == BLOCK_BUFFER_SIZE) {
block_index = 0;
}
return(block_index);
}
// Returns the index of the previous block in the ring buffer
static int8_t prev_block_index(int8_t block_index) {
if (block_index == 0) {
block_index = BLOCK_BUFFER_SIZE;
}
block_index--;
return(block_index);
}
//===========================================================================
//=============================functions ============================
//===========================================================================
// Calculates the distance (not time) it takes to accelerate from initial_rate to target_rate using the
// given acceleration:
FORCE_INLINE float estimate_acceleration_distance(float initial_rate, float target_rate, float acceleration)
{
if (acceleration!=0) {
return((target_rate*target_rate-initial_rate*initial_rate)/
(2.0*acceleration));
}
else {
return 0.0; // acceleration was 0, set acceleration distance to 0
}
}
// This function gives you the point at which you must start braking (at the rate of -acceleration) if
// you started at speed initial_rate and accelerated until this point and want to end at the final_rate after
// a total travel of distance. This can be used to compute the intersection point between acceleration and
// deceleration in the cases where the trapezoid has no plateau (i.e. never reaches maximum speed)
FORCE_INLINE float intersection_distance(float initial_rate, float final_rate, float acceleration, float distance)
{
if (acceleration!=0) {
return((2.0*acceleration*distance-initial_rate*initial_rate+final_rate*final_rate)/
(4.0*acceleration) );
}
else {
return 0.0; // acceleration was 0, set intersection distance to 0
}
}
// Calculates trapezoid parameters so that the entry- and exit-speed is compensated by the provided factors.
void calculate_trapezoid_for_block(block_t *block, float entry_factor, float exit_factor) {
unsigned long initial_rate = ceil(block->nominal_rate*entry_factor); // (step/min)
unsigned long final_rate = ceil(block->nominal_rate*exit_factor); // (step/min)
// Limit minimal step rate (Otherwise the timer will overflow.)
if(initial_rate <120) {
initial_rate=120;
}
if(final_rate < 120) {
final_rate=120;
}
long acceleration = block->acceleration_st;
int32_t accelerate_steps =
ceil(estimate_acceleration_distance(block->initial_rate, block->nominal_rate, acceleration));
int32_t decelerate_steps =
floor(estimate_acceleration_distance(block->nominal_rate, block->final_rate, -acceleration));
// Calculate the size of Plateau of Nominal Rate.
int32_t plateau_steps = block->step_event_count-accelerate_steps-decelerate_steps;
// Is the Plateau of Nominal Rate smaller than nothing? That means no cruising, and we will
// have to use intersection_distance() to calculate when to abort acceleration and start braking
// in order to reach the final_rate exactly at the end of this block.
if (plateau_steps < 0) {
accelerate_steps = ceil(
intersection_distance(block->initial_rate, block->final_rate, acceleration, block->step_event_count));
accelerate_steps = max(accelerate_steps,0); // Check limits due to numerical round-off
accelerate_steps = min(accelerate_steps,block->step_event_count);
plateau_steps = 0;
}
#ifdef ADVANCE
volatile long initial_advance = block->advance*entry_factor*entry_factor;
volatile long final_advance = block->advance*exit_factor*exit_factor;
#endif // ADVANCE
// block->accelerate_until = accelerate_steps;
// block->decelerate_after = accelerate_steps+plateau_steps;
CRITICAL_SECTION_START; // Fill variables used by the stepper in a critical section
if(block->busy == false) { // Don't update variables if block is busy.
block->accelerate_until = accelerate_steps;
block->decelerate_after = accelerate_steps+plateau_steps;
block->initial_rate = initial_rate;
block->final_rate = final_rate;
#ifdef ADVANCE
block->initial_advance = initial_advance;
block->final_advance = final_advance;
#endif //ADVANCE
}
CRITICAL_SECTION_END;
}
// Calculates the maximum allowable speed at this point when you must be able to reach target_velocity using the
// acceleration within the allotted distance.
FORCE_INLINE float max_allowable_speed(float acceleration, float target_velocity, float distance) {
return sqrt(target_velocity*target_velocity-2*acceleration*distance);
}
// "Junction jerk" in this context is the immediate change in speed at the junction of two blocks.
// This method will calculate the junction jerk as the euclidean distance between the nominal
// velocities of the respective blocks.
//inline float junction_jerk(block_t *before, block_t *after) {
// return sqrt(
// pow((before->speed_x-after->speed_x), 2)+pow((before->speed_y-after->speed_y), 2));
//}
// The kernel called by planner_recalculate() when scanning the plan from last to first entry.
void planner_reverse_pass_kernel(block_t *previous, block_t *current, block_t *next) {
if(!current) {
return;
}
if (next) {
// If entry speed is already at the maximum entry speed, no need to recheck. Block is cruising.
// If not, block in state of acceleration or deceleration. Reset entry speed to maximum and
// check for maximum allowable speed reductions to ensure maximum possible planned speed.
if (current->entry_speed != current->max_entry_speed) {
// If nominal length true, max junction speed is guaranteed to be reached. Only compute
// for max allowable speed if block is decelerating and nominal length is false.
if ((!current->nominal_length_flag) && (current->max_entry_speed > next->entry_speed)) {
current->entry_speed = min( current->max_entry_speed,
max_allowable_speed(-current->acceleration,next->entry_speed,current->millimeters));
}
else {
current->entry_speed = current->max_entry_speed;
}
current->recalculate_flag = true;
}
} // Skip last block. Already initialized and set for recalculation.
}
// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
// implements the reverse pass.
void planner_reverse_pass() {
uint8_t block_index = block_buffer_head;
//Make a local copy of block_buffer_tail, because the interrupt can alter it
CRITICAL_SECTION_START;
unsigned char tail = block_buffer_tail;
CRITICAL_SECTION_END
if(((block_buffer_head-tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1)) > 3) {
block_index = (block_buffer_head - 3) & (BLOCK_BUFFER_SIZE - 1);
block_t *block[3] = {
NULL, NULL, NULL };
while(block_index != tail) {
block_index = prev_block_index(block_index);
block[2]= block[1];
block[1]= block[0];
block[0] = &block_buffer[block_index];
planner_reverse_pass_kernel(block[0], block[1], block[2]);
}
}
}
// The kernel called by planner_recalculate() when scanning the plan from first to last entry.
void planner_forward_pass_kernel(block_t *previous, block_t *current, block_t *next) {
if(!previous) {
return;
}
// If the previous block is an acceleration block, but it is not long enough to complete the
// full speed change within the block, we need to adjust the entry speed accordingly. Entry
// speeds have already been reset, maximized, and reverse planned by reverse planner.
// If nominal length is true, max junction speed is guaranteed to be reached. No need to recheck.
if (!previous->nominal_length_flag) {
if (previous->entry_speed < current->entry_speed) {
double entry_speed = min( current->entry_speed,
max_allowable_speed(-previous->acceleration,previous->entry_speed,previous->millimeters) );
// Check for junction speed change
if (current->entry_speed != entry_speed) {
current->entry_speed = entry_speed;
current->recalculate_flag = true;
}
}
}
}
// planner_recalculate() needs to go over the current plan twice. Once in reverse and once forward. This
// implements the forward pass.
void planner_forward_pass() {
uint8_t block_index = block_buffer_tail;
block_t *block[3] = {
NULL, NULL, NULL };
while(block_index != block_buffer_head) {
block[0] = block[1];
block[1] = block[2];
block[2] = &block_buffer[block_index];
planner_forward_pass_kernel(block[0],block[1],block[2]);
block_index = next_block_index(block_index);
}
planner_forward_pass_kernel(block[1], block[2], NULL);
}
// Recalculates the trapezoid speed profiles for all blocks in the plan according to the
// entry_factor for each junction. Must be called by planner_recalculate() after
// updating the blocks.
void planner_recalculate_trapezoids() {
int8_t block_index = block_buffer_tail;
block_t *current;
block_t *next = NULL;
while(block_index != block_buffer_head) {
current = next;
next = &block_buffer[block_index];
if (current) {
// Recalculate if current block entry or exit junction speed has changed.
if (current->recalculate_flag || next->recalculate_flag) {
// NOTE: Entry and exit factors always > 0 by all previous logic operations.
calculate_trapezoid_for_block(current, current->entry_speed/current->nominal_speed,
next->entry_speed/current->nominal_speed);
current->recalculate_flag = false; // Reset current only to ensure next trapezoid is computed
}
}
block_index = next_block_index( block_index );
}
// Last/newest block in buffer. Exit speed is set with MINIMUM_PLANNER_SPEED. Always recalculated.
if(next != NULL) {
calculate_trapezoid_for_block(next, next->entry_speed/next->nominal_speed,
MINIMUM_PLANNER_SPEED/next->nominal_speed);
next->recalculate_flag = false;
}
}
// Recalculates the motion plan according to the following algorithm:
//
// 1. Go over every block in reverse order and calculate a junction speed reduction (i.e. block_t.entry_factor)
// so that:
// a. The junction jerk is within the set limit
// b. No speed reduction within one block requires faster deceleration than the one, true constant
// acceleration.
// 2. Go over every block in chronological order and dial down junction speed reduction values if
// a. The speed increase within one block would require faster accelleration than the one, true
// constant acceleration.
//
// When these stages are complete all blocks have an entry_factor that will allow all speed changes to
// be performed using only the one, true constant acceleration, and where no junction jerk is jerkier than
// the set limit. Finally it will:
//
// 3. Recalculate trapezoids for all blocks.
void planner_recalculate() {
planner_reverse_pass();
planner_forward_pass();
planner_recalculate_trapezoids();
}
void plan_init() {
block_buffer_head = 0;
block_buffer_tail = 0;
memset(position, 0, sizeof(position)); // clear position
previous_speed[0] = 0.0;
previous_speed[1] = 0.0;
previous_speed[2] = 0.0;
previous_speed[3] = 0.0;
previous_nominal_speed = 0.0;
}
#ifdef AUTOTEMP
void getHighESpeed()
{
static float oldt=0;
if(!autotemp_enabled){
return;
}
if(degTargetHotend0()+2<autotemp_min) { //probably temperature set to zero.
return; //do nothing
}
float high=0.0;
uint8_t block_index = block_buffer_tail;
while(block_index != block_buffer_head) {
if((block_buffer[block_index].steps_x != 0) ||
(block_buffer[block_index].steps_y != 0) ||
(block_buffer[block_index].steps_z != 0)) {
float se=(float(block_buffer[block_index].steps_e)/float(block_buffer[block_index].step_event_count))*block_buffer[block_index].nominal_speed;
//se; mm/sec;
if(se>high)
{
high=se;
}
}
block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1);
}
float g=autotemp_min+high*autotemp_factor;
float t=g;
if(t<autotemp_min)
t=autotemp_min;
if(t>autotemp_max)
t=autotemp_max;
if(oldt>t)
{
t=AUTOTEMP_OLDWEIGHT*oldt+(1-AUTOTEMP_OLDWEIGHT)*t;
}
oldt=t;
setTargetHotend0(t);
}
#endif
void check_axes_activity() {
unsigned char x_active = 0;
unsigned char y_active = 0;
unsigned char z_active = 0;
unsigned char e_active = 0;
unsigned char fan_speed = 0;
unsigned char tail_fan_speed = 0;
block_t *block;
if(block_buffer_tail != block_buffer_head) {
uint8_t block_index = block_buffer_tail;
tail_fan_speed = block_buffer[block_index].fan_speed;
while(block_index != block_buffer_head) {
block = &block_buffer[block_index];
if(block->steps_x != 0) x_active++;
if(block->steps_y != 0) y_active++;
if(block->steps_z != 0) z_active++;
if(block->steps_e != 0) e_active++;
if(block->fan_speed != 0) fan_speed++;
block_index = (block_index+1) & (BLOCK_BUFFER_SIZE - 1);
}
}
else {
#if FAN_PIN > -1
if (FanSpeed != 0){
analogWrite(FAN_PIN,FanSpeed); // If buffer is empty use current fan speed
}
#endif
}
if((DISABLE_X) && (x_active == 0)) disable_x();
if((DISABLE_Y) && (y_active == 0)) disable_y();
if((DISABLE_Z) && (z_active == 0)) disable_z();
if((DISABLE_E) && (e_active == 0)) {
disable_e0();
disable_e1();
disable_e2();
}
#if FAN_PIN > -1
if((FanSpeed == 0) && (fan_speed ==0)) {
analogWrite(FAN_PIN, 0);
}
if (FanSpeed != 0 && tail_fan_speed !=0) {
analogWrite(FAN_PIN,tail_fan_speed);
}
#endif
#ifdef AUTOTEMP
getHighESpeed();
#endif
}
float junction_deviation = 0.1;
// Add a new linear movement to the buffer. steps_x, _y and _z is the absolute position in
// mm. Microseconds specify how many microseconds the move should take to perform. To aid acceleration
// calculation the caller must also provide the physical length of the line in millimeters.
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder)
{
// Calculate the buffer head after we push this byte
int next_buffer_head = next_block_index(block_buffer_head);
// If the buffer is full: good! That means we are well ahead of the robot.
// Rest here until there is room in the buffer.
while(block_buffer_tail == next_buffer_head) {
manage_heater();
manage_inactivity();
LCD_STATUS;
}
// The target position of the tool in absolute steps
// Calculate target position in absolute steps
//this should be done after the wait, because otherwise a M92 code within the gcode disrupts this calculation somehow
long target[4];
target[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
target[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
target[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
target[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
#ifdef PREVENT_DANGEROUS_EXTRUDE
if(target[E_AXIS]!=position[E_AXIS])
if(degHotend(active_extruder)<EXTRUDE_MINTEMP && !allow_cold_extrude)
{
position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_ERR_COLD_EXTRUDE_STOP);
}
#ifdef PREVENT_LENGTHY_EXTRUDE
if(labs(target[E_AXIS]-position[E_AXIS])>axis_steps_per_unit[E_AXIS]*EXTRUDE_MAXLENGTH)
{
position[E_AXIS]=target[E_AXIS]; //behave as if the move really took place, but ignore E part
SERIAL_ECHO_START;
SERIAL_ECHOLNPGM(MSG_ERR_LONG_EXTRUDE_STOP);
}
#endif
#endif
// Prepare to set up new block
block_t *block = &block_buffer[block_buffer_head];
// Mark block as not busy (Not executed by the stepper interrupt)
block->busy = false;
// Number of steps for each axis
block->steps_x = labs(target[X_AXIS]-position[X_AXIS]);
block->steps_y = labs(target[Y_AXIS]-position[Y_AXIS]);
block->steps_z = labs(target[Z_AXIS]-position[Z_AXIS]);
block->steps_e = labs(target[E_AXIS]-position[E_AXIS]);
block->steps_e *= extrudemultiply;
block->steps_e /= 100;
block->step_event_count = max(block->steps_x, max(block->steps_y, max(block->steps_z, block->steps_e)));
// Bail if this is a zero-length block
if (block->step_event_count <= dropsegments) {
return;
};
block->fan_speed = FanSpeed;
// Compute direction bits for this block
block->direction_bits = 0;
if (target[X_AXIS] < position[X_AXIS]) {
block->direction_bits |= (1<<X_AXIS);
}
if (target[Y_AXIS] < position[Y_AXIS]) {
block->direction_bits |= (1<<Y_AXIS);
}
if (target[Z_AXIS] < position[Z_AXIS]) {
block->direction_bits |= (1<<Z_AXIS);
}
if (target[E_AXIS] < position[E_AXIS]) {
block->direction_bits |= (1<<E_AXIS);
}
block->active_extruder = extruder;
//enable active axes
if(block->steps_x != 0) enable_x();
if(block->steps_y != 0) enable_y();
#ifndef Z_LATE_ENABLE
if(block->steps_z != 0) enable_z();
#endif
// Enable all
if(block->steps_e != 0) {
enable_e0();
enable_e1();
enable_e2();
}
if (block->steps_e == 0) {
if(feed_rate<mintravelfeedrate) feed_rate=mintravelfeedrate;
}
else {
if(feed_rate<minimumfeedrate) feed_rate=minimumfeedrate;
}
float delta_mm[4];
delta_mm[X_AXIS] = (target[X_AXIS]-position[X_AXIS])/axis_steps_per_unit[X_AXIS];
delta_mm[Y_AXIS] = (target[Y_AXIS]-position[Y_AXIS])/axis_steps_per_unit[Y_AXIS];
delta_mm[Z_AXIS] = (target[Z_AXIS]-position[Z_AXIS])/axis_steps_per_unit[Z_AXIS];
delta_mm[E_AXIS] = ((target[E_AXIS]-position[E_AXIS])/axis_steps_per_unit[E_AXIS])*extrudemultiply/100.0;
if ( block->steps_x <=dropsegments && block->steps_y <=dropsegments && block->steps_z <=dropsegments ) {
block->millimeters = fabs(delta_mm[E_AXIS]);
}
else {
block->millimeters = sqrt(square(delta_mm[X_AXIS]) + square(delta_mm[Y_AXIS]) + square(delta_mm[Z_AXIS]));
}
float inverse_millimeters = 1.0/block->millimeters; // Inverse millimeters to remove multiple divides
// Calculate speed in mm/second for each axis. No divide by zero due to previous checks.
float inverse_second = feed_rate * inverse_millimeters;
int moves_queued=(block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);
// slow down when de buffer starts to empty, rather than wait at the corner for a buffer refill
#ifdef OLD_SLOWDOWN
if(moves_queued < (BLOCK_BUFFER_SIZE * 0.5) && moves_queued > 1) feed_rate = feed_rate*moves_queued / (BLOCK_BUFFER_SIZE * 0.5);
#endif
#ifdef SLOWDOWN
// segment time im micro seconds
unsigned long segment_time = lround(1000000.0/inverse_second);
if ((moves_queued > 1) && (moves_queued < (BLOCK_BUFFER_SIZE * 0.5))) {
if (segment_time < minsegmenttime) { // buffer is draining, add extra time. The amount of time added increases if the buffer is still emptied more.
inverse_second=1000000.0/(segment_time+lround(2*(minsegmenttime-segment_time)/moves_queued));
}
}
#endif
// END OF SLOW DOWN SECTION
block->nominal_speed = block->millimeters * inverse_second; // (mm/sec) Always > 0
block->nominal_rate = ceil(block->step_event_count * inverse_second); // (step/sec) Always > 0
// Calculate and limit speed in mm/sec for each axis
float current_speed[4];
float speed_factor = 1.0; //factor <=1 do decrease speed
for(int i=0; i < 4; i++) {
current_speed[i] = delta_mm[i] * inverse_second;
if(fabs(current_speed[i]) > max_feedrate[i])
speed_factor = min(speed_factor, max_feedrate[i] / fabs(current_speed[i]));
}
// Max segement time in us.
#ifdef XY_FREQUENCY_LIMIT
#define MAX_FREQ_TIME (1000000.0/XY_FREQUENCY_LIMIT)
// Check and limit the xy direction change frequency
unsigned char direction_change = block->direction_bits ^ old_direction_bits;
old_direction_bits = block->direction_bits;
if((direction_change & (1<<X_AXIS)) == 0) {
x_segment_time[0] += segment_time;
}
else {
x_segment_time[2] = x_segment_time[1];
x_segment_time[1] = x_segment_time[0];
x_segment_time[0] = segment_time;
}
if((direction_change & (1<<Y_AXIS)) == 0) {
y_segment_time[0] += segment_time;
}
else {
y_segment_time[2] = y_segment_time[1];
y_segment_time[1] = y_segment_time[0];
y_segment_time[0] = segment_time;
}
long max_x_segment_time = max(x_segment_time[0], max(x_segment_time[1], x_segment_time[2]));
long max_y_segment_time = max(y_segment_time[0], max(y_segment_time[1], y_segment_time[2]));
long min_xy_segment_time =min(max_x_segment_time, max_y_segment_time);
if(min_xy_segment_time < MAX_FREQ_TIME) speed_factor = min(speed_factor, speed_factor * (float)min_xy_segment_time / (float)MAX_FREQ_TIME);
#endif
// Correct the speed
if( speed_factor < 1.0) {
for(unsigned char i=0; i < 4; i++) {
current_speed[i] *= speed_factor;
}
block->nominal_speed *= speed_factor;
block->nominal_rate *= speed_factor;
}
// Compute and limit the acceleration rate for the trapezoid generator.
float steps_per_mm = block->step_event_count/block->millimeters;
if(block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0) {
block->acceleration_st = ceil(retract_acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
}
else {
block->acceleration_st = ceil(acceleration * steps_per_mm); // convert to: acceleration steps/sec^2
// Limit acceleration per axis
if(((float)block->acceleration_st * (float)block->steps_x / (float)block->step_event_count) > axis_steps_per_sqr_second[X_AXIS])
block->acceleration_st = axis_steps_per_sqr_second[X_AXIS];
if(((float)block->acceleration_st * (float)block->steps_y / (float)block->step_event_count) > axis_steps_per_sqr_second[Y_AXIS])
block->acceleration_st = axis_steps_per_sqr_second[Y_AXIS];
if(((float)block->acceleration_st * (float)block->steps_e / (float)block->step_event_count) > axis_steps_per_sqr_second[E_AXIS])
block->acceleration_st = axis_steps_per_sqr_second[E_AXIS];
if(((float)block->acceleration_st * (float)block->steps_z / (float)block->step_event_count ) > axis_steps_per_sqr_second[Z_AXIS])
block->acceleration_st = axis_steps_per_sqr_second[Z_AXIS];
}
block->acceleration = block->acceleration_st / steps_per_mm;
block->acceleration_rate = (long)((float)block->acceleration_st * 8.388608);
#if 0 // Use old jerk for now
// Compute path unit vector
double unit_vec[3];
unit_vec[X_AXIS] = delta_mm[X_AXIS]*inverse_millimeters;
unit_vec[Y_AXIS] = delta_mm[Y_AXIS]*inverse_millimeters;
unit_vec[Z_AXIS] = delta_mm[Z_AXIS]*inverse_millimeters;
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
// Let a circle be tangent to both previous and current path line segments, where the junction
// deviation is defined as the distance from the junction to the closest edge of the circle,
// colinear with the circle center. The circular segment joining the two paths represents the
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
// radius of the circle, defined indirectly by junction deviation. This may be also viewed as
// path width or max_jerk in the previous grbl version. This approach does not actually deviate
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
// nonlinearities of both the junction angle and junction velocity.
double vmax_junction = MINIMUM_PLANNER_SPEED; // Set default max junction speed
// Skip first block or when previous_nominal_speed is used as a flag for homing and offset cycles.
if ((block_buffer_head != block_buffer_tail) && (previous_nominal_speed > 0.0)) {
// Compute cosine of angle between previous and current path. (prev_unit_vec is negative)
// NOTE: Max junction velocity is computed without sin() or acos() by trig half angle identity.
double cos_theta = - previous_unit_vec[X_AXIS] * unit_vec[X_AXIS]
- previous_unit_vec[Y_AXIS] * unit_vec[Y_AXIS]
- previous_unit_vec[Z_AXIS] * unit_vec[Z_AXIS] ;
// Skip and use default max junction speed for 0 degree acute junction.
if (cos_theta < 0.95) {
vmax_junction = min(previous_nominal_speed,block->nominal_speed);
// Skip and avoid divide by zero for straight junctions at 180 degrees. Limit to min() of nominal speeds.
if (cos_theta > -0.95) {
// Compute maximum junction velocity based on maximum acceleration and junction deviation
double sin_theta_d2 = sqrt(0.5*(1.0-cos_theta)); // Trig half angle identity. Always positive.
vmax_junction = min(vmax_junction,
sqrt(block->acceleration * junction_deviation * sin_theta_d2/(1.0-sin_theta_d2)) );
}
}
}
#endif
// Start with a safe speed
float vmax_junction = max_xy_jerk/2;
float vmax_junction_factor = 1.0;
if(fabs(current_speed[Z_AXIS]) > max_z_jerk/2)
vmax_junction = min(vmax_junction, max_z_jerk/2);
if(fabs(current_speed[E_AXIS]) > max_e_jerk/2)
vmax_junction = min(vmax_junction, max_e_jerk/2);
vmax_junction = min(vmax_junction, block->nominal_speed);
float safe_speed = vmax_junction;
if ((moves_queued > 1) && (previous_nominal_speed > 0.0001)) {
float jerk = sqrt(pow((current_speed[X_AXIS]-previous_speed[X_AXIS]), 2)+pow((current_speed[Y_AXIS]-previous_speed[Y_AXIS]), 2));
// if((fabs(previous_speed[X_AXIS]) > 0.0001) || (fabs(previous_speed[Y_AXIS]) > 0.0001)) {
vmax_junction = block->nominal_speed;
// }
if (jerk > max_xy_jerk) {
vmax_junction_factor = (max_xy_jerk/jerk);
}
if(fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS]) > max_z_jerk) {
vmax_junction_factor= min(vmax_junction_factor, (max_z_jerk/fabs(current_speed[Z_AXIS] - previous_speed[Z_AXIS])));
}
if(fabs(current_speed[E_AXIS] - previous_speed[E_AXIS]) > max_e_jerk) {
vmax_junction_factor = min(vmax_junction_factor, (max_e_jerk/fabs(current_speed[E_AXIS] - previous_speed[E_AXIS])));
}
vmax_junction = min(previous_nominal_speed, vmax_junction * vmax_junction_factor); // Limit speed to max previous speed
}
block->max_entry_speed = vmax_junction;
// Initialize block entry speed. Compute based on deceleration to user-defined MINIMUM_PLANNER_SPEED.
double v_allowable = max_allowable_speed(-block->acceleration,MINIMUM_PLANNER_SPEED,block->millimeters);
block->entry_speed = min(vmax_junction, v_allowable);
// Initialize planner efficiency flags
// Set flag if block will always reach maximum junction speed regardless of entry/exit speeds.
// If a block can de/ac-celerate from nominal speed to zero within the length of the block, then
// the current block and next block junction speeds are guaranteed to always be at their maximum
// junction speeds in deceleration and acceleration, respectively. This is due to how the current
// block nominal speed limits both the current and next maximum junction speeds. Hence, in both
// the reverse and forward planners, the corresponding block junction speed will always be at the
// the maximum junction speed and may always be ignored for any speed reduction checks.
if (block->nominal_speed <= v_allowable) {
block->nominal_length_flag = true;
}
else {
block->nominal_length_flag = false;
}
block->recalculate_flag = true; // Always calculate trapezoid for new block
// Update previous path unit_vector and nominal speed
memcpy(previous_speed, current_speed, sizeof(previous_speed)); // previous_speed[] = current_speed[]
previous_nominal_speed = block->nominal_speed;
#ifdef ADVANCE
// Calculate advance rate
if((block->steps_e == 0) || (block->steps_x == 0 && block->steps_y == 0 && block->steps_z == 0)) {
block->advance_rate = 0;
block->advance = 0;
}
else {
long acc_dist = estimate_acceleration_distance(0, block->nominal_rate, block->acceleration_st);
float advance = (STEPS_PER_CUBIC_MM_E * EXTRUDER_ADVANCE_K) *
(current_speed[E_AXIS] * current_speed[E_AXIS] * EXTRUTION_AREA * EXTRUTION_AREA)*256;
block->advance = advance;
if(acc_dist == 0) {
block->advance_rate = 0;
}
else {
block->advance_rate = advance / (float)acc_dist;
}
}
/*
SERIAL_ECHO_START;
SERIAL_ECHOPGM("advance :");
SERIAL_ECHO(block->advance/256.0);
SERIAL_ECHOPGM("advance rate :");
SERIAL_ECHOLN(block->advance_rate/256.0);
*/
#endif // ADVANCE
calculate_trapezoid_for_block(block, block->entry_speed/block->nominal_speed,
safe_speed/block->nominal_speed);
// Move buffer head
block_buffer_head = next_buffer_head;
// Update position
memcpy(position, target, sizeof(target)); // position[] = target[]
planner_recalculate();
st_wake_up();
}
void plan_set_position(const float &x, const float &y, const float &z, const float &e)
{
position[X_AXIS] = lround(x*axis_steps_per_unit[X_AXIS]);
position[Y_AXIS] = lround(y*axis_steps_per_unit[Y_AXIS]);
position[Z_AXIS] = lround(z*axis_steps_per_unit[Z_AXIS]);
position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
st_set_position(position[X_AXIS], position[Y_AXIS], position[Z_AXIS], position[E_AXIS]);
previous_nominal_speed = 0.0; // Resets planner junction speeds. Assumes start from rest.
previous_speed[0] = 0.0;
previous_speed[1] = 0.0;
previous_speed[2] = 0.0;
previous_speed[3] = 0.0;
}
void plan_set_e_position(const float &e)
{
position[E_AXIS] = lround(e*axis_steps_per_unit[E_AXIS]);
st_set_e_position(position[E_AXIS]);
}
uint8_t movesplanned()
{
return (block_buffer_head-block_buffer_tail + BLOCK_BUFFER_SIZE) & (BLOCK_BUFFER_SIZE - 1);
}
void allow_cold_extrudes(bool allow)
{
#ifdef PREVENT_DANGEROUS_EXTRUDE
allow_cold_extrude=allow;
#endif
}

@ -0,0 +1,139 @@
/*
planner.h - buffers movement commands and manages the acceleration profile plan
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
// This module is to be considered a sub-module of stepper.c. Please don't include
// this file from any other module.
#ifndef planner_h
#define planner_h
#include "Marlin.h"
// This struct is used when buffering the setup for each linear movement "nominal" values are as specified in
// the source g-code and may never actually be reached if acceleration management is active.
typedef struct {
// Fields used by the bresenham algorithm for tracing the line
long steps_x, steps_y, steps_z, steps_e; // Step count along each axis
unsigned long step_event_count; // The number of step events required to complete this block
long accelerate_until; // The index of the step event on which to stop acceleration
long decelerate_after; // The index of the step event on which to start decelerating
long acceleration_rate; // The acceleration rate used for acceleration calculation
unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
unsigned char active_extruder; // Selects the active extruder
#ifdef ADVANCE
long advance_rate;
volatile long initial_advance;
volatile long final_advance;
float advance;
#endif
// Fields used by the motion planner to manage acceleration
// float speed_x, speed_y, speed_z, speed_e; // Nominal mm/sec for each axis
float nominal_speed; // The nominal speed for this block in mm/sec
float entry_speed; // Entry speed at previous-current junction in mm/sec
float max_entry_speed; // Maximum allowable junction entry speed in mm/sec
float millimeters; // The total travel of this block in mm
float acceleration; // acceleration mm/sec^2
unsigned char recalculate_flag; // Planner flag to recalculate trapezoids on entry junction
unsigned char nominal_length_flag; // Planner flag for nominal speed always reached
// Settings for the trapezoid generator
unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec
unsigned long initial_rate; // The jerk-adjusted step rate at start of block
unsigned long final_rate; // The minimal rate at exit
unsigned long acceleration_st; // acceleration steps/sec^2
unsigned long fan_speed;
volatile char busy;
} block_t;
// Initialize the motion plan subsystem
void plan_init();
// Add a new linear movement to the buffer. x, y and z is the signed, absolute target position in
// millimaters. Feed rate specifies the speed of the motion.
void plan_buffer_line(const float &x, const float &y, const float &z, const float &e, float feed_rate, const uint8_t &extruder);
// Set position. Used for G92 instructions.
void plan_set_position(const float &x, const float &y, const float &z, const float &e);
void plan_set_e_position(const float &e);
void check_axes_activity();
uint8_t movesplanned(); //return the nr of buffered moves
extern unsigned long minsegmenttime;
extern float max_feedrate[4]; // set the max speeds
extern float axis_steps_per_unit[4];
extern unsigned long max_acceleration_units_per_sq_second[4]; // Use M201 to override by software
extern float minimumfeedrate;
extern float acceleration; // Normal acceleration mm/s^2 THIS IS THE DEFAULT ACCELERATION for all moves. M204 SXXXX
extern float retract_acceleration; // mm/s^2 filament pull-pack and push-forward while standing still in the other axis M204 TXXXX
extern float max_xy_jerk; //speed than can be stopped at once, if i understand correctly.
extern float max_z_jerk;
extern float max_e_jerk;
extern float mintravelfeedrate;
extern unsigned long axis_steps_per_sqr_second[NUM_AXIS];
#ifdef AUTOTEMP
extern bool autotemp_enabled;
extern float autotemp_max;
extern float autotemp_min;
extern float autotemp_factor;
#endif
extern block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
extern volatile unsigned char block_buffer_head; // Index of the next block to be pushed
extern volatile unsigned char block_buffer_tail;
// Called when the current block is no longer needed. Discards the block and makes the memory
// availible for new blocks.
FORCE_INLINE void plan_discard_current_block()
{
if (block_buffer_head != block_buffer_tail) {
block_buffer_tail = (block_buffer_tail + 1) & (BLOCK_BUFFER_SIZE - 1);
}
}
// Gets the current block. Returns NULL if buffer empty
FORCE_INLINE block_t *plan_get_current_block()
{
if (block_buffer_head == block_buffer_tail) {
return(NULL);
}
block_t *block = &block_buffer[block_buffer_tail];
block->busy = true;
return(block);
}
// Gets the current block. Returns NULL if buffer empty
FORCE_INLINE bool blocks_queued()
{
if (block_buffer_head == block_buffer_tail) {
return false;
}
else
return true;
}
void allow_cold_extrudes(bool allow);
#endif

@ -0,0 +1,152 @@
#ifndef SPEED_LOOKUPTABLE_H
#define SPEED_LOOKUPTABLE_H
#include "Marlin.h"
#if F_CPU == 16000000
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {\
{ 62500, 55556}, { 6944, 3268}, { 3676, 1176}, { 2500, 607}, { 1893, 369}, { 1524, 249}, { 1275, 179}, { 1096, 135},
{ 961, 105}, { 856, 85}, { 771, 69}, { 702, 58}, { 644, 49}, { 595, 42}, { 553, 37}, { 516, 32},
{ 484, 28}, { 456, 25}, { 431, 23}, { 408, 20}, { 388, 19}, { 369, 16}, { 353, 16}, { 337, 14},
{ 323, 13}, { 310, 11}, { 299, 11}, { 288, 11}, { 277, 9}, { 268, 9}, { 259, 8}, { 251, 8},
{ 243, 8}, { 235, 7}, { 228, 6}, { 222, 6}, { 216, 6}, { 210, 6}, { 204, 5}, { 199, 5},
{ 194, 5}, { 189, 4}, { 185, 4}, { 181, 4}, { 177, 4}, { 173, 4}, { 169, 4}, { 165, 3},
{ 162, 3}, { 159, 4}, { 155, 3}, { 152, 3}, { 149, 2}, { 147, 3}, { 144, 3}, { 141, 2},
{ 139, 3}, { 136, 2}, { 134, 2}, { 132, 3}, { 129, 2}, { 127, 2}, { 125, 2}, { 123, 2},
{ 121, 2}, { 119, 1}, { 118, 2}, { 116, 2}, { 114, 1}, { 113, 2}, { 111, 2}, { 109, 1},
{ 108, 2}, { 106, 1}, { 105, 2}, { 103, 1}, { 102, 1}, { 101, 1}, { 100, 2}, { 98, 1},
{ 97, 1}, { 96, 1}, { 95, 2}, { 93, 1}, { 92, 1}, { 91, 1}, { 90, 1}, { 89, 1},
{ 88, 1}, { 87, 1}, { 86, 1}, { 85, 1}, { 84, 1}, { 83, 0}, { 83, 1}, { 82, 1},
{ 81, 1}, { 80, 1}, { 79, 1}, { 78, 0}, { 78, 1}, { 77, 1}, { 76, 1}, { 75, 0},
{ 75, 1}, { 74, 1}, { 73, 1}, { 72, 0}, { 72, 1}, { 71, 1}, { 70, 0}, { 70, 1},
{ 69, 0}, { 69, 1}, { 68, 1}, { 67, 0}, { 67, 1}, { 66, 0}, { 66, 1}, { 65, 0},
{ 65, 1}, { 64, 1}, { 63, 0}, { 63, 1}, { 62, 0}, { 62, 1}, { 61, 0}, { 61, 1},
{ 60, 0}, { 60, 0}, { 60, 1}, { 59, 0}, { 59, 1}, { 58, 0}, { 58, 1}, { 57, 0},
{ 57, 1}, { 56, 0}, { 56, 0}, { 56, 1}, { 55, 0}, { 55, 1}, { 54, 0}, { 54, 0},
{ 54, 1}, { 53, 0}, { 53, 0}, { 53, 1}, { 52, 0}, { 52, 0}, { 52, 1}, { 51, 0},
{ 51, 0}, { 51, 1}, { 50, 0}, { 50, 0}, { 50, 1}, { 49, 0}, { 49, 0}, { 49, 1},
{ 48, 0}, { 48, 0}, { 48, 1}, { 47, 0}, { 47, 0}, { 47, 0}, { 47, 1}, { 46, 0},
{ 46, 0}, { 46, 1}, { 45, 0}, { 45, 0}, { 45, 0}, { 45, 1}, { 44, 0}, { 44, 0},
{ 44, 0}, { 44, 1}, { 43, 0}, { 43, 0}, { 43, 0}, { 43, 1}, { 42, 0}, { 42, 0},
{ 42, 0}, { 42, 1}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 0}, { 41, 1}, { 40, 0},
{ 40, 0}, { 40, 0}, { 40, 0}, { 40, 1}, { 39, 0}, { 39, 0}, { 39, 0}, { 39, 0},
{ 39, 1}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 0}, { 38, 1}, { 37, 0}, { 37, 0},
{ 37, 0}, { 37, 0}, { 37, 0}, { 37, 1}, { 36, 0}, { 36, 0}, { 36, 0}, { 36, 0},
{ 36, 1}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 0}, { 35, 1},
{ 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 0}, { 34, 1}, { 33, 0}, { 33, 0},
{ 33, 0}, { 33, 0}, { 33, 0}, { 33, 0}, { 33, 1}, { 32, 0}, { 32, 0}, { 32, 0},
{ 32, 0}, { 32, 0}, { 32, 0}, { 32, 0}, { 32, 1}, { 31, 0}, { 31, 0}, { 31, 0},
{ 31, 0}, { 31, 0}, { 31, 0}, { 31, 1}, { 30, 0}, { 30, 0}, { 30, 0}, { 30, 0}
};
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {\
{ 62500, 12500}, { 50000, 8334}, { 41666, 5952}, { 35714, 4464}, { 31250, 3473}, { 27777, 2777}, { 25000, 2273}, { 22727, 1894},
{ 20833, 1603}, { 19230, 1373}, { 17857, 1191}, { 16666, 1041}, { 15625, 920}, { 14705, 817}, { 13888, 731}, { 13157, 657},
{ 12500, 596}, { 11904, 541}, { 11363, 494}, { 10869, 453}, { 10416, 416}, { 10000, 385}, { 9615, 356}, { 9259, 331},
{ 8928, 308}, { 8620, 287}, { 8333, 269}, { 8064, 252}, { 7812, 237}, { 7575, 223}, { 7352, 210}, { 7142, 198},
{ 6944, 188}, { 6756, 178}, { 6578, 168}, { 6410, 160}, { 6250, 153}, { 6097, 145}, { 5952, 139}, { 5813, 132},
{ 5681, 126}, { 5555, 121}, { 5434, 115}, { 5319, 111}, { 5208, 106}, { 5102, 102}, { 5000, 99}, { 4901, 94},
{ 4807, 91}, { 4716, 87}, { 4629, 84}, { 4545, 81}, { 4464, 79}, { 4385, 75}, { 4310, 73}, { 4237, 71},
{ 4166, 68}, { 4098, 66}, { 4032, 64}, { 3968, 62}, { 3906, 60}, { 3846, 59}, { 3787, 56}, { 3731, 55},
{ 3676, 53}, { 3623, 52}, { 3571, 50}, { 3521, 49}, { 3472, 48}, { 3424, 46}, { 3378, 45}, { 3333, 44},
{ 3289, 43}, { 3246, 41}, { 3205, 41}, { 3164, 39}, { 3125, 39}, { 3086, 38}, { 3048, 36}, { 3012, 36},
{ 2976, 35}, { 2941, 35}, { 2906, 33}, { 2873, 33}, { 2840, 32}, { 2808, 31}, { 2777, 30}, { 2747, 30},
{ 2717, 29}, { 2688, 29}, { 2659, 28}, { 2631, 27}, { 2604, 27}, { 2577, 26}, { 2551, 26}, { 2525, 25},
{ 2500, 25}, { 2475, 25}, { 2450, 23}, { 2427, 24}, { 2403, 23}, { 2380, 22}, { 2358, 22}, { 2336, 22},
{ 2314, 21}, { 2293, 21}, { 2272, 20}, { 2252, 20}, { 2232, 20}, { 2212, 20}, { 2192, 19}, { 2173, 18},
{ 2155, 19}, { 2136, 18}, { 2118, 18}, { 2100, 17}, { 2083, 17}, { 2066, 17}, { 2049, 17}, { 2032, 16},
{ 2016, 16}, { 2000, 16}, { 1984, 16}, { 1968, 15}, { 1953, 16}, { 1937, 14}, { 1923, 15}, { 1908, 15},
{ 1893, 14}, { 1879, 14}, { 1865, 14}, { 1851, 13}, { 1838, 14}, { 1824, 13}, { 1811, 13}, { 1798, 13},
{ 1785, 12}, { 1773, 13}, { 1760, 12}, { 1748, 12}, { 1736, 12}, { 1724, 12}, { 1712, 12}, { 1700, 11},
{ 1689, 12}, { 1677, 11}, { 1666, 11}, { 1655, 11}, { 1644, 11}, { 1633, 10}, { 1623, 11}, { 1612, 10},
{ 1602, 10}, { 1592, 10}, { 1582, 10}, { 1572, 10}, { 1562, 10}, { 1552, 9}, { 1543, 10}, { 1533, 9},
{ 1524, 9}, { 1515, 9}, { 1506, 9}, { 1497, 9}, { 1488, 9}, { 1479, 9}, { 1470, 9}, { 1461, 8},
{ 1453, 8}, { 1445, 9}, { 1436, 8}, { 1428, 8}, { 1420, 8}, { 1412, 8}, { 1404, 8}, { 1396, 8},
{ 1388, 7}, { 1381, 8}, { 1373, 7}, { 1366, 8}, { 1358, 7}, { 1351, 7}, { 1344, 8}, { 1336, 7},
{ 1329, 7}, { 1322, 7}, { 1315, 7}, { 1308, 6}, { 1302, 7}, { 1295, 7}, { 1288, 6}, { 1282, 7},
{ 1275, 6}, { 1269, 7}, { 1262, 6}, { 1256, 6}, { 1250, 7}, { 1243, 6}, { 1237, 6}, { 1231, 6},
{ 1225, 6}, { 1219, 6}, { 1213, 6}, { 1207, 6}, { 1201, 5}, { 1196, 6}, { 1190, 6}, { 1184, 5},
{ 1179, 6}, { 1173, 5}, { 1168, 6}, { 1162, 5}, { 1157, 5}, { 1152, 6}, { 1146, 5}, { 1141, 5},
{ 1136, 5}, { 1131, 5}, { 1126, 5}, { 1121, 5}, { 1116, 5}, { 1111, 5}, { 1106, 5}, { 1101, 5},
{ 1096, 5}, { 1091, 5}, { 1086, 4}, { 1082, 5}, { 1077, 5}, { 1072, 4}, { 1068, 5}, { 1063, 4},
{ 1059, 5}, { 1054, 4}, { 1050, 4}, { 1046, 5}, { 1041, 4}, { 1037, 4}, { 1033, 5}, { 1028, 4},
{ 1024, 4}, { 1020, 4}, { 1016, 4}, { 1012, 4}, { 1008, 4}, { 1004, 4}, { 1000, 4}, { 996, 4},
{ 992, 4}, { 988, 4}, { 984, 4}, { 980, 4}, { 976, 4}, { 972, 4}, { 968, 3}, { 965, 3}
};
#else
const uint16_t speed_lookuptable_fast[256][2] PROGMEM = {
{62500, 54055}, {8445, 3917}, {4528, 1434}, {3094, 745}, {2349, 456}, {1893, 307}, {1586, 222}, {1364, 167},
{1197, 131}, {1066, 105}, {961, 86}, {875, 72}, {803, 61}, {742, 53}, {689, 45}, {644, 40},
{604, 35}, {569, 32}, {537, 28}, {509, 25}, {484, 23}, {461, 21}, {440, 19}, {421, 17},
{404, 16}, {388, 15}, {373, 14}, {359, 13}, {346, 12}, {334, 11}, {323, 10}, {313, 10},
{303, 9}, {294, 9}, {285, 8}, {277, 7}, {270, 8}, {262, 7}, {255, 6}, {249, 6},
{243, 6}, {237, 6}, {231, 5}, {226, 5}, {221, 5}, {216, 5}, {211, 4}, {207, 5},
{202, 4}, {198, 4}, {194, 4}, {190, 3}, {187, 4}, {183, 3}, {180, 3}, {177, 4},
{173, 3}, {170, 3}, {167, 2}, {165, 3}, {162, 3}, {159, 2}, {157, 3}, {154, 2},
{152, 3}, {149, 2}, {147, 2}, {145, 2}, {143, 2}, {141, 2}, {139, 2}, {137, 2},
{135, 2}, {133, 2}, {131, 2}, {129, 1}, {128, 2}, {126, 2}, {124, 1}, {123, 2},
{121, 1}, {120, 2}, {118, 1}, {117, 1}, {116, 2}, {114, 1}, {113, 1}, {112, 2},
{110, 1}, {109, 1}, {108, 1}, {107, 2}, {105, 1}, {104, 1}, {103, 1}, {102, 1},
{101, 1}, {100, 1}, {99, 1}, {98, 1}, {97, 1}, {96, 1}, {95, 1}, {94, 1},
{93, 1}, {92, 1}, {91, 0}, {91, 1}, {90, 1}, {89, 1}, {88, 1}, {87, 0},
{87, 1}, {86, 1}, {85, 1}, {84, 0}, {84, 1}, {83, 1}, {82, 1}, {81, 0},
{81, 1}, {80, 1}, {79, 0}, {79, 1}, {78, 0}, {78, 1}, {77, 1}, {76, 0},
{76, 1}, {75, 0}, {75, 1}, {74, 1}, {73, 0}, {73, 1}, {72, 0}, {72, 1},
{71, 0}, {71, 1}, {70, 0}, {70, 1}, {69, 0}, {69, 1}, {68, 0}, {68, 1},
{67, 0}, {67, 1}, {66, 0}, {66, 1}, {65, 0}, {65, 0}, {65, 1}, {64, 0},
{64, 1}, {63, 0}, {63, 1}, {62, 0}, {62, 0}, {62, 1}, {61, 0}, {61, 1},
{60, 0}, {60, 0}, {60, 1}, {59, 0}, {59, 0}, {59, 1}, {58, 0}, {58, 0},
{58, 1}, {57, 0}, {57, 0}, {57, 1}, {56, 0}, {56, 0}, {56, 1}, {55, 0},
{55, 0}, {55, 1}, {54, 0}, {54, 0}, {54, 1}, {53, 0}, {53, 0}, {53, 0},
{53, 1}, {52, 0}, {52, 0}, {52, 1}, {51, 0}, {51, 0}, {51, 0}, {51, 1},
{50, 0}, {50, 0}, {50, 0}, {50, 1}, {49, 0}, {49, 0}, {49, 0}, {49, 1},
{48, 0}, {48, 0}, {48, 0}, {48, 1}, {47, 0}, {47, 0}, {47, 0}, {47, 1},
{46, 0}, {46, 0}, {46, 0}, {46, 0}, {46, 1}, {45, 0}, {45, 0}, {45, 0},
{45, 1}, {44, 0}, {44, 0}, {44, 0}, {44, 0}, {44, 1}, {43, 0}, {43, 0},
{43, 0}, {43, 0}, {43, 1}, {42, 0}, {42, 0}, {42, 0}, {42, 0}, {42, 0},
{42, 1}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 0}, {41, 1}, {40, 0},
{40, 0}, {40, 0}, {40, 0}, {40, 1}, {39, 0}, {39, 0}, {39, 0}, {39, 0},
{39, 0}, {39, 0}, {39, 1}, {38, 0}, {38, 0}, {38, 0}, {38, 0}, {38, 0},
};
const uint16_t speed_lookuptable_slow[256][2] PROGMEM = {
{62500, 10417}, {52083, 7441}, {44642, 5580}, {39062, 4340}, {34722, 3472}, {31250, 2841}, {28409, 2368}, {26041, 2003},
{24038, 1717}, {22321, 1488}, {20833, 1302}, {19531, 1149}, {18382, 1021}, {17361, 914}, {16447, 822}, {15625, 745},
{14880, 676}, {14204, 618}, {13586, 566}, {13020, 520}, {12500, 481}, {12019, 445}, {11574, 414}, {11160, 385},
{10775, 359}, {10416, 336}, {10080, 315}, {9765, 296}, {9469, 278}, {9191, 263}, {8928, 248}, {8680, 235},
{8445, 222}, {8223, 211}, {8012, 200}, {7812, 191}, {7621, 181}, {7440, 173}, {7267, 165}, {7102, 158},
{6944, 151}, {6793, 145}, {6648, 138}, {6510, 133}, {6377, 127}, {6250, 123}, {6127, 118}, {6009, 113},
{5896, 109}, {5787, 106}, {5681, 101}, {5580, 98}, {5482, 95}, {5387, 91}, {5296, 88}, {5208, 86},
{5122, 82}, {5040, 80}, {4960, 78}, {4882, 75}, {4807, 73}, {4734, 70}, {4664, 69}, {4595, 67},
{4528, 64}, {4464, 63}, {4401, 61}, {4340, 60}, {4280, 58}, {4222, 56}, {4166, 55}, {4111, 53},
{4058, 52}, {4006, 51}, {3955, 49}, {3906, 48}, {3858, 48}, {3810, 45}, {3765, 45}, {3720, 44},
{3676, 43}, {3633, 42}, {3591, 40}, {3551, 40}, {3511, 39}, {3472, 38}, {3434, 38}, {3396, 36},
{3360, 36}, {3324, 35}, {3289, 34}, {3255, 34}, {3221, 33}, {3188, 32}, {3156, 31}, {3125, 31},
{3094, 31}, {3063, 30}, {3033, 29}, {3004, 28}, {2976, 28}, {2948, 28}, {2920, 27}, {2893, 27},
{2866, 26}, {2840, 25}, {2815, 25}, {2790, 25}, {2765, 24}, {2741, 24}, {2717, 24}, {2693, 23},
{2670, 22}, {2648, 22}, {2626, 22}, {2604, 22}, {2582, 21}, {2561, 21}, {2540, 20}, {2520, 20},
{2500, 20}, {2480, 20}, {2460, 19}, {2441, 19}, {2422, 19}, {2403, 18}, {2385, 18}, {2367, 18},
{2349, 17}, {2332, 18}, {2314, 17}, {2297, 16}, {2281, 17}, {2264, 16}, {2248, 16}, {2232, 16},
{2216, 16}, {2200, 15}, {2185, 15}, {2170, 15}, {2155, 15}, {2140, 15}, {2125, 14}, {2111, 14},
{2097, 14}, {2083, 14}, {2069, 14}, {2055, 13}, {2042, 13}, {2029, 13}, {2016, 13}, {2003, 13},
{1990, 13}, {1977, 12}, {1965, 12}, {1953, 13}, {1940, 11}, {1929, 12}, {1917, 12}, {1905, 12},
{1893, 11}, {1882, 11}, {1871, 11}, {1860, 11}, {1849, 11}, {1838, 11}, {1827, 11}, {1816, 10},
{1806, 11}, {1795, 10}, {1785, 10}, {1775, 10}, {1765, 10}, {1755, 10}, {1745, 9}, {1736, 10},
{1726, 9}, {1717, 10}, {1707, 9}, {1698, 9}, {1689, 9}, {1680, 9}, {1671, 9}, {1662, 9},
{1653, 9}, {1644, 8}, {1636, 9}, {1627, 8}, {1619, 9}, {1610, 8}, {1602, 8}, {1594, 8},
{1586, 8}, {1578, 8}, {1570, 8}, {1562, 8}, {1554, 7}, {1547, 8}, {1539, 8}, {1531, 7},
{1524, 8}, {1516, 7}, {1509, 7}, {1502, 7}, {1495, 7}, {1488, 7}, {1481, 7}, {1474, 7},
{1467, 7}, {1460, 7}, {1453, 7}, {1446, 6}, {1440, 7}, {1433, 7}, {1426, 6}, {1420, 6},
{1414, 7}, {1407, 6}, {1401, 6}, {1395, 7}, {1388, 6}, {1382, 6}, {1376, 6}, {1370, 6},
{1364, 6}, {1358, 6}, {1352, 6}, {1346, 5}, {1341, 6}, {1335, 6}, {1329, 5}, {1324, 6},
{1318, 5}, {1313, 6}, {1307, 5}, {1302, 6}, {1296, 5}, {1291, 5}, {1286, 6}, {1280, 5},
{1275, 5}, {1270, 5}, {1265, 5}, {1260, 5}, {1255, 5}, {1250, 5}, {1245, 5}, {1240, 5},
{1235, 5}, {1230, 5}, {1225, 5}, {1220, 5}, {1215, 4}, {1211, 5}, {1206, 5}, {1201, 5},
};
#endif
#endif

@ -0,0 +1,953 @@
/*
stepper.c - stepper motor driver: executes motion plans using stepper motors
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
/* The timer calculations of this module informed by the 'RepRap cartesian firmware' by Zack Smith
and Philipp Tiefenbacher. */
#include "Marlin.h"
#include "stepper.h"
#include "planner.h"
#include "temperature.h"
#include "ultralcd.h"
#include "language.h"
#include "speed_lookuptable.h"
//===========================================================================
//=============================public variables ============================
//===========================================================================
block_t *current_block; // A pointer to the block currently being traced
//===========================================================================
//=============================private variables ============================
//===========================================================================
//static makes it inpossible to be called from outside of this file by extern.!
// Variables used by The Stepper Driver Interrupt
static unsigned char out_bits; // The next stepping-bits to be output
static long counter_x, // Counter variables for the bresenham line tracer
counter_y,
counter_z,
counter_e;
volatile static unsigned long step_events_completed; // The number of step events executed in the current block
#ifdef ADVANCE
static long advance_rate, advance, final_advance = 0;
static long old_advance = 0;
#endif
static long e_steps[3];
static long acceleration_time, deceleration_time;
//static unsigned long accelerate_until, decelerate_after, acceleration_rate, initial_rate, final_rate, nominal_rate;
static unsigned short acc_step_rate; // needed for deccelaration start point
static char step_loops;
static unsigned short OCR1A_nominal;
volatile long endstops_trigsteps[3]={0,0,0};
volatile long endstops_stepsTotal,endstops_stepsDone;
static volatile bool endstop_x_hit=false;
static volatile bool endstop_y_hit=false;
static volatile bool endstop_z_hit=false;
static bool old_x_min_endstop=false;
static bool old_x_max_endstop=false;
static bool old_y_min_endstop=false;
static bool old_y_max_endstop=false;
static bool old_z_min_endstop=false;
static bool old_z_max_endstop=false;
static bool check_endstops = true;
volatile long count_position[NUM_AXIS] = { 0, 0, 0, 0};
volatile char count_direction[NUM_AXIS] = { 1, 1, 1, 1};
//===========================================================================
//=============================functions ============================
//===========================================================================
#define CHECK_ENDSTOPS if(check_endstops)
// intRes = intIn1 * intIn2 >> 16
// uses:
// r26 to store 0
// r27 to store the byte 1 of the 24 bit result
#define MultiU16X8toH16(intRes, charIn1, intIn2) \
asm volatile ( \
"clr r26 \n\t" \
"mul %A1, %B2 \n\t" \
"movw %A0, r0 \n\t" \
"mul %A1, %A2 \n\t" \
"add %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"lsr r0 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"clr r1 \n\t" \
: \
"=&r" (intRes) \
: \
"d" (charIn1), \
"d" (intIn2) \
: \
"r26" \
)
// intRes = longIn1 * longIn2 >> 24
// uses:
// r26 to store 0
// r27 to store the byte 1 of the 48bit result
#define MultiU24X24toH16(intRes, longIn1, longIn2) \
asm volatile ( \
"clr r26 \n\t" \
"mul %A1, %B2 \n\t" \
"mov r27, r1 \n\t" \
"mul %B1, %C2 \n\t" \
"movw %A0, r0 \n\t" \
"mul %C1, %C2 \n\t" \
"add %B0, r0 \n\t" \
"mul %C1, %B2 \n\t" \
"add %A0, r0 \n\t" \
"adc %B0, r1 \n\t" \
"mul %A1, %C2 \n\t" \
"add r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %B1, %B2 \n\t" \
"add r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %C1, %A2 \n\t" \
"add r27, r0 \n\t" \
"adc %A0, r1 \n\t" \
"adc %B0, r26 \n\t" \
"mul %B1, %A2 \n\t" \
"add r27, r1 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"lsr r27 \n\t" \
"adc %A0, r26 \n\t" \
"adc %B0, r26 \n\t" \
"clr r1 \n\t" \
: \
"=&r" (intRes) \
: \
"d" (longIn1), \
"d" (longIn2) \
: \
"r26" , "r27" \
)
// Some useful constants
#define ENABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 |= (1<<OCIE1A)
#define DISABLE_STEPPER_DRIVER_INTERRUPT() TIMSK1 &= ~(1<<OCIE1A)
void checkHitEndstops()
{
if( endstop_x_hit || endstop_y_hit || endstop_z_hit) {
SERIAL_ECHO_START;
SERIAL_ECHOPGM(MSG_ENDSTOPS_HIT);
if(endstop_x_hit) {
SERIAL_ECHOPAIR(" X:",(float)endstops_trigsteps[X_AXIS]/axis_steps_per_unit[X_AXIS]);
}
if(endstop_y_hit) {
SERIAL_ECHOPAIR(" Y:",(float)endstops_trigsteps[Y_AXIS]/axis_steps_per_unit[Y_AXIS]);
}
if(endstop_z_hit) {
SERIAL_ECHOPAIR(" Z:",(float)endstops_trigsteps[Z_AXIS]/axis_steps_per_unit[Z_AXIS]);
}
SERIAL_ECHOLN("");
endstop_x_hit=false;
endstop_y_hit=false;
endstop_z_hit=false;
}
}
void endstops_hit_on_purpose()
{
endstop_x_hit=false;
endstop_y_hit=false;
endstop_z_hit=false;
}
void enable_endstops(bool check)
{
check_endstops = check;
}
// __________________________
// /| |\ _________________ ^
// / | | \ /| |\ |
// / | | \ / | | \ s
// / | | | | | \ p
// / | | | | | \ e
// +-----+------------------------+---+--+---------------+----+ e
// | BLOCK 1 | BLOCK 2 | d
//
// time ----->
//
// The trapezoid is the shape the speed curve over time. It starts at block->initial_rate, accelerates
// first block->accelerate_until step_events_completed, then keeps going at constant speed until
// step_events_completed reaches block->decelerate_after after which it decelerates until the trapezoid generator is reset.
// The slope of acceleration is calculated with the leib ramp alghorithm.
void st_wake_up() {
// TCNT1 = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();
}
void step_wait(){
for(int8_t i=0; i < 6; i++){
}
}
FORCE_INLINE unsigned short calc_timer(unsigned short step_rate) {
unsigned short timer;
if(step_rate > MAX_STEP_FREQUENCY) step_rate = MAX_STEP_FREQUENCY;
if(step_rate > 20000) { // If steprate > 20kHz >> step 4 times
step_rate = (step_rate >> 2)&0x3fff;
step_loops = 4;
}
else if(step_rate > 10000) { // If steprate > 10kHz >> step 2 times
step_rate = (step_rate >> 1)&0x7fff;
step_loops = 2;
}
else {
step_loops = 1;
}
if(step_rate < (F_CPU/500000)) step_rate = (F_CPU/500000);
step_rate -= (F_CPU/500000); // Correct for minimal speed
if(step_rate >= (8*256)){ // higher step rate
unsigned short table_address = (unsigned short)&speed_lookuptable_fast[(unsigned char)(step_rate>>8)][0];
unsigned char tmp_step_rate = (step_rate & 0x00ff);
unsigned short gain = (unsigned short)pgm_read_word_near(table_address+2);
MultiU16X8toH16(timer, tmp_step_rate, gain);
timer = (unsigned short)pgm_read_word_near(table_address) - timer;
}
else { // lower step rates
unsigned short table_address = (unsigned short)&speed_lookuptable_slow[0][0];
table_address += ((step_rate)>>1) & 0xfffc;
timer = (unsigned short)pgm_read_word_near(table_address);
timer -= (((unsigned short)pgm_read_word_near(table_address+2) * (unsigned char)(step_rate & 0x0007))>>3);
}
if(timer < 100) { timer = 100; MYSERIAL.print(MSG_STEPPER_TO_HIGH); MYSERIAL.println(step_rate); }//(20kHz this should never happen)
return timer;
}
// Initializes the trapezoid generator from the current block. Called whenever a new
// block begins.
FORCE_INLINE void trapezoid_generator_reset() {
#ifdef ADVANCE
advance = current_block->initial_advance;
final_advance = current_block->final_advance;
// Do E steps + advance steps
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
old_advance = advance >>8;
#endif
deceleration_time = 0;
// step_rate to timer interval
OCR1A_nominal = calc_timer(current_block->nominal_rate);
acc_step_rate = current_block->initial_rate;
acceleration_time = calc_timer(acc_step_rate);
OCR1A = acceleration_time;
// SERIAL_ECHO_START;
// SERIAL_ECHOPGM("advance :");
// SERIAL_ECHO(current_block->advance/256.0);
// SERIAL_ECHOPGM("advance rate :");
// SERIAL_ECHO(current_block->advance_rate/256.0);
// SERIAL_ECHOPGM("initial advance :");
// SERIAL_ECHO(current_block->initial_advance/256.0);
// SERIAL_ECHOPGM("final advance :");
// SERIAL_ECHOLN(current_block->final_advance/256.0);
}
// "The Stepper Driver Interrupt" - This timer interrupt is the workhorse.
// It pops blocks from the block_buffer and executes them by pulsing the stepper pins appropriately.
ISR(TIMER1_COMPA_vect)
{
// If there is no current block, attempt to pop one from the buffer
if (current_block == NULL) {
// Anything in the buffer?
current_block = plan_get_current_block();
if (current_block != NULL) {
current_block->busy = true;
trapezoid_generator_reset();
counter_x = -(current_block->step_event_count >> 1);
counter_y = counter_x;
counter_z = counter_x;
counter_e = counter_x;
step_events_completed = 0;
#ifdef Z_LATE_ENABLE
if(current_block->steps_z > 0) {
enable_z();
OCR1A = 2000; //1ms wait
return;
}
#endif
// #ifdef ADVANCE
// e_steps[current_block->active_extruder] = 0;
// #endif
}
else {
OCR1A=2000; // 1kHz.
}
}
if (current_block != NULL) {
// Set directions TO DO This should be done once during init of trapezoid. Endstops -> interrupt
out_bits = current_block->direction_bits;
// Set direction en check limit switches
if ((out_bits & (1<<X_AXIS)) != 0) { // stepping along -X axis
#if !defined COREXY //NOT COREXY
WRITE(X_DIR_PIN, INVERT_X_DIR);
#endif
count_direction[X_AXIS]=-1;
CHECK_ENDSTOPS
{
#if X_MIN_PIN > -1
bool x_min_endstop=(READ(X_MIN_PIN) != X_ENDSTOPS_INVERTING);
if(x_min_endstop && old_x_min_endstop && (current_block->steps_x > 0)) {
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
endstop_x_hit=true;
step_events_completed = current_block->step_event_count;
}
old_x_min_endstop = x_min_endstop;
#endif
}
}
else { // +direction
#if !defined COREXY //NOT COREXY
WRITE(X_DIR_PIN,!INVERT_X_DIR);
#endif
count_direction[X_AXIS]=1;
CHECK_ENDSTOPS
{
#if X_MAX_PIN > -1
bool x_max_endstop=(READ(X_MAX_PIN) != X_ENDSTOPS_INVERTING);
if(x_max_endstop && old_x_max_endstop && (current_block->steps_x > 0)){
endstops_trigsteps[X_AXIS] = count_position[X_AXIS];
endstop_x_hit=true;
step_events_completed = current_block->step_event_count;
}
old_x_max_endstop = x_max_endstop;
#endif
}
}
if ((out_bits & (1<<Y_AXIS)) != 0) { // -direction
#if !defined COREXY //NOT COREXY
WRITE(Y_DIR_PIN,INVERT_Y_DIR);
#endif
count_direction[Y_AXIS]=-1;
CHECK_ENDSTOPS
{
#if Y_MIN_PIN > -1
bool y_min_endstop=(READ(Y_MIN_PIN) != Y_ENDSTOPS_INVERTING);
if(y_min_endstop && old_y_min_endstop && (current_block->steps_y > 0)) {
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
endstop_y_hit=true;
step_events_completed = current_block->step_event_count;
}
old_y_min_endstop = y_min_endstop;
#endif
}
}
else { // +direction
#if !defined COREXY //NOT COREXY
WRITE(Y_DIR_PIN,!INVERT_Y_DIR);
#endif
count_direction[Y_AXIS]=1;
CHECK_ENDSTOPS
{
#if Y_MAX_PIN > -1
bool y_max_endstop=(READ(Y_MAX_PIN) != Y_ENDSTOPS_INVERTING);
if(y_max_endstop && old_y_max_endstop && (current_block->steps_y > 0)){
endstops_trigsteps[Y_AXIS] = count_position[Y_AXIS];
endstop_y_hit=true;
step_events_completed = current_block->step_event_count;
}
old_y_max_endstop = y_max_endstop;
#endif
}
}
#ifdef COREXY //coreXY kinematics defined
if((current_block->steps_x >= current_block->steps_y)&&((out_bits & (1<<X_AXIS)) == 0)){ //+X is major axis
WRITE(X_DIR_PIN, !INVERT_X_DIR);
WRITE(Y_DIR_PIN, !INVERT_Y_DIR);
}
if((current_block->steps_x >= current_block->steps_y)&&((out_bits & (1<<X_AXIS)) != 0)){ //-X is major axis
WRITE(X_DIR_PIN, INVERT_X_DIR);
WRITE(Y_DIR_PIN, INVERT_Y_DIR);
}
if((current_block->steps_y > current_block->steps_x)&&((out_bits & (1<<Y_AXIS)) == 0)){ //+Y is major axis
WRITE(X_DIR_PIN, !INVERT_X_DIR);
WRITE(Y_DIR_PIN, INVERT_Y_DIR);
}
if((current_block->steps_y > current_block->steps_x)&&((out_bits & (1<<Y_AXIS)) != 0)){ //-Y is major axis
WRITE(X_DIR_PIN, INVERT_X_DIR);
WRITE(Y_DIR_PIN, !INVERT_Y_DIR);
}
#endif //coreXY
if ((out_bits & (1<<Z_AXIS)) != 0) { // -direction
WRITE(Z_DIR_PIN,INVERT_Z_DIR);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,INVERT_Z_DIR);
#endif
count_direction[Z_AXIS]=-1;
CHECK_ENDSTOPS
{
#if Z_MIN_PIN > -1
bool z_min_endstop=(READ(Z_MIN_PIN) != Z_ENDSTOPS_INVERTING);
if(z_min_endstop && old_z_min_endstop && (current_block->steps_z > 0)) {
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
endstop_z_hit=true;
step_events_completed = current_block->step_event_count;
}
old_z_min_endstop = z_min_endstop;
#endif
}
}
else { // +direction
WRITE(Z_DIR_PIN,!INVERT_Z_DIR);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_DIR_PIN,!INVERT_Z_DIR);
#endif
count_direction[Z_AXIS]=1;
CHECK_ENDSTOPS
{
#if Z_MAX_PIN > -1
bool z_max_endstop=(READ(Z_MAX_PIN) != Z_ENDSTOPS_INVERTING);
if(z_max_endstop && old_z_max_endstop && (current_block->steps_z > 0)) {
endstops_trigsteps[Z_AXIS] = count_position[Z_AXIS];
endstop_z_hit=true;
step_events_completed = current_block->step_event_count;
}
old_z_max_endstop = z_max_endstop;
#endif
}
}
#ifndef ADVANCE
if ((out_bits & (1<<E_AXIS)) != 0) { // -direction
REV_E_DIR();
count_direction[E_AXIS]=-1;
}
else { // +direction
NORM_E_DIR();
count_direction[E_AXIS]=1;
}
#endif //!ADVANCE
for(int8_t i=0; i < step_loops; i++) { // Take multiple steps per interrupt (For high speed moves)
#if MOTHERBOARD != 8 // !teensylu
MSerial.checkRx(); // Check for serial chars.
#endif
#ifdef ADVANCE
counter_e += current_block->steps_e;
if (counter_e > 0) {
counter_e -= current_block->step_event_count;
if ((out_bits & (1<<E_AXIS)) != 0) { // - direction
e_steps[current_block->active_extruder]--;
}
else {
e_steps[current_block->active_extruder]++;
}
}
#endif //ADVANCE
#if !defined COREXY
counter_x += current_block->steps_x;
if (counter_x > 0) {
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
counter_x -= current_block->step_event_count;
count_position[X_AXIS]+=count_direction[X_AXIS];
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
}
counter_y += current_block->steps_y;
if (counter_y > 0) {
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
counter_y -= current_block->step_event_count;
count_position[Y_AXIS]+=count_direction[Y_AXIS];
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
}
#endif
#ifdef COREXY
counter_x += current_block->steps_x;
counter_y += current_block->steps_y;
if ((counter_x > 0)&&!(counter_y>0)){ //X step only
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
counter_x -= current_block->step_event_count;
count_position[X_AXIS]+=count_direction[X_AXIS];
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
}
if (!(counter_x > 0)&&(counter_y>0)){ //Y step only
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
counter_y -= current_block->step_event_count;
count_position[Y_AXIS]+=count_direction[Y_AXIS];
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
}
if ((counter_x > 0)&&(counter_y>0)){ //step in both axes
if (((out_bits & (1<<X_AXIS)) == 0)^((out_bits & (1<<Y_AXIS)) == 0)){ //X and Y in different directions
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
counter_x -= current_block->step_event_count;
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
step_wait();
count_position[X_AXIS]+=count_direction[X_AXIS];
count_position[Y_AXIS]+=count_direction[Y_AXIS];
WRITE(Y_STEP_PIN, !INVERT_Y_STEP_PIN);
counter_y -= current_block->step_event_count;
WRITE(Y_STEP_PIN, INVERT_Y_STEP_PIN);
}
else{ //X and Y in same direction
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
counter_x -= current_block->step_event_count;
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN) ;
step_wait();
count_position[X_AXIS]+=count_direction[X_AXIS];
count_position[Y_AXIS]+=count_direction[Y_AXIS];
WRITE(X_STEP_PIN, !INVERT_X_STEP_PIN);
counter_y -= current_block->step_event_count;
WRITE(X_STEP_PIN, INVERT_X_STEP_PIN);
}
}
#endif //corexy
counter_z += current_block->steps_z;
if (counter_z > 0) {
WRITE(Z_STEP_PIN, !INVERT_Z_STEP_PIN);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, !INVERT_Z_STEP_PIN);
#endif
counter_z -= current_block->step_event_count;
count_position[Z_AXIS]+=count_direction[Z_AXIS];
WRITE(Z_STEP_PIN, INVERT_Z_STEP_PIN);
#ifdef Z_DUAL_STEPPER_DRIVERS
WRITE(Z2_STEP_PIN, INVERT_Z_STEP_PIN);
#endif
}
#ifndef ADVANCE
counter_e += current_block->steps_e;
if (counter_e > 0) {
WRITE_E_STEP(!INVERT_E_STEP_PIN);
counter_e -= current_block->step_event_count;
count_position[E_AXIS]+=count_direction[E_AXIS];
WRITE_E_STEP(INVERT_E_STEP_PIN);
}
#endif //!ADVANCE
step_events_completed += 1;
if(step_events_completed >= current_block->step_event_count) break;
}
// Calculare new timer value
unsigned short timer;
unsigned short step_rate;
if (step_events_completed <= (unsigned long int)current_block->accelerate_until) {
MultiU24X24toH16(acc_step_rate, acceleration_time, current_block->acceleration_rate);
acc_step_rate += current_block->initial_rate;
// upper limit
if(acc_step_rate > current_block->nominal_rate)
acc_step_rate = current_block->nominal_rate;
// step_rate to timer interval
timer = calc_timer(acc_step_rate);
OCR1A = timer;
acceleration_time += timer;
#ifdef ADVANCE
for(int8_t i=0; i < step_loops; i++) {
advance += advance_rate;
}
//if(advance > current_block->advance) advance = current_block->advance;
// Do E steps + advance steps
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
old_advance = advance >>8;
#endif
}
else if (step_events_completed > (unsigned long int)current_block->decelerate_after) {
MultiU24X24toH16(step_rate, deceleration_time, current_block->acceleration_rate);
if(step_rate > acc_step_rate) { // Check step_rate stays positive
step_rate = current_block->final_rate;
}
else {
step_rate = acc_step_rate - step_rate; // Decelerate from aceleration end point.
}
// lower limit
if(step_rate < current_block->final_rate)
step_rate = current_block->final_rate;
// step_rate to timer interval
timer = calc_timer(step_rate);
OCR1A = timer;
deceleration_time += timer;
#ifdef ADVANCE
for(int8_t i=0; i < step_loops; i++) {
advance -= advance_rate;
}
if(advance < final_advance) advance = final_advance;
// Do E steps + advance steps
e_steps[current_block->active_extruder] += ((advance >>8) - old_advance);
old_advance = advance >>8;
#endif //ADVANCE
}
else {
OCR1A = OCR1A_nominal;
}
// If current block is finished, reset pointer
if (step_events_completed >= current_block->step_event_count) {
current_block = NULL;
plan_discard_current_block();
}
}
}
#ifdef ADVANCE
unsigned char old_OCR0A;
// Timer interrupt for E. e_steps is set in the main routine;
// Timer 0 is shared with millies
ISR(TIMER0_COMPA_vect)
{
old_OCR0A += 52; // ~10kHz interrupt (250000 / 26 = 9615kHz)
OCR0A = old_OCR0A;
// Set E direction (Depends on E direction + advance)
for(unsigned char i=0; i<4;i++) {
if (e_steps[0] != 0) {
WRITE(E0_STEP_PIN, INVERT_E_STEP_PIN);
if (e_steps[0] < 0) {
WRITE(E0_DIR_PIN, INVERT_E0_DIR);
e_steps[0]++;
WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[0] > 0) {
WRITE(E0_DIR_PIN, !INVERT_E0_DIR);
e_steps[0]--;
WRITE(E0_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#if EXTRUDERS > 1
if (e_steps[1] != 0) {
WRITE(E1_STEP_PIN, INVERT_E_STEP_PIN);
if (e_steps[1] < 0) {
WRITE(E1_DIR_PIN, INVERT_E1_DIR);
e_steps[1]++;
WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[1] > 0) {
WRITE(E1_DIR_PIN, !INVERT_E1_DIR);
e_steps[1]--;
WRITE(E1_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#endif
#if EXTRUDERS > 2
if (e_steps[2] != 0) {
WRITE(E2_STEP_PIN, INVERT_E_STEP_PIN);
if (e_steps[2] < 0) {
WRITE(E2_DIR_PIN, INVERT_E2_DIR);
e_steps[2]++;
WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
}
else if (e_steps[2] > 0) {
WRITE(E2_DIR_PIN, !INVERT_E2_DIR);
e_steps[2]--;
WRITE(E2_STEP_PIN, !INVERT_E_STEP_PIN);
}
}
#endif
}
}
#endif // ADVANCE
void st_init()
{
//Initialize Dir Pins
#if X_DIR_PIN > -1
SET_OUTPUT(X_DIR_PIN);
#endif
#if Y_DIR_PIN > -1
SET_OUTPUT(Y_DIR_PIN);
#endif
#if Z_DIR_PIN > -1
SET_OUTPUT(Z_DIR_PIN);
#if defined(Z_DUAL_STEPPER_DRIVERS) && (Z2_DIR_PIN > -1)
SET_OUTPUT(Z2_DIR_PIN);
#endif
#endif
#if E0_DIR_PIN > -1
SET_OUTPUT(E0_DIR_PIN);
#endif
#if defined(E1_DIR_PIN) && (E1_DIR_PIN > -1)
SET_OUTPUT(E1_DIR_PIN);
#endif
#if defined(E2_DIR_PIN) && (E2_DIR_PIN > -1)
SET_OUTPUT(E2_DIR_PIN);
#endif
//Initialize Enable Pins - steppers default to disabled.
#if (X_ENABLE_PIN > -1)
SET_OUTPUT(X_ENABLE_PIN);
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
#endif
#if (Y_ENABLE_PIN > -1)
SET_OUTPUT(Y_ENABLE_PIN);
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
#endif
#if (Z_ENABLE_PIN > -1)
SET_OUTPUT(Z_ENABLE_PIN);
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
#if defined(Z_DUAL_STEPPER_DRIVERS) && (Z2_ENABLE_PIN > -1)
SET_OUTPUT(Z2_ENABLE_PIN);
if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH);
#endif
#endif
#if (E0_ENABLE_PIN > -1)
SET_OUTPUT(E0_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,HIGH);
#endif
#if defined(E1_ENABLE_PIN) && (E1_ENABLE_PIN > -1)
SET_OUTPUT(E1_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,HIGH);
#endif
#if defined(E2_ENABLE_PIN) && (E2_ENABLE_PIN > -1)
SET_OUTPUT(E2_ENABLE_PIN);
if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,HIGH);
#endif
//endstops and pullups
#if X_MIN_PIN > -1
SET_INPUT(X_MIN_PIN);
#ifdef ENDSTOPPULLUP_XMIN
WRITE(X_MIN_PIN,HIGH);
#endif
#endif
#if Y_MIN_PIN > -1
SET_INPUT(Y_MIN_PIN);
#ifdef ENDSTOPPULLUP_YMIN
WRITE(Y_MIN_PIN,HIGH);
#endif
#endif
#if Z_MIN_PIN > -1
SET_INPUT(Z_MIN_PIN);
#ifdef ENDSTOPPULLUP_ZMIN
WRITE(Z_MIN_PIN,HIGH);
#endif
#endif
#if X_MAX_PIN > -1
SET_INPUT(X_MAX_PIN);
#ifdef ENDSTOPPULLUP_XMAX
WRITE(X_MAX_PIN,HIGH);
#endif
#endif
#if Y_MAX_PIN > -1
SET_INPUT(Y_MAX_PIN);
#ifdef ENDSTOPPULLUP_YMAX
WRITE(Y_MAX_PIN,HIGH);
#endif
#endif
#if Z_MAX_PIN > -1
SET_INPUT(Z_MAX_PIN);
#ifdef ENDSTOPPULLUP_ZMAX
WRITE(Z_MAX_PIN,HIGH);
#endif
#endif
//Initialize Step Pins
#if (X_STEP_PIN > -1)
SET_OUTPUT(X_STEP_PIN);
WRITE(X_STEP_PIN,INVERT_X_STEP_PIN);
if(!X_ENABLE_ON) WRITE(X_ENABLE_PIN,HIGH);
#endif
#if (Y_STEP_PIN > -1)
SET_OUTPUT(Y_STEP_PIN);
WRITE(Y_STEP_PIN,INVERT_Y_STEP_PIN);
if(!Y_ENABLE_ON) WRITE(Y_ENABLE_PIN,HIGH);
#endif
#if (Z_STEP_PIN > -1)
SET_OUTPUT(Z_STEP_PIN);
WRITE(Z_STEP_PIN,INVERT_Z_STEP_PIN);
if(!Z_ENABLE_ON) WRITE(Z_ENABLE_PIN,HIGH);
#if defined(Z_DUAL_STEPPER_DRIVERS) && (Z2_STEP_PIN > -1)
SET_OUTPUT(Z2_STEP_PIN);
WRITE(Z2_STEP_PIN,INVERT_Z_STEP_PIN);
if(!Z_ENABLE_ON) WRITE(Z2_ENABLE_PIN,HIGH);
#endif
#endif
#if (E0_STEP_PIN > -1)
SET_OUTPUT(E0_STEP_PIN);
WRITE(E0_STEP_PIN,INVERT_E_STEP_PIN);
if(!E_ENABLE_ON) WRITE(E0_ENABLE_PIN,HIGH);
#endif
#if defined(E1_STEP_PIN) && (E1_STEP_PIN > -1)
SET_OUTPUT(E1_STEP_PIN);
WRITE(E1_STEP_PIN,INVERT_E_STEP_PIN);
if(!E_ENABLE_ON) WRITE(E1_ENABLE_PIN,HIGH);
#endif
#if defined(E2_STEP_PIN) && (E2_STEP_PIN > -1)
SET_OUTPUT(E2_STEP_PIN);
WRITE(E2_STEP_PIN,INVERT_E_STEP_PIN);
if(!E_ENABLE_ON) WRITE(E2_ENABLE_PIN,HIGH);
#endif
#ifdef CONTROLLERFAN_PIN
SET_OUTPUT(CONTROLLERFAN_PIN); //Set pin used for driver cooling fan
#endif
// waveform generation = 0100 = CTC
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1A &= ~(1<<WGM11);
TCCR1A &= ~(1<<WGM10);
// output mode = 00 (disconnected)
TCCR1A &= ~(3<<COM1A0);
TCCR1A &= ~(3<<COM1B0);
// Set the timer pre-scaler
// Generally we use a divider of 8, resulting in a 2MHz timer
// frequency on a 16MHz MCU. If you are going to change this, be
// sure to regenerate speed_lookuptable.h with
// create_speed_lookuptable.py
TCCR1B = (TCCR1B & ~(0x07<<CS10)) | (2<<CS10);
OCR1A = 0x4000;
TCNT1 = 0;
ENABLE_STEPPER_DRIVER_INTERRUPT();
#ifdef ADVANCE
#if defined(TCCR0A) && defined(WGM01)
TCCR0A &= ~(1<<WGM01);
TCCR0A &= ~(1<<WGM00);
#endif
e_steps[0] = 0;
e_steps[1] = 0;
e_steps[2] = 0;
TIMSK0 |= (1<<OCIE0A);
#endif //ADVANCE
enable_endstops(true); // Start with endstops active. After homing they can be disabled
sei();
}
// Block until all buffered steps are executed
void st_synchronize()
{
while( blocks_queued()) {
manage_heater();
manage_inactivity();
LCD_STATUS;
}
}
void st_set_position(const long &x, const long &y, const long &z, const long &e)
{
CRITICAL_SECTION_START;
count_position[X_AXIS] = x;
count_position[Y_AXIS] = y;
count_position[Z_AXIS] = z;
count_position[E_AXIS] = e;
CRITICAL_SECTION_END;
}
void st_set_e_position(const long &e)
{
CRITICAL_SECTION_START;
count_position[E_AXIS] = e;
CRITICAL_SECTION_END;
}
long st_get_position(uint8_t axis)
{
long count_pos;
CRITICAL_SECTION_START;
count_pos = count_position[axis];
CRITICAL_SECTION_END;
return count_pos;
}
void finishAndDisableSteppers()
{
st_synchronize();
LCD_MESSAGEPGM(MSG_STEPPER_RELEASED);
disable_x();
disable_y();
disable_z();
disable_e0();
disable_e1();
disable_e2();
}
void quickStop()
{
DISABLE_STEPPER_DRIVER_INTERRUPT();
while(blocks_queued())
plan_discard_current_block();
current_block = NULL;
ENABLE_STEPPER_DRIVER_INTERRUPT();
}

@ -0,0 +1,71 @@
/*
stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
Part of Grbl
Copyright (c) 2009-2011 Simen Svale Skogsrud
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef stepper_h
#define stepper_h
#include "planner.h"
#if EXTRUDERS > 2
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 2) { WRITE(E2_STEP_PIN, v); } else { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}}
#define NORM_E_DIR() { if(current_block->active_extruder == 2) { WRITE(!E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(!E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}}
#define REV_E_DIR() { if(current_block->active_extruder == 2) { WRITE(E2_DIR_PIN, INVERT_E2_DIR); } else { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}}
#elif EXTRUDERS > 1
#define WRITE_E_STEP(v) { if(current_block->active_extruder == 1) { WRITE(E1_STEP_PIN, v); } else { WRITE(E0_STEP_PIN, v); }}
#define NORM_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, !INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, !INVERT_E0_DIR); }}
#define REV_E_DIR() { if(current_block->active_extruder == 1) { WRITE(E1_DIR_PIN, INVERT_E1_DIR); } else { WRITE(E0_DIR_PIN, INVERT_E0_DIR); }}
#else
#define WRITE_E_STEP(v) WRITE(E0_STEP_PIN, v)
#define NORM_E_DIR() WRITE(E0_DIR_PIN, !INVERT_E0_DIR)
#define REV_E_DIR() WRITE(E0_DIR_PIN, INVERT_E0_DIR)
#endif
// Initialize and start the stepper motor subsystem
void st_init();
// Block until all buffered steps are executed
void st_synchronize();
// Set current position in steps
void st_set_position(const long &x, const long &y, const long &z, const long &e);
void st_set_e_position(const long &e);
// Get current position in steps
long st_get_position(uint8_t axis);
// The stepper subsystem goes to sleep when it runs out of things to execute. Call this
// to notify the subsystem that it is time to go to work.
void st_wake_up();
void checkHitEndstops(); //call from somwhere to create an serial error message with the locations the endstops where hit, in case they were triggered
void endstops_hit_on_purpose(); //avoid creation of the message, i.e. after homeing and before a routine call of checkHitEndstops();
void enable_endstops(bool check); // Enable/disable endstop checking
void checkStepperErrors(); //Print errors detected by the stepper
void finishAndDisableSteppers();
extern block_t *current_block; // A pointer to the block currently being traced
void quickStop();
#endif

@ -0,0 +1,1019 @@
/*
temperature.c - temperature control
Part of Marlin
Copyright (C) 2011 Camiel Gubbels / Erik van der Zalm
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This firmware is a mashup between Sprinter and grbl.
(https://github.com/kliment/Sprinter)
(https://github.com/simen/grbl/tree)
It has preliminary support for Matthew Roberts advance algorithm
http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
*/
#include "Marlin.h"
#include "ultralcd.h"
#include "temperature.h"
#include "watchdog.h"
//===========================================================================
//=============================public variables============================
//===========================================================================
int target_raw[EXTRUDERS] = { 0 };
int target_raw_bed = 0;
#ifdef BED_LIMIT_SWITCHING
int target_bed_low_temp =0;
int target_bed_high_temp =0;
#endif
int current_raw[EXTRUDERS] = { 0 };
int current_raw_bed = 0;
#ifdef PIDTEMP
// used external
float pid_setpoint[EXTRUDERS] = { 0.0 };
float Kp=DEFAULT_Kp;
float Ki=(DEFAULT_Ki*PID_dT);
float Kd=(DEFAULT_Kd/PID_dT);
#ifdef PID_ADD_EXTRUSION_RATE
float Kc=DEFAULT_Kc;
#endif
#endif //PIDTEMP
//===========================================================================
//=============================private variables============================
//===========================================================================
static volatile bool temp_meas_ready = false;
static unsigned long previous_millis_bed_heater;
//static unsigned long previous_millis_heater;
#ifdef PIDTEMP
//static cannot be external:
static float temp_iState[EXTRUDERS] = { 0 };
static float temp_dState[EXTRUDERS] = { 0 };
static float pTerm[EXTRUDERS];
static float iTerm[EXTRUDERS];
static float dTerm[EXTRUDERS];
//int output;
static float pid_error[EXTRUDERS];
static float temp_iState_min[EXTRUDERS];
static float temp_iState_max[EXTRUDERS];
// static float pid_input[EXTRUDERS];
// static float pid_output[EXTRUDERS];
static bool pid_reset[EXTRUDERS];
#endif //PIDTEMP
static unsigned char soft_pwm[EXTRUDERS];
#ifdef WATCHPERIOD
int watch_raw[EXTRUDERS] = { -1000 }; // the first value used for all
int watch_oldtemp[3] = {0,0,0};
unsigned long watchmillis = 0;
#endif //WATCHPERIOD
// Init min and max temp with extreme values to prevent false errors during startup
static int minttemp[EXTRUDERS] = { 0 };
static int maxttemp[EXTRUDERS] = { 16383 }; // the first value used for all
static int bed_minttemp = 0;
static int bed_maxttemp = 16383;
static void *heater_ttbl_map[EXTRUDERS] = { (void *)heater_0_temptable
#if EXTRUDERS > 1
, (void *)heater_1_temptable
#endif
#if EXTRUDERS > 2
, (void *)heater_2_temptable
#endif
#if EXTRUDERS > 3
#error Unsupported number of extruders
#endif
};
static int heater_ttbllen_map[EXTRUDERS] = { heater_0_temptable_len
#if EXTRUDERS > 1
, heater_1_temptable_len
#endif
#if EXTRUDERS > 2
, heater_2_temptable_len
#endif
#if EXTRUDERS > 3
#error Unsupported number of extruders
#endif
};
//===========================================================================
//============================= functions ============================
//===========================================================================
void PID_autotune(float temp)
{
float input;
int cycles=0;
bool heating = true;
unsigned long temp_millis = millis();
unsigned long t1=temp_millis;
unsigned long t2=temp_millis;
long t_high;
long t_low;
long bias=PID_MAX/2;
long d = PID_MAX/2;
float Ku, Tu;
float Kp, Ki, Kd;
float max, min;
SERIAL_ECHOLN("PID Autotune start");
disable_heater(); // switch off all heaters.
soft_pwm[0] = PID_MAX/2;
for(;;) {
if(temp_meas_ready == true) { // temp sample ready
CRITICAL_SECTION_START;
temp_meas_ready = false;
CRITICAL_SECTION_END;
input = analog2temp(current_raw[0], 0);
max=max(max,input);
min=min(min,input);
if(heating == true && input > temp) {
if(millis() - t2 > 5000) {
heating=false;
soft_pwm[0] = (bias - d) >> 1;
t1=millis();
t_high=t1 - t2;
max=temp;
}
}
if(heating == false && input < temp) {
if(millis() - t1 > 5000) {
heating=true;
t2=millis();
t_low=t2 - t1;
if(cycles > 0) {
bias += (d*(t_high - t_low))/(t_low + t_high);
bias = constrain(bias, 20 ,PID_MAX-20);
if(bias > PID_MAX/2) d = PID_MAX - 1 - bias;
else d = bias;
SERIAL_PROTOCOLPGM(" bias: "); SERIAL_PROTOCOL(bias);
SERIAL_PROTOCOLPGM(" d: "); SERIAL_PROTOCOL(d);
SERIAL_PROTOCOLPGM(" min: "); SERIAL_PROTOCOL(min);
SERIAL_PROTOCOLPGM(" max: "); SERIAL_PROTOCOLLN(max);
if(cycles > 2) {
Ku = (4.0*d)/(3.14159*(max-min)/2.0);
Tu = ((float)(t_low + t_high)/1000.0);
SERIAL_PROTOCOLPGM(" Ku: "); SERIAL_PROTOCOL(Ku);
SERIAL_PROTOCOLPGM(" Tu: "); SERIAL_PROTOCOLLN(Tu);
Kp = 0.6*Ku;
Ki = 2*Kp/Tu;
Kd = Kp*Tu/8;
SERIAL_PROTOCOLLNPGM(" Clasic PID ")
SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
/*
Kp = 0.33*Ku;
Ki = Kp/Tu;
Kd = Kp*Tu/3;
SERIAL_PROTOCOLLNPGM(" Some overshoot ")
SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
Kp = 0.2*Ku;
Ki = 2*Kp/Tu;
Kd = Kp*Tu/3;
SERIAL_PROTOCOLLNPGM(" No overshoot ")
SERIAL_PROTOCOLPGM(" Kp: "); SERIAL_PROTOCOLLN(Kp);
SERIAL_PROTOCOLPGM(" Ki: "); SERIAL_PROTOCOLLN(Ki);
SERIAL_PROTOCOLPGM(" Kd: "); SERIAL_PROTOCOLLN(Kd);
*/
}
}
soft_pwm[0] = (bias + d) >> 1;
cycles++;
min=temp;
}
}
}
if(input > (temp + 20)) {
SERIAL_PROTOCOLLNPGM("PID Autotune failed! Temperature to high");
return;
}
if(millis() - temp_millis > 2000) {
temp_millis = millis();
SERIAL_PROTOCOLPGM("ok T:");
SERIAL_PROTOCOL(degHotend(0));
SERIAL_PROTOCOLPGM(" @:");
SERIAL_PROTOCOLLN(getHeaterPower(0));
}
if(((millis() - t1) + (millis() - t2)) > (10L*60L*1000L*2L)) {
SERIAL_PROTOCOLLNPGM("PID Autotune failed! timeout");
return;
}
if(cycles > 5) {
SERIAL_PROTOCOLLNPGM("PID Autotune finished ! Place the Kp, Ki and Kd constants in the configuration.h");
return;
}
LCD_STATUS;
}
}
void updatePID()
{
#ifdef PIDTEMP
for(int e = 0; e < EXTRUDERS; e++) {
temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
}
#endif
}
int getHeaterPower(int heater) {
return soft_pwm[heater];
}
void manage_heater()
{
#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER
static int bed_needs_heating=0;
static int bed_is_on=0;
#endif
#ifdef USE_WATCHDOG
wd_reset();
#endif
float pid_input;
float pid_output;
if(temp_meas_ready != true) //better readability
return;
CRITICAL_SECTION_START;
temp_meas_ready = false;
CRITICAL_SECTION_END;
for(int e = 0; e < EXTRUDERS; e++)
{
#ifdef PIDTEMP
pid_input = analog2temp(current_raw[e], e);
#ifndef PID_OPENLOOP
pid_error[e] = pid_setpoint[e] - pid_input;
if(pid_error[e] > 10) {
pid_output = PID_MAX;
pid_reset[e] = true;
}
else if(pid_error[e] < -10) {
pid_output = 0;
pid_reset[e] = true;
}
else {
if(pid_reset[e] == true) {
temp_iState[e] = 0.0;
pid_reset[e] = false;
}
pTerm[e] = Kp * pid_error[e];
temp_iState[e] += pid_error[e];
temp_iState[e] = constrain(temp_iState[e], temp_iState_min[e], temp_iState_max[e]);
iTerm[e] = Ki * temp_iState[e];
//K1 defined in Configuration.h in the PID settings
#define K2 (1.0-K1)
dTerm[e] = (Kd * (pid_input - temp_dState[e]))*K2 + (K1 * dTerm[e]);
temp_dState[e] = pid_input;
pid_output = constrain(pTerm[e] + iTerm[e] - dTerm[e], 0, PID_MAX);
}
#endif //PID_OPENLOOP
#ifdef PID_DEBUG
SERIAL_ECHOLN(" PIDDEBUG "<<e<<": Input "<<pid_input<<" Output "<<pid_output" pTerm "<<pTerm[e]<<" iTerm "<<iTerm[e]<<" dTerm "<<dTerm[e]);
#endif //PID_DEBUG
#else /* PID off */
pid_output = 0;
if(current_raw[e] < target_raw[e]) {
pid_output = PID_MAX;
}
#endif
// Check if temperature is within the correct range
if((current_raw[e] > minttemp[e]) && (current_raw[e] < maxttemp[e]))
{
soft_pwm[e] = (int)pid_output >> 1;
}
else {
soft_pwm[e] = 0;
}
} // End extruder for loop
#ifdef WATCHPERIOD
if(watchmillis && millis() - watchmillis > WATCHPERIOD){
if(watch_oldtemp[0] >= degHotend(active_extruder)){
setTargetHotend(0,active_extruder);
LCD_MESSAGEPGM("Heating failed");
SERIAL_ECHO_START;
SERIAL_ECHOLN("Heating failed");
}else{
watchmillis = 0;
}
}
#endif
#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER
if (bed_needs_heating){
if (bed_is_on==0)
WRITE(HEATER_BED_PIN,HIGH);
if (bed_is_on==1)
WRITE(HEATER_BED_PIN,LOW);
bed_is_on=(bed_is_on+1) % HEATER_BED_DUTY_CYCLE_DIVIDER;
}
#endif
if(millis() - previous_millis_bed_heater < BED_CHECK_INTERVAL)
return;
previous_millis_bed_heater = millis();
#if TEMP_BED_PIN > -1
#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER
bed_needs_heating=0;
#endif
#ifndef BED_LIMIT_SWITCHING
// Check if temperature is within the correct range
if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) {
if(current_raw_bed >= target_raw_bed)
{
WRITE(HEATER_BED_PIN,LOW);
}
else
{
#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER
bed_needs_heating=1;
#endif
WRITE(HEATER_BED_PIN,HIGH);
}
}
else {
WRITE(HEATER_BED_PIN,LOW);
}
#else //#ifdef BED_LIMIT_SWITCHING
// Check if temperature is within the correct band
if((current_raw_bed > bed_minttemp) && (current_raw_bed < bed_maxttemp)) {
if(current_raw_bed > target_bed_high_temp)
{
WRITE(HEATER_BED_PIN,LOW);
}
else
if(current_raw_bed <= target_bed_low_temp)
{
#ifdef HEATER_BED_DUTY_CYCLE_DIVIDER
bed_needs_heating=1;
#endif
WRITE(HEATER_BED_PIN,HIGH);
}
}
else {
WRITE(HEATER_BED_PIN,LOW);
}
#endif
#endif
}
#define PGM_RD_W(x) (short)pgm_read_word(&x)
// Takes hot end temperature value as input and returns corresponding raw value.
// For a thermistor, it uses the RepRap thermistor temp table.
// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value.
// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware.
int temp2analog(int celsius, uint8_t e) {
if(e >= EXTRUDERS)
{
SERIAL_ERROR_START;
SERIAL_ERROR((int)e);
SERIAL_ERRORLNPGM(" - Invalid extruder number!");
kill();
}
#ifdef HEATER_0_USES_MAX6675
if (e == 0)
{
return celsius * 4;
}
#endif
if(heater_ttbl_map[e] != 0)
{
int raw = 0;
byte i;
short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
for (i=1; i<heater_ttbllen_map[e]; i++)
{
if (PGM_RD_W((*tt)[i][1]) < celsius)
{
raw = PGM_RD_W((*tt)[i-1][0]) +
(celsius - PGM_RD_W((*tt)[i-1][1])) *
(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0])) /
(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1]));
break;
}
}
// Overflow: Set to last value in the table
if (i == heater_ttbllen_map[e]) raw = PGM_RD_W((*tt)[i-1][0]);
return (1023 * OVERSAMPLENR) - raw;
}
return ((celsius-TEMP_SENSOR_AD595_OFFSET)/TEMP_SENSOR_AD595_GAIN) * (1024.0 / (5.0 * 100.0) ) * OVERSAMPLENR;
}
// Takes bed temperature value as input and returns corresponding raw value.
// For a thermistor, it uses the RepRap thermistor temp table.
// This is needed because PID in hydra firmware hovers around a given analog value, not a temp value.
// This function is derived from inversing the logic from a portion of getTemperature() in FiveD RepRap firmware.
int temp2analogBed(int celsius) {
#ifdef BED_USES_THERMISTOR
int raw = 0;
byte i;
for (i=1; i<bedtemptable_len; i++)
{
if (PGM_RD_W(bedtemptable[i][1]) < celsius)
{
raw = PGM_RD_W(bedtemptable[i-1][0]) +
(celsius - PGM_RD_W(bedtemptable[i-1][1])) *
(PGM_RD_W(bedtemptable[i][0]) - PGM_RD_W(bedtemptable[i-1][0])) /
(PGM_RD_W(bedtemptable[i][1]) - PGM_RD_W(bedtemptable[i-1][1]));
break;
}
}
// Overflow: Set to last value in the table
if (i == bedtemptable_len) raw = PGM_RD_W(bedtemptable[i-1][0]);
return (1023 * OVERSAMPLENR) - raw;
#elif defined BED_USES_AD595
return lround(((celsius-TEMP_SENSOR_AD595_OFFSET)/TEMP_SENSOR_AD595_GAIN) * (1024.0 * OVERSAMPLENR/ (5.0 * 100.0) ) );
#else
#warning No heater-type defined for the bed.
return 0;
#endif
}
// Derived from RepRap FiveD extruder::getTemperature()
// For hot end temperature measurement.
float analog2temp(int raw, uint8_t e) {
if(e >= EXTRUDERS)
{
SERIAL_ERROR_START;
SERIAL_ERROR((int)e);
SERIAL_ERRORLNPGM(" - Invalid extruder number !");
kill();
}
#ifdef HEATER_0_USES_MAX6675
if (e == 0)
{
return 0.25 * raw;
}
#endif
if(heater_ttbl_map[e] != 0)
{
float celsius = 0;
byte i;
short (*tt)[][2] = (short (*)[][2])(heater_ttbl_map[e]);
raw = (1023 * OVERSAMPLENR) - raw;
for (i=1; i<heater_ttbllen_map[e]; i++)
{
if (PGM_RD_W((*tt)[i][0]) > raw)
{
celsius = PGM_RD_W((*tt)[i-1][1]) +
(raw - PGM_RD_W((*tt)[i-1][0])) *
(float)(PGM_RD_W((*tt)[i][1]) - PGM_RD_W((*tt)[i-1][1])) /
(float)(PGM_RD_W((*tt)[i][0]) - PGM_RD_W((*tt)[i-1][0]));
break;
}
}
// Overflow: Set to last value in the table
if (i == heater_ttbllen_map[e]) celsius = PGM_RD_W((*tt)[i-1][1]);
return celsius;
}
return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
}
// Derived from RepRap FiveD extruder::getTemperature()
// For bed temperature measurement.
float analog2tempBed(int raw) {
#ifdef BED_USES_THERMISTOR
float celsius = 0;
byte i;
raw = (1023 * OVERSAMPLENR) - raw;
for (i=1; i<bedtemptable_len; i++)
{
if (PGM_RD_W(bedtemptable[i][0]) > raw)
{
celsius = PGM_RD_W(bedtemptable[i-1][1]) +
(raw - PGM_RD_W(bedtemptable[i-1][0])) *
(float)(PGM_RD_W(bedtemptable[i][1]) - PGM_RD_W(bedtemptable[i-1][1])) /
(float)(PGM_RD_W(bedtemptable[i][0]) - PGM_RD_W(bedtemptable[i-1][0]));
break;
}
}
// Overflow: Set to last value in the table
if (i == bedtemptable_len) celsius = PGM_RD_W(bedtemptable[i-1][1]);
return celsius;
#elif defined BED_USES_AD595
return ((raw * ((5.0 * 100.0) / 1024.0) / OVERSAMPLENR) * TEMP_SENSOR_AD595_GAIN) + TEMP_SENSOR_AD595_OFFSET;
#else
#warning No heater-type defined for the bed.
return 0;
#endif
}
void tp_init()
{
// Finish init of mult extruder arrays
for(int e = 0; e < EXTRUDERS; e++) {
// populate with the first value
#ifdef WATCHPERIOD
watch_raw[e] = watch_raw[0];
#endif
maxttemp[e] = maxttemp[0];
#ifdef PIDTEMP
temp_iState_min[e] = 0.0;
temp_iState_max[e] = PID_INTEGRAL_DRIVE_MAX / Ki;
#endif //PIDTEMP
}
#if (HEATER_0_PIN > -1)
SET_OUTPUT(HEATER_0_PIN);
#endif
#if (HEATER_1_PIN > -1)
SET_OUTPUT(HEATER_1_PIN);
#endif
#if (HEATER_2_PIN > -1)
SET_OUTPUT(HEATER_2_PIN);
#endif
#if (HEATER_BED_PIN > -1)
SET_OUTPUT(HEATER_BED_PIN);
#endif
#if (FAN_PIN > -1)
SET_OUTPUT(FAN_PIN);
#ifdef FAST_PWM_FAN
setPwmFrequency(FAN_PIN, 1); // No prescaling. Pwm frequency = F_CPU/256/8
#endif
#endif
#ifdef HEATER_0_USES_MAX6675
#ifndef SDSUPPORT
SET_OUTPUT(MAX_SCK_PIN);
WRITE(MAX_SCK_PIN,0);
SET_OUTPUT(MAX_MOSI_PIN);
WRITE(MAX_MOSI_PIN,1);
SET_INPUT(MAX_MISO_PIN);
WRITE(MAX_MISO_PIN,1);
#endif
SET_OUTPUT(MAX6675_SS);
WRITE(MAX6675_SS,1);
#endif
// Set analog inputs
ADCSRA = 1<<ADEN | 1<<ADSC | 1<<ADIF | 0x07;
DIDR0 = 0;
#ifdef DIDR2
DIDR2 = 0;
#endif
#if (TEMP_0_PIN > -1)
#if TEMP_0_PIN < 8
DIDR0 |= 1 << TEMP_0_PIN;
#else
DIDR2 |= 1<<(TEMP_0_PIN - 8);
#endif
#endif
#if (TEMP_1_PIN > -1)
#if TEMP_1_PIN < 8
DIDR0 |= 1<<TEMP_1_PIN;
#else
DIDR2 |= 1<<(TEMP_1_PIN - 8);
#endif
#endif
#if (TEMP_2_PIN > -1)
#if TEMP_2_PIN < 8
DIDR0 |= 1 << TEMP_2_PIN;
#else
DIDR2 = 1<<(TEMP_2_PIN - 8);
#endif
#endif
#if (TEMP_BED_PIN > -1)
#if TEMP_BED_PIN < 8
DIDR0 |= 1<<TEMP_BED_PIN;
#else
DIDR2 |= 1<<(TEMP_BED_PIN - 8);
#endif
#endif
// Use timer0 for temperature measurement
// Interleave temperature interrupt with millies interrupt
OCR0B = 128;
TIMSK0 |= (1<<OCIE0B);
// Wait for temperature measurement to settle
delay(250);
#ifdef HEATER_0_MINTEMP
minttemp[0] = temp2analog(HEATER_0_MINTEMP, 0);
#endif //MINTEMP
#ifdef HEATER_0_MAXTEMP
maxttemp[0] = temp2analog(HEATER_0_MAXTEMP, 0);
#endif //MAXTEMP
#if (EXTRUDERS > 1) && defined(HEATER_1_MINTEMP)
minttemp[1] = temp2analog(HEATER_1_MINTEMP, 1);
#endif // MINTEMP 1
#if (EXTRUDERS > 1) && defined(HEATER_1_MAXTEMP)
maxttemp[1] = temp2analog(HEATER_1_MAXTEMP, 1);
#endif //MAXTEMP 1
#if (EXTRUDERS > 2) && defined(HEATER_2_MINTEMP)
minttemp[2] = temp2analog(HEATER_2_MINTEMP, 2);
#endif //MINTEMP 2
#if (EXTRUDERS > 2) && defined(HEATER_2_MAXTEMP)
maxttemp[2] = temp2analog(HEATER_2_MAXTEMP, 2);
#endif //MAXTEMP 2
#ifdef BED_MINTEMP
bed_minttemp = temp2analogBed(BED_MINTEMP);
#endif //BED_MINTEMP
#ifdef BED_MAXTEMP
bed_maxttemp = temp2analogBed(BED_MAXTEMP);
#endif //BED_MAXTEMP
}
void setWatch()
{
#ifdef WATCHPERIOD
int t = 0;
for (int e = 0; e < EXTRUDERS; e++)
{
if(isHeatingHotend(e))
watch_oldtemp[0] = degHotend(0);
{
t = max(t,millis());
watch_raw[e] = current_raw[e];
}
}
watchmillis = t;
#endif
}
void disable_heater()
{
for(int i=0;i<EXTRUDERS;i++)
setTargetHotend(0,i);
setTargetBed(0);
#if TEMP_0_PIN > -1
target_raw[0]=0;
soft_pwm[0]=0;
#if HEATER_0_PIN > -1
WRITE(HEATER_0_PIN,LOW);
#endif
#endif
#if TEMP_1_PIN > -1
target_raw[1]=0;
soft_pwm[1]=0;
#if HEATER_1_PIN > -1
WRITE(HEATER_1_PIN,LOW);
#endif
#endif
#if TEMP_2_PIN > -1
target_raw[2]=0;
soft_pwm[2]=0;
#if HEATER_2_PIN > -1
WRITE(HEATER_2_PIN,LOW);
#endif
#endif
#if TEMP_BED_PIN > -1
target_raw_bed=0;
#if HEATER_BED_PIN > -1
WRITE(HEATER_BED_PIN,LOW);
#endif
#endif
}
void max_temp_error(uint8_t e) {
disable_heater();
if(IsStopped() == false) {
SERIAL_ERROR_START;
SERIAL_ERRORLN((int)e);
SERIAL_ERRORLNPGM(": Extruder switched off. MAXTEMP triggered !");
}
}
void min_temp_error(uint8_t e) {
disable_heater();
if(IsStopped() == false) {
SERIAL_ERROR_START;
SERIAL_ERRORLN((int)e);
SERIAL_ERRORLNPGM(": Extruder switched off. MINTEMP triggered !");
}
}
void bed_max_temp_error(void) {
#if HEATER_BED_PIN > -1
WRITE(HEATER_BED_PIN, 0);
#endif
if(IsStopped() == false) {
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM("Temperature heated bed switched off. MAXTEMP triggered !!");
}
}
#define HEAT_INTERVAL 250
#ifdef HEATER_0_USES_MAX6675
long max6675_previous_millis = -HEAT_INTERVAL;
int max6675_temp = 2000;
int read_max6675()
{
if (millis() - max6675_previous_millis < HEAT_INTERVAL)
return max6675_temp;
max6675_previous_millis = millis();
max6675_temp = 0;
#ifdef PRR
PRR &= ~(1<<PRSPI);
#elif defined PRR0
PRR0 &= ~(1<<PRSPI);
#endif
SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPR0);
// enable TT_MAX6675
WRITE(MAX6675_SS, 0);
// ensure 100ns delay - a bit extra is fine
delay(1);
// read MSB
SPDR = 0;
for (;(SPSR & (1<<SPIF)) == 0;);
max6675_temp = SPDR;
max6675_temp <<= 8;
// read LSB
SPDR = 0;
for (;(SPSR & (1<<SPIF)) == 0;);
max6675_temp |= SPDR;
// disable TT_MAX6675
WRITE(MAX6675_SS, 1);
if (max6675_temp & 4)
{
// thermocouple open
max6675_temp = 2000;
}
else
{
max6675_temp = max6675_temp >> 3;
}
return max6675_temp;
}
#endif
// Timer 0 is shared with millies
ISR(TIMER0_COMPB_vect)
{
//these variables are only accesible from the ISR, but static, so they don't loose their value
static unsigned char temp_count = 0;
static unsigned long raw_temp_0_value = 0;
static unsigned long raw_temp_1_value = 0;
static unsigned long raw_temp_2_value = 0;
static unsigned long raw_temp_bed_value = 0;
static unsigned char temp_state = 0;
static unsigned char pwm_count = 1;
static unsigned char soft_pwm_0;
static unsigned char soft_pwm_1;
static unsigned char soft_pwm_2;
if(pwm_count == 0){
soft_pwm_0 = soft_pwm[0];
if(soft_pwm_0 > 0) WRITE(HEATER_0_PIN,1);
#if EXTRUDERS > 1
soft_pwm_1 = soft_pwm[1];
if(soft_pwm_1 > 0) WRITE(HEATER_1_PIN,1);
#endif
#if EXTRUDERS > 2
soft_pwm_2 = soft_pwm[2];
if(soft_pwm_2 > 0) WRITE(HEATER_2_PIN,1);
#endif
}
if(soft_pwm_0 <= pwm_count) WRITE(HEATER_0_PIN,0);
#if EXTRUDERS > 1
if(soft_pwm_1 <= pwm_count) WRITE(HEATER_1_PIN,0);
#endif
#if EXTRUDERS > 2
if(soft_pwm_2 <= pwm_count) WRITE(HEATER_2_PIN,0);
#endif
pwm_count++;
pwm_count &= 0x7f;
switch(temp_state) {
case 0: // Prepare TEMP_0
#if (TEMP_0_PIN > -1)
#if TEMP_0_PIN > 7
ADCSRB = 1<<MUX5;
#else
ADCSRB = 0;
#endif
ADMUX = ((1 << REFS0) | (TEMP_0_PIN & 0x07));
ADCSRA |= 1<<ADSC; // Start conversion
#endif
#ifdef ULTIPANEL
buttons_check();
#endif
temp_state = 1;
break;
case 1: // Measure TEMP_0
#if (TEMP_0_PIN > -1)
raw_temp_0_value += ADC;
#endif
#ifdef HEATER_0_USES_MAX6675 // TODO remove the blocking
raw_temp_0_value = read_max6675();
#endif
temp_state = 2;
break;
case 2: // Prepare TEMP_BED
#if (TEMP_BED_PIN > -1)
#if TEMP_BED_PIN > 7
ADCSRB = 1<<MUX5;
#endif
ADMUX = ((1 << REFS0) | (TEMP_BED_PIN & 0x07));
ADCSRA |= 1<<ADSC; // Start conversion
#endif
#ifdef ULTIPANEL
buttons_check();
#endif
temp_state = 3;
break;
case 3: // Measure TEMP_BED
#if (TEMP_BED_PIN > -1)
raw_temp_bed_value += ADC;
#endif
temp_state = 4;
break;
case 4: // Prepare TEMP_1
#if (TEMP_1_PIN > -1)
#if TEMP_1_PIN > 7
ADCSRB = 1<<MUX5;
#else
ADCSRB = 0;
#endif
ADMUX = ((1 << REFS0) | (TEMP_1_PIN & 0x07));
ADCSRA |= 1<<ADSC; // Start conversion
#endif
#ifdef ULTIPANEL
buttons_check();
#endif
temp_state = 5;
break;
case 5: // Measure TEMP_1
#if (TEMP_1_PIN > -1)
raw_temp_1_value += ADC;
#endif
temp_state = 6;
break;
case 6: // Prepare TEMP_2
#if (TEMP_2_PIN > -1)
#if TEMP_2_PIN > 7
ADCSRB = 1<<MUX5;
#else
ADCSRB = 0;
#endif
ADMUX = ((1 << REFS0) | (TEMP_2_PIN & 0x07));
ADCSRA |= 1<<ADSC; // Start conversion
#endif
#ifdef ULTIPANEL
buttons_check();
#endif
temp_state = 7;
break;
case 7: // Measure TEMP_2
#if (TEMP_2_PIN > -1)
raw_temp_2_value += ADC;
#endif
temp_state = 0;
temp_count++;
break;
// default:
// SERIAL_ERROR_START;
// SERIAL_ERRORLNPGM("Temp measurement error!");
// break;
}
if(temp_count >= 16) // 8 ms * 16 = 128ms.
{
#if defined(HEATER_0_USES_AD595) || defined(HEATER_0_USES_MAX6675)
current_raw[0] = raw_temp_0_value;
#else
current_raw[0] = 16383 - raw_temp_0_value;
#endif
#if EXTRUDERS > 1
#ifdef HEATER_1_USES_AD595
current_raw[1] = raw_temp_1_value;
#else
current_raw[1] = 16383 - raw_temp_1_value;
#endif
#endif
#if EXTRUDERS > 2
#ifdef HEATER_2_USES_AD595
current_raw[2] = raw_temp_2_value;
#else
current_raw[2] = 16383 - raw_temp_2_value;
#endif
#endif
#ifdef BED_USES_AD595
current_raw_bed = raw_temp_bed_value;
#else
current_raw_bed = 16383 - raw_temp_bed_value;
#endif
temp_meas_ready = true;
temp_count = 0;
raw_temp_0_value = 0;
raw_temp_1_value = 0;
raw_temp_2_value = 0;
raw_temp_bed_value = 0;
for(unsigned char e = 0; e < EXTRUDERS; e++) {
if(current_raw[e] >= maxttemp[e]) {
target_raw[e] = 0;
max_temp_error(e);
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
{
Stop();;
}
#endif
}
if(current_raw[e] <= minttemp[e]) {
target_raw[e] = 0;
min_temp_error(e);
#ifndef BOGUS_TEMPERATURE_FAILSAFE_OVERRIDE
{
Stop();
}
#endif
}
}
#if defined(BED_MAXTEMP) && (HEATER_BED_PIN > -1)
if(current_raw_bed >= bed_maxttemp) {
target_raw_bed = 0;
bed_max_temp_error();
Stop();
}
#endif
}
}

@ -0,0 +1,169 @@
/*
temperature.h - temperature controller
Part of Marlin
Copyright (c) 2011 Erik van der Zalm
Grbl 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.
Grbl 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 Grbl. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef temperature_h
#define temperature_h
#include "Marlin.h"
#include "planner.h"
#ifdef PID_ADD_EXTRUSION_RATE
#include "stepper.h"
#endif
// public functions
void tp_init(); //initialise the heating
void manage_heater(); //it is critical that this is called periodically.
//low leven conversion routines
// do not use this routines and variables outsie of temperature.cpp
int temp2analog(int celsius, uint8_t e);
int temp2analogBed(int celsius);
float analog2temp(int raw, uint8_t e);
float analog2tempBed(int raw);
extern int target_raw[EXTRUDERS];
extern int heatingtarget_raw[EXTRUDERS];
extern int current_raw[EXTRUDERS];
extern int target_raw_bed;
extern int current_raw_bed;
#ifdef BED_LIMIT_SWITCHING
extern int target_bed_low_temp ;
extern int target_bed_high_temp ;
#endif
extern float Kp,Ki,Kd,Kc;
#ifdef PIDTEMP
extern float pid_setpoint[EXTRUDERS];
#endif
// #ifdef WATCHPERIOD
extern int watch_raw[EXTRUDERS] ;
// extern unsigned long watchmillis;
// #endif
//high level conversion routines, for use outside of temperature.cpp
//inline so that there is no performance decrease.
//deg=degreeCelsius
FORCE_INLINE float degHotend(uint8_t extruder) {
return analog2temp(current_raw[extruder], extruder);
};
FORCE_INLINE float degBed() {
return analog2tempBed(current_raw_bed);
};
FORCE_INLINE float degTargetHotend(uint8_t extruder) {
return analog2temp(target_raw[extruder], extruder);
};
FORCE_INLINE float degTargetBed() {
return analog2tempBed(target_raw_bed);
};
FORCE_INLINE void setTargetHotend(const float &celsius, uint8_t extruder) {
target_raw[extruder] = temp2analog(celsius, extruder);
#ifdef PIDTEMP
pid_setpoint[extruder] = celsius;
#endif //PIDTEMP
};
FORCE_INLINE void setTargetBed(const float &celsius) {
target_raw_bed = temp2analogBed(celsius);
#ifdef BED_LIMIT_SWITCHING
if(celsius>BED_HYSTERESIS)
{
target_bed_low_temp= temp2analogBed(celsius-BED_HYSTERESIS);
target_bed_high_temp= temp2analogBed(celsius+BED_HYSTERESIS);
}
else
{
target_bed_low_temp=0;
target_bed_high_temp=0;
}
#endif
};
FORCE_INLINE bool isHeatingHotend(uint8_t extruder){
return target_raw[extruder] > current_raw[extruder];
};
FORCE_INLINE bool isHeatingBed() {
return target_raw_bed > current_raw_bed;
};
FORCE_INLINE bool isCoolingHotend(uint8_t extruder) {
return target_raw[extruder] < current_raw[extruder];
};
FORCE_INLINE bool isCoolingBed() {
return target_raw_bed < current_raw_bed;
};
#define degHotend0() degHotend(0)
#define degTargetHotend0() degTargetHotend(0)
#define setTargetHotend0(_celsius) setTargetHotend((_celsius), 0)
#define isHeatingHotend0() isHeatingHotend(0)
#define isCoolingHotend0() isCoolingHotend(0)
#if EXTRUDERS > 1
#define degHotend1() degHotend(1)
#define degTargetHotend1() degTargetHotend(1)
#define setTargetHotend1(_celsius) setTargetHotend((_celsius), 1)
#define isHeatingHotend1() isHeatingHotend(1)
#define isCoolingHotend1() isCoolingHotend(1)
#else
#define setTargetHotend1(_celsius) do{}while(0)
#endif
#if EXTRUDERS > 2
#define degHotend2() degHotend(2)
#define degTargetHotend2() degTargetHotend(2)
#define setTargetHotend2(_celsius) setTargetHotend((_celsius), 2)
#define isHeatingHotend2() isHeatingHotend(2)
#define isCoolingHotend2() isCoolingHotend(2)
#else
#define setTargetHotend2(_celsius) do{}while(0)
#endif
#if EXTRUDERS > 3
#error Invalid number of extruders
#endif
int getHeaterPower(int heater);
void disable_heater();
void setWatch();
void updatePID();
FORCE_INLINE void autotempShutdown(){
#ifdef AUTOTEMP
if(autotemp_enabled)
{
autotemp_enabled=false;
if(degTargetHotend(active_extruder)>autotemp_min)
setTargetHotend(0,active_extruder);
}
#endif
}
void PID_autotune(float temp);
#endif

@ -0,0 +1,507 @@
#ifndef THERMISTORTABLES_H_
#define THERMISTORTABLES_H_
#include "Marlin.h"
#define OVERSAMPLENR 16
#if (THERMISTORHEATER_0 == 1) || (THERMISTORHEATER_1 == 1) || (THERMISTORHEATER_2 == 1) || (THERMISTORBED == 1) //100k bed thermistor
const short temptable_1[][2] PROGMEM = {
{ 23*OVERSAMPLENR , 300 },
{ 25*OVERSAMPLENR , 295 },
{ 27*OVERSAMPLENR , 290 },
{ 28*OVERSAMPLENR , 285 },
{ 31*OVERSAMPLENR , 280 },
{ 33*OVERSAMPLENR , 275 },
{ 35*OVERSAMPLENR , 270 },
{ 38*OVERSAMPLENR , 265 },
{ 41*OVERSAMPLENR , 260 },
{ 44*OVERSAMPLENR , 255 },
{ 48*OVERSAMPLENR , 250 },
{ 52*OVERSAMPLENR , 245 },
{ 56*OVERSAMPLENR , 240 },
{ 61*OVERSAMPLENR , 235 },
{ 66*OVERSAMPLENR , 230 },
{ 71*OVERSAMPLENR , 225 },
{ 78*OVERSAMPLENR , 220 },
{ 84*OVERSAMPLENR , 215 },
{ 92*OVERSAMPLENR , 210 },
{ 100*OVERSAMPLENR , 205 },
{ 109*OVERSAMPLENR , 200 },
{ 120*OVERSAMPLENR , 195 },
{ 131*OVERSAMPLENR , 190 },
{ 143*OVERSAMPLENR , 185 },
{ 156*OVERSAMPLENR , 180 },
{ 171*OVERSAMPLENR , 175 },
{ 187*OVERSAMPLENR , 170 },
{ 205*OVERSAMPLENR , 165 },
{ 224*OVERSAMPLENR , 160 },
{ 245*OVERSAMPLENR , 155 },
{ 268*OVERSAMPLENR , 150 },
{ 293*OVERSAMPLENR , 145 },
{ 320*OVERSAMPLENR , 140 },
{ 348*OVERSAMPLENR , 135 },
{ 379*OVERSAMPLENR , 130 },
{ 411*OVERSAMPLENR , 125 },
{ 445*OVERSAMPLENR , 120 },
{ 480*OVERSAMPLENR , 115 },
{ 516*OVERSAMPLENR , 110 },
{ 553*OVERSAMPLENR , 105 },
{ 591*OVERSAMPLENR , 100 },
{ 628*OVERSAMPLENR , 95 },
{ 665*OVERSAMPLENR , 90 },
{ 702*OVERSAMPLENR , 85 },
{ 737*OVERSAMPLENR , 80 },
{ 770*OVERSAMPLENR , 75 },
{ 801*OVERSAMPLENR , 70 },
{ 830*OVERSAMPLENR , 65 },
{ 857*OVERSAMPLENR , 60 },
{ 881*OVERSAMPLENR , 55 },
{ 903*OVERSAMPLENR , 50 },
{ 922*OVERSAMPLENR , 45 },
{ 939*OVERSAMPLENR , 40 },
{ 954*OVERSAMPLENR , 35 },
{ 966*OVERSAMPLENR , 30 },
{ 977*OVERSAMPLENR , 25 },
{ 985*OVERSAMPLENR , 20 },
{ 993*OVERSAMPLENR , 15 },
{ 999*OVERSAMPLENR , 10 },
{ 1004*OVERSAMPLENR , 5 },
{ 1008*OVERSAMPLENR , 0 } //safety
};
#endif
#if (THERMISTORHEATER_0 == 2) || (THERMISTORHEATER_1 == 2) || (THERMISTORHEATER_2 == 2) || (THERMISTORBED == 2) //200k bed thermistor
const short temptable_2[][2] PROGMEM = {
//200k ATC Semitec 204GT-2
//Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
{1*OVERSAMPLENR, 848},
{30*OVERSAMPLENR, 300}, //top rating 300C
{34*OVERSAMPLENR, 290},
{39*OVERSAMPLENR, 280},
{46*OVERSAMPLENR, 270},
{53*OVERSAMPLENR, 260},
{63*OVERSAMPLENR, 250},
{74*OVERSAMPLENR, 240},
{87*OVERSAMPLENR, 230},
{104*OVERSAMPLENR, 220},
{124*OVERSAMPLENR, 210},
{148*OVERSAMPLENR, 200},
{176*OVERSAMPLENR, 190},
{211*OVERSAMPLENR, 180},
{252*OVERSAMPLENR, 170},
{301*OVERSAMPLENR, 160},
{357*OVERSAMPLENR, 150},
{420*OVERSAMPLENR, 140},
{489*OVERSAMPLENR, 130},
{562*OVERSAMPLENR, 120},
{636*OVERSAMPLENR, 110},
{708*OVERSAMPLENR, 100},
{775*OVERSAMPLENR, 90},
{835*OVERSAMPLENR, 80},
{884*OVERSAMPLENR, 70},
{924*OVERSAMPLENR, 60},
{955*OVERSAMPLENR, 50},
{977*OVERSAMPLENR, 40},
{993*OVERSAMPLENR, 30},
{1004*OVERSAMPLENR, 20},
{1012*OVERSAMPLENR, 10},
{1016*OVERSAMPLENR, 0},
};
#endif
#if (THERMISTORHEATER_0 == 3) || (THERMISTORHEATER_1 == 3) || (THERMISTORHEATER_2 == 3) || (THERMISTORBED == 3) //mendel-parts
const short temptable_3[][2] PROGMEM = {
{1*OVERSAMPLENR,864},
{21*OVERSAMPLENR,300},
{25*OVERSAMPLENR,290},
{29*OVERSAMPLENR,280},
{33*OVERSAMPLENR,270},
{39*OVERSAMPLENR,260},
{46*OVERSAMPLENR,250},
{54*OVERSAMPLENR,240},
{64*OVERSAMPLENR,230},
{75*OVERSAMPLENR,220},
{90*OVERSAMPLENR,210},
{107*OVERSAMPLENR,200},
{128*OVERSAMPLENR,190},
{154*OVERSAMPLENR,180},
{184*OVERSAMPLENR,170},
{221*OVERSAMPLENR,160},
{265*OVERSAMPLENR,150},
{316*OVERSAMPLENR,140},
{375*OVERSAMPLENR,130},
{441*OVERSAMPLENR,120},
{513*OVERSAMPLENR,110},
{588*OVERSAMPLENR,100},
{734*OVERSAMPLENR,80},
{856*OVERSAMPLENR,60},
{938*OVERSAMPLENR,40},
{986*OVERSAMPLENR,20},
{1008*OVERSAMPLENR,0},
{1018*OVERSAMPLENR,-20}
};
#endif
#if (THERMISTORHEATER_0 == 4) || (THERMISTORHEATER_1 == 4) || (THERMISTORHEATER_2 == 4) || (THERMISTORBED == 4) //10k thermistor
const short temptable_4[][2] PROGMEM = {
{1*OVERSAMPLENR, 430},
{54*OVERSAMPLENR, 137},
{107*OVERSAMPLENR, 107},
{160*OVERSAMPLENR, 91},
{213*OVERSAMPLENR, 80},
{266*OVERSAMPLENR, 71},
{319*OVERSAMPLENR, 64},
{372*OVERSAMPLENR, 57},
{425*OVERSAMPLENR, 51},
{478*OVERSAMPLENR, 46},
{531*OVERSAMPLENR, 41},
{584*OVERSAMPLENR, 35},
{637*OVERSAMPLENR, 30},
{690*OVERSAMPLENR, 25},
{743*OVERSAMPLENR, 20},
{796*OVERSAMPLENR, 14},
{849*OVERSAMPLENR, 7},
{902*OVERSAMPLENR, 0},
{955*OVERSAMPLENR, -11},
{1008*OVERSAMPLENR, -35}
};
#endif
#if (THERMISTORHEATER_0 == 5) || (THERMISTORHEATER_1 == 5) || (THERMISTORHEATER_2 == 5) || (THERMISTORBED == 5) //100k ParCan thermistor (104GT-2)
const short temptable_5[][2] PROGMEM = {
// ATC Semitec 104GT-2 (Used in ParCan)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Calculated using 4.7kohm pullup, voltage divider math, and manufacturer provided temp/resistance
{1*OVERSAMPLENR, 713},
{17*OVERSAMPLENR, 300}, //top rating 300C
{20*OVERSAMPLENR, 290},
{23*OVERSAMPLENR, 280},
{27*OVERSAMPLENR, 270},
{31*OVERSAMPLENR, 260},
{37*OVERSAMPLENR, 250},
{43*OVERSAMPLENR, 240},
{51*OVERSAMPLENR, 230},
{61*OVERSAMPLENR, 220},
{73*OVERSAMPLENR, 210},
{87*OVERSAMPLENR, 200},
{106*OVERSAMPLENR, 190},
{128*OVERSAMPLENR, 180},
{155*OVERSAMPLENR, 170},
{189*OVERSAMPLENR, 160},
{230*OVERSAMPLENR, 150},
{278*OVERSAMPLENR, 140},
{336*OVERSAMPLENR, 130},
{402*OVERSAMPLENR, 120},
{476*OVERSAMPLENR, 110},
{554*OVERSAMPLENR, 100},
{635*OVERSAMPLENR, 90},
{713*OVERSAMPLENR, 80},
{784*OVERSAMPLENR, 70},
{846*OVERSAMPLENR, 60},
{897*OVERSAMPLENR, 50},
{937*OVERSAMPLENR, 40},
{966*OVERSAMPLENR, 30},
{986*OVERSAMPLENR, 20},
{1000*OVERSAMPLENR, 10},
{1010*OVERSAMPLENR, 0}
};
#endif
#if (THERMISTORHEATER_0 == 6) || (THERMISTORHEATER_1 == 6) || (THERMISTORHEATER_2 == 6) || (THERMISTORBED == 6) // 100k Epcos thermistor
const short temptable_6[][2] PROGMEM = {
{1*OVERSAMPLENR, 350},
{28*OVERSAMPLENR, 250}, //top rating 250C
{31*OVERSAMPLENR, 245},
{35*OVERSAMPLENR, 240},
{39*OVERSAMPLENR, 235},
{42*OVERSAMPLENR, 230},
{44*OVERSAMPLENR, 225},
{49*OVERSAMPLENR, 220},
{53*OVERSAMPLENR, 215},
{62*OVERSAMPLENR, 210},
{71*OVERSAMPLENR, 205}, //fitted graphically
{78*OVERSAMPLENR, 200}, //fitted graphically
{94*OVERSAMPLENR, 190},
{102*OVERSAMPLENR, 185},
{116*OVERSAMPLENR, 170},
{143*OVERSAMPLENR, 160},
{183*OVERSAMPLENR, 150},
{223*OVERSAMPLENR, 140},
{270*OVERSAMPLENR, 130},
{318*OVERSAMPLENR, 120},
{383*OVERSAMPLENR, 110},
{413*OVERSAMPLENR, 105},
{439*OVERSAMPLENR, 100},
{484*OVERSAMPLENR, 95},
{513*OVERSAMPLENR, 90},
{607*OVERSAMPLENR, 80},
{664*OVERSAMPLENR, 70},
{781*OVERSAMPLENR, 60},
{810*OVERSAMPLENR, 55},
{849*OVERSAMPLENR, 50},
{914*OVERSAMPLENR, 45},
{914*OVERSAMPLENR, 40},
{935*OVERSAMPLENR, 35},
{954*OVERSAMPLENR, 30},
{970*OVERSAMPLENR, 25},
{978*OVERSAMPLENR, 22},
{1008*OVERSAMPLENR, 3}
};
#endif
#if (THERMISTORHEATER_0 == 7) || (THERMISTORHEATER_1 == 7) || (THERMISTORHEATER_2 == 7) || (THERMISTORBED == 7) // 100k Honeywell 135-104LAG-J01
const short temptable_7[][2] PROGMEM = {
{1*OVERSAMPLENR, 500},
{46*OVERSAMPLENR, 270}, //top rating 300C
{50*OVERSAMPLENR, 265},
{54*OVERSAMPLENR, 260},
{58*OVERSAMPLENR, 255},
{62*OVERSAMPLENR, 250},
{67*OVERSAMPLENR, 245},
{72*OVERSAMPLENR, 240},
{79*OVERSAMPLENR, 235},
{85*OVERSAMPLENR, 230},
{91*OVERSAMPLENR, 225},
{99*OVERSAMPLENR, 220},
{107*OVERSAMPLENR, 215},
{116*OVERSAMPLENR, 210},
{126*OVERSAMPLENR, 205},
{136*OVERSAMPLENR, 200},
{149*OVERSAMPLENR, 195},
{160*OVERSAMPLENR, 190},
{175*OVERSAMPLENR, 185},
{191*OVERSAMPLENR, 180},
{209*OVERSAMPLENR, 175},
{224*OVERSAMPLENR, 170},
{246*OVERSAMPLENR, 165},
{267*OVERSAMPLENR, 160},
{293*OVERSAMPLENR, 155},
{316*OVERSAMPLENR, 150},
{340*OVERSAMPLENR, 145},
{364*OVERSAMPLENR, 140},
{396*OVERSAMPLENR, 135},
{425*OVERSAMPLENR, 130},
{460*OVERSAMPLENR, 125},
{489*OVERSAMPLENR, 120},
{526*OVERSAMPLENR, 115},
{558*OVERSAMPLENR, 110},
{591*OVERSAMPLENR, 105},
{628*OVERSAMPLENR, 100},
{660*OVERSAMPLENR, 95},
{696*OVERSAMPLENR, 90},
{733*OVERSAMPLENR, 85},
{761*OVERSAMPLENR, 80},
{794*OVERSAMPLENR, 75},
{819*OVERSAMPLENR, 70},
{847*OVERSAMPLENR, 65},
{870*OVERSAMPLENR, 60},
{892*OVERSAMPLENR, 55},
{911*OVERSAMPLENR, 50},
{929*OVERSAMPLENR, 45},
{944*OVERSAMPLENR, 40},
{959*OVERSAMPLENR, 35},
{971*OVERSAMPLENR, 30},
{981*OVERSAMPLENR, 25},
{989*OVERSAMPLENR, 20},
{994*OVERSAMPLENR, 15},
{1001*OVERSAMPLENR, 10},
{1005*OVERSAMPLENR, 5}
};
#endif
#if (THERMISTORHEATER_0 == 51) || (THERMISTORHEATER_1 == 51) || (THERMISTORHEATER_2 == 51) || (THERMISTORBED == 51)
// 100k EPCOS (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// Verified by linagee.
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: Twice the resolution and better linearity from 150C to 200C
const short temptable_51[][2] PROGMEM = {
{1*OVERSAMPLENR, 350},
{190*OVERSAMPLENR, 250}, //top rating 250C
{203*OVERSAMPLENR, 245},
{217*OVERSAMPLENR, 240},
{232*OVERSAMPLENR, 235},
{248*OVERSAMPLENR, 230},
{265*OVERSAMPLENR, 225},
{283*OVERSAMPLENR, 220},
{302*OVERSAMPLENR, 215},
{322*OVERSAMPLENR, 210},
{344*OVERSAMPLENR, 205},
{366*OVERSAMPLENR, 200},
{390*OVERSAMPLENR, 195},
{415*OVERSAMPLENR, 190},
{440*OVERSAMPLENR, 185},
{467*OVERSAMPLENR, 180},
{494*OVERSAMPLENR, 175},
{522*OVERSAMPLENR, 170},
{551*OVERSAMPLENR, 165},
{580*OVERSAMPLENR, 160},
{609*OVERSAMPLENR, 155},
{638*OVERSAMPLENR, 150},
{666*OVERSAMPLENR, 145},
{695*OVERSAMPLENR, 140},
{722*OVERSAMPLENR, 135},
{749*OVERSAMPLENR, 130},
{775*OVERSAMPLENR, 125},
{800*OVERSAMPLENR, 120},
{823*OVERSAMPLENR, 115},
{845*OVERSAMPLENR, 110},
{865*OVERSAMPLENR, 105},
{884*OVERSAMPLENR, 100},
{901*OVERSAMPLENR, 95},
{917*OVERSAMPLENR, 90},
{932*OVERSAMPLENR, 85},
{944*OVERSAMPLENR, 80},
{956*OVERSAMPLENR, 75},
{966*OVERSAMPLENR, 70},
{975*OVERSAMPLENR, 65},
{982*OVERSAMPLENR, 60},
{989*OVERSAMPLENR, 55},
{995*OVERSAMPLENR, 50},
{1000*OVERSAMPLENR, 45},
{1004*OVERSAMPLENR, 40},
{1007*OVERSAMPLENR, 35},
{1010*OVERSAMPLENR, 30},
{1013*OVERSAMPLENR, 25},
{1015*OVERSAMPLENR, 20},
{1017*OVERSAMPLENR, 15},
{1018*OVERSAMPLENR, 10},
{1019*OVERSAMPLENR, 5},
{1020*OVERSAMPLENR, 0},
{1021*OVERSAMPLENR, -5}
};
#endif
#if (THERMISTORHEATER_0 == 52) || (THERMISTORHEATER_1 == 52) || (THERMISTORHEATER_2 == 52) || (THERMISTORBED == 52)
// 200k ATC Semitec 204GT-2 (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: More resolution and better linearity from 150C to 200C
const short temptable_52[][2] PROGMEM = {
{1*OVERSAMPLENR, 500},
{125*OVERSAMPLENR, 300}, //top rating 300C
{142*OVERSAMPLENR, 290},
{162*OVERSAMPLENR, 280},
{185*OVERSAMPLENR, 270},
{211*OVERSAMPLENR, 260},
{240*OVERSAMPLENR, 250},
{274*OVERSAMPLENR, 240},
{312*OVERSAMPLENR, 230},
{355*OVERSAMPLENR, 220},
{401*OVERSAMPLENR, 210},
{452*OVERSAMPLENR, 200},
{506*OVERSAMPLENR, 190},
{563*OVERSAMPLENR, 180},
{620*OVERSAMPLENR, 170},
{677*OVERSAMPLENR, 160},
{732*OVERSAMPLENR, 150},
{783*OVERSAMPLENR, 140},
{830*OVERSAMPLENR, 130},
{871*OVERSAMPLENR, 120},
{906*OVERSAMPLENR, 110},
{935*OVERSAMPLENR, 100},
{958*OVERSAMPLENR, 90},
{976*OVERSAMPLENR, 80},
{990*OVERSAMPLENR, 70},
{1000*OVERSAMPLENR, 60},
{1008*OVERSAMPLENR, 50},
{1013*OVERSAMPLENR, 40},
{1017*OVERSAMPLENR, 30},
{1019*OVERSAMPLENR, 20},
{1021*OVERSAMPLENR, 10},
{1022*OVERSAMPLENR, 0}
};
#endif
#if (THERMISTORHEATER_0 == 55) || (THERMISTORHEATER_1 == 55) || (THERMISTORHEATER_2 == 55) || (THERMISTORBED == 55)
// 100k ATC Semitec 104GT-2 (Used on ParCan) (WITH 1kohm RESISTOR FOR PULLUP, R9 ON SANGUINOLOLU! NOT FOR 4.7kohm PULLUP! THIS IS NOT NORMAL!)
// Verified by linagee. Source: http://shop.arcol.hu/static/datasheets/thermistors.pdf
// Calculated using 1kohm pullup, voltage divider math, and manufacturer provided temp/resistance
// Advantage: More resolution and better linearity from 150C to 200C
const short temptable_55[][2] PROGMEM = {
{1*OVERSAMPLENR, 500},
{76*OVERSAMPLENR, 300},
{87*OVERSAMPLENR, 290},
{100*OVERSAMPLENR, 280},
{114*OVERSAMPLENR, 270},
{131*OVERSAMPLENR, 260},
{152*OVERSAMPLENR, 250},
{175*OVERSAMPLENR, 240},
{202*OVERSAMPLENR, 230},
{234*OVERSAMPLENR, 220},
{271*OVERSAMPLENR, 210},
{312*OVERSAMPLENR, 200},
{359*OVERSAMPLENR, 190},
{411*OVERSAMPLENR, 180},
{467*OVERSAMPLENR, 170},
{527*OVERSAMPLENR, 160},
{590*OVERSAMPLENR, 150},
{652*OVERSAMPLENR, 140},
{713*OVERSAMPLENR, 130},
{770*OVERSAMPLENR, 120},
{822*OVERSAMPLENR, 110},
{867*OVERSAMPLENR, 100},
{905*OVERSAMPLENR, 90},
{936*OVERSAMPLENR, 80},
{961*OVERSAMPLENR, 70},
{979*OVERSAMPLENR, 60},
{993*OVERSAMPLENR, 50},
{1003*OVERSAMPLENR, 40},
{1010*OVERSAMPLENR, 30},
{1015*OVERSAMPLENR, 20},
{1018*OVERSAMPLENR, 10},
{1020*OVERSAMPLENR, 0}
};
#endif
#define _TT_NAME(_N) temptable_ ## _N
#define TT_NAME(_N) _TT_NAME(_N)
#ifdef THERMISTORHEATER_0
#define heater_0_temptable TT_NAME(THERMISTORHEATER_0)
#define heater_0_temptable_len (sizeof(heater_0_temptable)/sizeof(*heater_0_temptable))
#else
#ifdef HEATER_0_USES_THERMISTOR
#error No heater 0 thermistor table specified
#else // HEATER_0_USES_THERMISTOR
#define heater_0_temptable 0
#define heater_0_temptable_len 0
#endif // HEATER_0_USES_THERMISTOR
#endif
#ifdef THERMISTORHEATER_1
#define heater_1_temptable TT_NAME(THERMISTORHEATER_1)
#define heater_1_temptable_len (sizeof(heater_1_temptable)/sizeof(*heater_1_temptable))
#else
#ifdef HEATER_1_USES_THERMISTOR
#error No heater 1 thermistor table specified
#else // HEATER_1_USES_THERMISTOR
#define heater_1_temptable 0
#define heater_1_temptable_len 0
#endif // HEATER_1_USES_THERMISTOR
#endif
#ifdef THERMISTORHEATER_2
#define heater_2_temptable TT_NAME(THERMISTORHEATER_2)
#define heater_2_temptable_len (sizeof(heater_2_temptable)/sizeof(*heater_2_temptable))
#else
#ifdef HEATER_2_USES_THERMISTOR
#error No heater 2 thermistor table specified
#else // HEATER_2_USES_THERMISTOR
#define heater_2_temptable 0
#define heater_2_temptable_len 0
#endif // HEATER_2_USES_THERMISTOR
#endif
#ifdef THERMISTORBED
#define bedtemptable TT_NAME(THERMISTORBED)
#define bedtemptable_len (sizeof(bedtemptable)/sizeof(*bedtemptable))
#else
#ifdef BED_USES_THERMISTOR
#error No bed thermistor table specified
#endif // BED_USES_THERMISTOR
#endif
#endif //THERMISTORTABLES_H_

@ -0,0 +1,172 @@
#ifndef ULTRALCD_H
#define ULTRALCD_H
#include "Marlin.h"
#ifdef ULTRA_LCD
#include <LiquidCrystal.h>
void lcd_status();
void lcd_init();
void lcd_status(const char* message);
void beep();
void buttons_init();
void buttons_check();
#define LCD_UPDATE_INTERVAL 100
#define STATUSTIMEOUT 15000
extern LiquidCrystal lcd;
extern volatile char buttons; //the last checked buttons in a bit array.
#ifdef NEWPANEL
#define EN_C (1<<BLEN_C)
#define EN_B (1<<BLEN_B)
#define EN_A (1<<BLEN_A)
#define CLICKED (buttons&EN_C)
#define BLOCK {blocking=millis()+blocktime;}
#if (SDCARDDETECT > -1)
#ifdef SDCARDDETECTINVERTED
#define CARDINSERTED (READ(SDCARDDETECT)!=0)
#else
#define CARDINSERTED (READ(SDCARDDETECT)==0)
#endif
#endif //SDCARDTETECTINVERTED
#else
//atomatic, do not change
#define B_LE (1<<BL_LE)
#define B_UP (1<<BL_UP)
#define B_MI (1<<BL_MI)
#define B_DW (1<<BL_DW)
#define B_RI (1<<BL_RI)
#define B_ST (1<<BL_ST)
#define EN_B (1<<BLEN_B)
#define EN_A (1<<BLEN_A)
#define CLICKED ((buttons&B_MI)||(buttons&B_ST))
#define BLOCK {blocking[BL_MI]=millis()+blocktime;blocking[BL_ST]=millis()+blocktime;}
#endif
// blocking time for recognizing a new keypress of one key, ms
#define blocktime 500
#define lcdslow 5
enum MainStatus{Main_Status, Main_Menu, Main_Prepare,Sub_PrepareMove, Main_Control, Main_SD,Sub_TempControl,Sub_MotionControl,Sub_RetractControl, Sub_PreheatPLASettings, Sub_PreheatABSSettings};
class MainMenu{
public:
MainMenu();
void update();
int8_t activeline;
MainStatus status;
uint8_t displayStartingRow;
void showStatus();
void showMainMenu();
void showPrepare();
void showTune();
void showControl();
void showControlMotion();
void showControlTemp();
void showControlRetract();
void showAxisMove();
void showSD();
void showPLAsettings();
void showABSsettings();
bool force_lcd_update;
long lastencoderpos;
int8_t lineoffset;
int8_t lastlineoffset;
bool linechanging;
bool tune;
private:
FORCE_INLINE void updateActiveLines(const uint8_t &maxlines,volatile long &encoderpos)
{
if(linechanging) return; // an item is changint its value, do not switch lines hence
lastlineoffset=lineoffset;
long curencoderpos=encoderpos;
force_lcd_update=false;
if( (abs(curencoderpos-lastencoderpos)<lcdslow) )
{
lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?' ':' ');
if(curencoderpos<0)
{
lineoffset--;
if(lineoffset<0) lineoffset=0;
curencoderpos=lcdslow-1;
}
if(curencoderpos>(LCD_HEIGHT-1+1)*lcdslow)
{
lineoffset++;
curencoderpos=(LCD_HEIGHT-1)*lcdslow;
if(lineoffset>(maxlines+1-LCD_HEIGHT))
lineoffset=maxlines+1-LCD_HEIGHT;
if(curencoderpos>maxlines*lcdslow)
curencoderpos=maxlines*lcdslow;
}
lastencoderpos=encoderpos=curencoderpos;
activeline=curencoderpos/lcdslow;
if(activeline<0) activeline=0;
if(activeline>LCD_HEIGHT-1) activeline=LCD_HEIGHT-1;
if(activeline>maxlines)
{
activeline=maxlines;
curencoderpos=maxlines*lcdslow;
}
if(lastlineoffset!=lineoffset)
force_lcd_update=true;
lcd.setCursor(0,activeline);lcd.print((activeline+lineoffset)?'>':'\003');
}
}
FORCE_INLINE void clearIfNecessary()
{
if(lastlineoffset!=lineoffset ||force_lcd_update)
{
force_lcd_update=true;
lcd.clear();
}
}
};
//conversion routines, could need some overworking
char *ftostr51(const float &x);
char *ftostr52(const float &x);
char *ftostr31(const float &x);
char *ftostr3(const float &x);
#define LCD_INIT lcd_init();
#define LCD_MESSAGE(x) lcd_status(x);
#define LCD_MESSAGEPGM(x) lcd_statuspgm(MYPGM(x));
#define LCD_ALERTMESSAGEPGM(x) lcd_alertstatuspgm(MYPGM(x));
#define LCD_STATUS lcd_status()
#else //no lcd
#define LCD_INIT
#define LCD_STATUS
#define LCD_MESSAGE(x)
#define LCD_MESSAGEPGM(x)
#define LCD_ALERTMESSAGEPGM(x)
FORCE_INLINE void lcd_status() {};
#define CLICKED false
#define BLOCK ;
#endif
void lcd_statuspgm(const char* message);
void lcd_alertstatuspgm(const char* message);
char *ftostr3(const float &x);
char *itostr2(const uint8_t &x);
char *ftostr31(const float &x);
char *ftostr32(const float &x);
char *itostr31(const int &xx);
char *itostr3(const int &xx);
char *itostr4(const int &xx);
char *ftostr51(const float &x);
#endif //ULTRALCD

File diff suppressed because it is too large Load Diff

@ -0,0 +1,16 @@
#ifndef WATCHDOG_H
#define WATCHDOG_H
#include "Marlin.h"
#ifdef USE_WATCHDOG
// intialise watch dog with a 1 sec interrupt time
void wd_init();
// pad the dog/reset watchdog. MUST be called at least every second after the first wd_init or avr will go into emergency procedures..
void wd_reset();
#else
FORCE_INLINE void wd_init() {};
FORCE_INLINE void wd_reset() {};
#endif
#endif

@ -0,0 +1,63 @@
#ifdef USE_WATCHDOG
#include "Marlin.h"
#include "watchdog.h"
//===========================================================================
//=============================private variables ============================
//===========================================================================
static volatile uint8_t timeout_seconds=0;
void(* ctrlaltdelete) (void) = 0; //does not work on my atmega2560
//===========================================================================
//=============================functinos ============================
//===========================================================================
/// intialise watch dog with a 1 sec interrupt time
void wd_init()
{
WDTCSR |= (1<<WDCE )|(1<<WDE ); //allow changes
WDTCSR = (1<<WDCE )|(1<<WDE )|(1<<WDP3 )|(1<<WDP0); // Reset after 8 sec.
// WDTCSR = (1<<WDIF)|(1<<WDIE)| (1<<WDCE )|(1<<WDE )| (1<<WDP3) | (1<<WDP0);
}
/// reset watchdog. MUST be called every 1s after init or avr will reset.
void wd_reset()
{
wdt_reset();
}
//===========================================================================
//=============================ISR ============================
//===========================================================================
//Watchdog timer interrupt, called if main program blocks >1sec
ISR(WDT_vect)
{
if(timeout_seconds++ >= WATCHDOG_TIMEOUT)
{
#ifdef RESET_MANUAL
LCD_MESSAGEPGM("Please Reset!");
LCD_STATUS;
SERIAL_ERROR_START;
SERIAL_ERRORLNPGM("Something is wrong, please turn off the printer.");
#else
LCD_MESSAGEPGM("Timeout, resetting!");
LCD_STATUS;
#endif
//disable watchdog, it will survife reboot.
WDTCSR |= (1<<WDCE) | (1<<WDE);
WDTCSR = 0;
#ifdef RESET_MANUAL
kill(); //kill blocks
while(1); //wait for user or serial reset
#else
ctrlaltdelete();
#endif
}
}
#endif /* USE_WATCHDOG */

@ -0,0 +1,141 @@
/*
* fixed by this patch:
* http://code.google.com/p/arduino/issues/detail?id=604
* */
/*
wiring.h - Partial implementation of the Wiring API for the ATmega8.
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
$Id$
*/
#ifndef Wiring_h
#define Wiring_h
#include <avr/io.h>
#include <stdlib.h>
#include "binary.h"
#ifdef __cplusplus
extern "C"{
#endif
#define HIGH 0x1
#define LOW 0x0
#define INPUT 0x0
#define OUTPUT 0x1
#define true 0x1
#define false 0x0
#define PI 3.1415926535897932384626433832795
#define HALF_PI 1.5707963267948966192313216916398
#define TWO_PI 6.283185307179586476925286766559
#define DEG_TO_RAD 0.017453292519943295769236907684886
#define RAD_TO_DEG 57.295779513082320876798154814105
#define SERIAL 0x0
#define DISPLAY 0x1
#define LSBFIRST 0
#define MSBFIRST 1
#define CHANGE 1
#define FALLING 2
#define RISING 3
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define INTERNAL1V1 2
#define INTERNAL2V56 3
#else
#define INTERNAL 3
#endif
#define DEFAULT 1
#define EXTERNAL 0
// undefine stdlib's abs if encountered
#ifdef abs
#undef abs
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#if __AVR_LIBC_VERSION__ < 10701UL
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#endif
#define radians(deg) ((deg)*DEG_TO_RAD)
#define degrees(rad) ((rad)*RAD_TO_DEG)
#define sq(x) ((x)*(x))
#define interrupts() sei()
#define noInterrupts() cli()
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( ((a) * 1000L) / (F_CPU / 1000L) )
#define microsecondsToClockCycles(a) ( ((a) * (F_CPU / 1000L)) / 1000L )
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
typedef unsigned int word;
#define bit(b) (1UL << (b))
typedef uint8_t boolean;
typedef uint8_t byte;
void init(void);
void pinMode(uint8_t, uint8_t);
void digitalWrite(uint8_t, uint8_t);
int digitalRead(uint8_t);
int analogRead(uint8_t);
void analogReference(uint8_t mode);
void analogWrite(uint8_t, int);
unsigned long millis(void);
unsigned long micros(void);
void delay(unsigned long);
void delayMicroseconds(unsigned int us);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
void attachInterrupt(uint8_t, void (*)(void), int mode);
void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

@ -0,0 +1,222 @@
WARNING:
--------
THIS IS RELEASE CANDIDATE 2 FOR MARLIN 1.0.0
The configuration is now split in two files
Configuration.h for the normal settings
Configuration_adv.h for the advanced settings
Gen7T is not supported.
Quick Information
===================
This RepRap firmware is a mashup between <a href="https://github.com/kliment/Sprinter">Sprinter</a>, <a href="https://github.com/simen/grbl/tree">grbl</a> and many original parts.
Derived from Sprinter and Grbl by Erik van der Zalm.
Sprinters lead developers are Kliment and caru.
Grbls lead developer is Simen Svale Skogsrud. Sonney Jeon (Chamnit) improved some parts of grbl
A fork by bkubicek for the Ultimaker was merged, and further development was aided by him.
Some features have been added by:
Lampmaker, Bradley Feldman, and others...
Features:
* Interrupt based movement with real linear acceleration
* High steprate
* Look ahead (Keep the speed high when possible. High cornering speed)
* Interrupt based temperature protection
* preliminary support for Matthew Roberts advance algorithm
For more info see: http://reprap.org/pipermail/reprap-dev/2011-May/003323.html
* Full endstop support
* SD Card support
* SD Card folders (works in pronterface)
* SD Card autostart support
* LCD support (ideally 20x4)
* LCD menu system for autonomous SD card printing, controlled by an click-encoder.
* EEPROM storage of e.g. max-velocity, max-acceleration, and similar variables
* many small but handy things originating from bkubicek's fork.
* Arc support
* Temperature oversampling
* Dynamic Temperature setpointing aka "AutoTemp"
* Support for QTMarlin, a very beta GUI for PID-tuning and velocity-acceleration testing. https://github.com/bkubicek/QTMarlin
* Endstop trigger reporting to the host software.
* Updated sdcardlib
* Heater power reporting. Useful for PID monitoring.
* PID tuning
* CoreXY kinematics (www.corexy.com/theory.html)
The default baudrate is 250000. This baudrate has less jitter and hence errors than the usual 115200 baud, but is less supported by drivers and host-environments.
Differences and additions to the already good Sprinter firmware:
================================================================
*Look-ahead:*
Marlin has look-ahead. While sprinter has to break and re-accelerate at each corner,
lookahead will only decelerate and accelerate to a velocity,
so that the change in vectorial velocity magnitude is less than the xy_jerk_velocity.
This is only possible, if some future moves are already processed, hence the name.
It leads to less over-deposition at corners, especially at flat angles.
*Arc support:*
Slic3r can find curves that, although broken into segments, were ment to describe an arc.
Marlin is able to print those arcs. The advantage is the firmware can choose the resolution,
and can perform the arc with nearly constant velocity, resulting in a nice finish.
Also, less serial communication is needed.
*Temperature Oversampling:*
To reduce noise and make the PID-differential term more useful, 16 ADC conversion results are averaged.
*AutoTemp:*
If your gcode contains a wide spread of extruder velocities, or you realtime change the building speed, the temperature should be changed accordingly.
Usually, higher speed requires higher temperature.
This can now be performed by the AutoTemp function
By calling M109 S<mintemp> T<maxtemp> F<factor> you enter the autotemp mode.
You can leave it by calling M109 without any F.
If active, the maximal extruder stepper rate of all buffered moves will be calculated, and named "maxerate" [steps/sec].
The wanted temperature then will be set to t=tempmin+factor*maxerate, while being limited between tempmin and tempmax.
If the target temperature is set manually or by gcode to a value less then tempmin, it will be kept without change.
Ideally, your gcode can be completely free of temperature controls, apart from a M109 S T F in the start.gcode, and a M109 S0 in the end.gcode.
*EEPROM:*
If you know your PID values, the acceleration and max-velocities of your unique machine, you can set them, and finally store them in the EEPROM.
After each reboot, it will magically load them from EEPROM, independent what your Configuration.h says.
*LCD Menu:*
If your hardware supports it, you can build yourself a LCD-CardReader+Click+encoder combination. It will enable you to realtime tune temperatures,
accelerations, velocities, flow rates, select and print files from the SD card, preheat, disable the steppers, and do other fancy stuff.
One working hardware is documented here: http://www.thingiverse.com/thing:12663
Also, with just a 20x4 or 16x2 display, useful data is shown.
*SD card folders:*
If you have an SD card reader attached to your controller, also folders work now. Listing the files in pronterface will show "/path/subpath/file.g".
You can write to file in a subfolder by specifying a similar text using small letters in the path.
Also, backup copies of various operating systems are hidden, as well as files not ending with ".g".
*SD card folders:*
If you place a file auto[0-9].g into the root of the sd card, it will be automatically executed if you boot the printer. The same file will be executed by selecting "Autostart" from the menu.
First *0 will be performed, than *1 and so on. That way, you can heat up or even print automatically without user interaction.
*Endstop trigger reporting:*
If an endstop is hit while moving towards the endstop, the location at which the firmware thinks that the endstop was triggered is outputed on the serial port.
This is useful, because the user gets a warning message.
However, also tools like QTMarlin can use this for finding acceptable combinations of velocity+acceleration.
*Coding paradigm:*
Not relevant from a user side, but Marlin was split into thematic junks, and has tried to partially enforced private variables.
This is intended to make it clearer, what interacts which what, and leads to a higher level of modularization.
We think that this is a useful prestep for porting this firmware to e.g. an ARM platform in the future.
A lot of RAM (with enabled LCD ~2200 bytes) was saved by storing char []="some message" in Program memory.
In the serial communication, a #define based level of abstraction was enforced, so that it is clear that
some transfer is information (usually beginning with "echo:"), an error "error:", or just normal protocol,
necessary for backwards compatibility.
*Interrupt based temperature measurements:*
An interrupt is used to manage ADC conversions, and enforce checking for critical temperatures.
This leads to less blocking in the heater management routine.
Non-standard M-Codes, different to an old version of sprinter:
==============================================================
Movement:
* G2 - CW ARC
* G3 - CCW ARC
General:
* M17 - Enable/Power all stepper motors. Compatibility to ReplicatorG.
* M18 - Disable all stepper motors; same as M84.Compatibility to ReplicatorG.
* M30 - Print time since last M109 or SD card start to serial
* M42 - Change pin status via gcode
* M80 - Turn on Power Supply
* M81 - Turn off Power Supply
* M114 - Output current position to serial port
* M119 - Output Endstop status to serial port
Movement variables:
* M202 - Set max acceleration in units/s^2 for travel moves (M202 X1000 Y1000) Unused in Marlin!!
* M203 - Set maximum feedrate that your machine can sustain (M203 X200 Y200 Z300 E10000) in mm/sec
* M204 - Set default acceleration: S normal moves T filament only moves (M204 S3000 T7000) im mm/sec^2 also sets minimum segment time in ms (B20000) to prevent buffer underruns and M20 minimum feedrate
* M206 - set home offsets. This sets the X,Y,Z coordinates of the endstops (and is added to the {X,Y,Z}_HOME_POS configuration options (and is also added to the coordinates, if any, provided to G82, as with earlier firmware)
* M220 - set build speed mulitplying S:factor in percent ; aka "realtime tuneing in the gcode". So you can slow down if you have islands in one height-range, and speed up otherwise.
* M221 - set the extrude multiplying S:factor in percent
* M400 - Finish all buffered moves.
Temperature variables:
* M301 - Set PID parameters P I and D
* M302 - Allow cold extrudes
* M303 - PID relay autotune S<temperature> sets the target temperature. (default target temperature = 150C)
Advance:
* M200 - Set filament diameter for advance
* M205 - advanced settings: minimum travel speed S=while printing T=travel only, B=minimum segment time X= maximum xy jerk, Z=maximum Z jerk
EEPROM:
* M500 - stores paramters in EEPROM. This parameters are stored: axis_steps_per_unit, max_feedrate, max_acceleration ,acceleration,retract_acceleration,
minimumfeedrate,mintravelfeedrate,minsegmenttime, jerk velocities, PID
* M501 - reads parameters from EEPROM (if you need reset them after you changed them temporarily).
* M502 - reverts to the default "factory settings". You still need to store them in EEPROM afterwards if you want to.
* M503 - print the current settings (from memory not from eeprom)
MISC:
* M240 - Trigger a camera to take a photograph
* M999 - Restart after being stopped by error
Configuring and compilation:
============================
Install the arduino software IDE/toolset v22
http://www.arduino.cc/en/Main/Software
For gen6 and sanguinololu the Sanguino directory in the Marlin dir needs to be copied to the arduino environment.
copy Marlin\sanguino <arduino home>\hardware\Sanguino
Install Ultimaker's RepG 25 build
http://software.ultimaker.com
For SD handling and as better substitute (apart from stl manipulation) download
the very nice Kliment's printrun/pronterface https://github.com/kliment/Printrun
Copy the Ultimaker Marlin firmware
https://github.com/ErikZalm/Marlin/tree/Marlin_v1
(Use the download button)
Start the arduino IDE.
Select Tools -> Board -> Arduino Mega 2560 or your microcontroller
Select the correct serial port in Tools ->Serial Port
Open Marlin.pde
Click the Verify/Compile button
Click the Upload button
If all goes well the firmware is uploading
Start Ultimaker's Custom RepG 25
Make sure Show Experimental Profiles is enabled in Preferences
Select Sprinter as the Driver
Press the Connect button.
KNOWN ISSUES: RepG will display: Unknown: marlin x.y.z
That's ok. Enjoy Silky Smooth Printing.
Loading…
Cancel
Save