From 7a66c18e70ae097f47654bd63d6172bb6452a384 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 15 Jan 2011 13:29:08 +0000 Subject: [PATCH 01/54] Fix to optiboot infinite loop problem. Explicitly setting R1 to 0 so that the watchdog timer is properly initializing, preventing it from timing out and resetting the processor. http://code.google.com/p/optiboot/issues/detail?id=26 http://code.google.com/p/arduino/issues/detail?id=446 --- bootloaders/optiboot/optiboot.c | 2 +- bootloaders/optiboot/optiboot_atmega328.hex | 62 +-- bootloaders/optiboot/optiboot_atmega328.lst | 462 ++++++++++---------- 3 files changed, 265 insertions(+), 261 deletions(-) diff --git a/bootloaders/optiboot/optiboot.c b/bootloaders/optiboot/optiboot.c index af92995..c7d817a 100644 --- a/bootloaders/optiboot/optiboot.c +++ b/bootloaders/optiboot/optiboot.c @@ -213,7 +213,7 @@ int main(void) { // If not, uncomment the following instructions: // cli(); // SP=RAMEND; // This is done by hardware reset - // asm volatile ("clr __zero_reg__"); + asm volatile ("clr __zero_reg__"); uint8_t ch; diff --git a/bootloaders/optiboot/optiboot_atmega328.hex b/bootloaders/optiboot/optiboot_atmega328.hex index b1c8567..e8aa31c 100644 --- a/bootloaders/optiboot/optiboot_atmega328.hex +++ b/bootloaders/optiboot/optiboot_atmega328.hex @@ -1,33 +1,33 @@ -:107E000085E08093810082E08093C00088E18093C8 -:107E1000C10086E08093C20080E18093C40084B7F3 -:107E200014BE81FFD0D08DE0C8D0259A86E020E333 -:107E30003CEF91E0309385002093840096BBB09B8B -:107E4000FECF1D9AA8958150A9F7DD24D394A5E013 -:107E5000EA2EF1E1FF2EA4D0813421F481E0BED0DE -:107E600083E024C0823411F484E103C0853419F422 -:107E700085E0B4D08AC08535A1F492D0082F10E0F7 -:107E800010930102009300028BD090E0982F882776 -:107E9000802B912B880F991F9093010280930002F1 -:107EA00073C0863529F484E099D080E071D06DC02C -:107EB000843609F043C07CD0E0910002F0910102C9 -:107EC00083E080935700E895C0E0D1E069D08993C2 -:107ED000809102028150809302028823B9F778D002 -:107EE00007B600FCFDCF4091000250910102A0E0D6 -:107EF000B1E02C9130E011968C91119790E0982F81 -:107F00008827822B932B1296FA010C01D0925700EE -:107F1000E89511244E5F5F4FF1E0A038BF0749F7A5 -:107F2000E0910002F0910102E0925700E89507B657 -:107F300000FCFDCFF0925700E89527C08437B9F4D4 -:107F400037D046D0E0910002F09101023196F093D3 -:107F50000102E09300023197E4918E2F19D08091B5 -:107F60000202815080930202882361F70EC0853798 -:107F700039F42ED08EE10CD085E90AD08FE096CF6F -:107F8000813511F488E019D023D080E101D063CF8E -:107F9000982F8091C00085FFFCCF9093C600089574 -:107FA000A8958091C00087FFFCCF8091C6000895FE -:107FB000F7DFF6DF80930202F3CFE0E6F0E098E12E -:107FC00090838083089580E0F8DFEE27FF270994EF -:107FD000E7DF803209F0F7DF84E1DACF1F93182F53 -:0C7FE000DFDF1150E9F7F4DF1F91089576 +:107E0000112485E08093810082E08093C00088E1A6 +:107E10008093C10086E08093C20080E18093C4001B +:107E200084B714BE81FFD0D08DE0C8D0259A86E0FB +:107E300020E33CEF91E0309385002093840096BBD3 +:107E4000B09BFECF1D9AA8958150A9F7DD24D3944D +:107E5000A5E0EA2EF1E1FF2EA4D0813421F481E0E7 +:107E6000BED083E024C0823411F484E103C08534A1 +:107E700019F485E0B4D08AC08535A1F492D0082FDA +:107E800010E010930102009300028BD090E0982F35 +:107E90008827802B912B880F991F90930102809344 +:107EA000000273C0863529F484E099D080E071D057 +:107EB0006DC0843609F043C07CD0E0910002F0919F +:107EC000010283E080935700E895C0E0D1E069D0DB +:107ED0008993809102028150809302028823B9F72E +:107EE00078D007B600FCFDCF40910002509101020E +:107EF000A0E0B1E02C9130E011968C91119790E0C8 +:107F0000982F8827822B932B1296FA010C01D0927E +:107F10005700E89511244E5F5F4FF1E0A038BF078E +:107F200049F7E0910002F0910102E0925700E895D4 +:107F300007B600FCFDCFF0925700E89527C08437C4 +:107F4000B9F437D046D0E0910002F09101023196A9 +:107F5000F0930102E09300023197E4918E2F19D043 +:107F600080910202815080930202882361F70EC043 +:107F7000853739F42ED08EE10CD085E90AD08FE018 +:107F800096CF813511F488E019D023D080E101D05B +:107F900063CF982F8091C00085FFFCCF9093C600DF +:107FA0000895A8958091C00087FFFCCF8091C600FE +:107FB0000895F7DFF6DF80930202F3CFE0E6F0E00A +:107FC00098E190838083089580E0F8DFEE27FF2713 +:107FD0000994E7DF803209F0F7DF84E1DACF1F93FD +:0E7FE000182FDFDF1150E9F7F4DF1F9108952D :0400000300007E007B :00000001FF diff --git a/bootloaders/optiboot/optiboot_atmega328.lst b/bootloaders/optiboot/optiboot_atmega328.lst index 888871d..dd879dc 100644 --- a/bootloaders/optiboot/optiboot_atmega328.lst +++ b/bootloaders/optiboot/optiboot_atmega328.lst @@ -3,25 +3,25 @@ optiboot_atmega328.elf: file format elf32-avr Sections: Idx Name Size VMA LMA File off Algn - 0 .text 000001ec 00007e00 00007e00 00000054 2**1 + 0 .text 000001ee 00007e00 00007e00 00000054 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE - 1 .debug_aranges 00000028 00000000 00000000 00000240 2**0 + 1 .debug_aranges 00000028 00000000 00000000 00000242 2**0 CONTENTS, READONLY, DEBUGGING - 2 .debug_pubnames 0000006a 00000000 00000000 00000268 2**0 + 2 .debug_pubnames 0000006a 00000000 00000000 0000026a 2**0 CONTENTS, READONLY, DEBUGGING - 3 .debug_info 00000269 00000000 00000000 000002d2 2**0 + 3 .debug_info 00000269 00000000 00000000 000002d4 2**0 CONTENTS, READONLY, DEBUGGING - 4 .debug_abbrev 00000196 00000000 00000000 0000053b 2**0 + 4 .debug_abbrev 00000196 00000000 00000000 0000053d 2**0 CONTENTS, READONLY, DEBUGGING - 5 .debug_line 000003d3 00000000 00000000 000006d1 2**0 + 5 .debug_line 000003db 00000000 00000000 000006d3 2**0 CONTENTS, READONLY, DEBUGGING - 6 .debug_frame 00000090 00000000 00000000 00000aa4 2**2 + 6 .debug_frame 00000090 00000000 00000000 00000ab0 2**2 CONTENTS, READONLY, DEBUGGING - 7 .debug_str 00000135 00000000 00000000 00000b34 2**0 + 7 .debug_str 00000124 00000000 00000000 00000b40 2**0 CONTENTS, READONLY, DEBUGGING - 8 .debug_loc 000001d1 00000000 00000000 00000c69 2**0 + 8 .debug_loc 000001d1 00000000 00000000 00000c64 2**0 CONTENTS, READONLY, DEBUGGING - 9 .debug_ranges 00000068 00000000 00000000 00000e3a 2**0 + 9 .debug_ranges 00000068 00000000 00000000 00000e35 2**0 CONTENTS, READONLY, DEBUGGING Disassembly of section .text: @@ -33,488 +33,492 @@ Disassembly of section .text: #endif /* main program starts here */ int main(void) { - 7e00: 85 e0 ldi r24, 0x05 ; 5 - 7e02: 80 93 81 00 sts 0x0081, r24 + 7e00: 11 24 eor r1, r1 + + uint8_t ch; + #if LED_START_FLASHES > 0 // Set up Timer 1 for timeout counter TCCR1B = _BV(CS12) | _BV(CS10); // div 1024 + 7e02: 85 e0 ldi r24, 0x05 ; 5 + 7e04: 80 93 81 00 sts 0x0081, r24 #endif #ifndef SOFT_UART UCSR0A = _BV(U2X0); //Double speed mode USART0 - 7e06: 82 e0 ldi r24, 0x02 ; 2 - 7e08: 80 93 c0 00 sts 0x00C0, r24 + 7e08: 82 e0 ldi r24, 0x02 ; 2 + 7e0a: 80 93 c0 00 sts 0x00C0, r24 UCSR0B = _BV(RXEN0) | _BV(TXEN0); - 7e0c: 88 e1 ldi r24, 0x18 ; 24 - 7e0e: 80 93 c1 00 sts 0x00C1, r24 + 7e0e: 88 e1 ldi r24, 0x18 ; 24 + 7e10: 80 93 c1 00 sts 0x00C1, r24 UCSR0C = _BV(UCSZ00) | _BV(UCSZ01); - 7e12: 86 e0 ldi r24, 0x06 ; 6 - 7e14: 80 93 c2 00 sts 0x00C2, r24 + 7e14: 86 e0 ldi r24, 0x06 ; 6 + 7e16: 80 93 c2 00 sts 0x00C2, r24 UBRR0L = (uint8_t)( (F_CPU + BAUD_RATE * 4L) / (BAUD_RATE * 8L) - 1 ); - 7e18: 80 e1 ldi r24, 0x10 ; 16 - 7e1a: 80 93 c4 00 sts 0x00C4, r24 + 7e1a: 80 e1 ldi r24, 0x10 ; 16 + 7e1c: 80 93 c4 00 sts 0x00C4, r24 #endif // Adaboot no-wait mod ch = MCUSR; - 7e1e: 84 b7 in r24, 0x34 ; 52 + 7e20: 84 b7 in r24, 0x34 ; 52 MCUSR = 0; - 7e20: 14 be out 0x34, r1 ; 52 + 7e22: 14 be out 0x34, r1 ; 52 if (!(ch & _BV(EXTRF))) appStart(); - 7e22: 81 ff sbrs r24, 1 - 7e24: d0 d0 rcall .+416 ; 0x7fc6 + 7e24: 81 ff sbrs r24, 1 + 7e26: d0 d0 rcall .+416 ; 0x7fc8 // Set up watchdog to trigger after 500ms watchdogConfig(WATCHDOG_500MS); - 7e26: 8d e0 ldi r24, 0x0D ; 13 - 7e28: c8 d0 rcall .+400 ; 0x7fba + 7e28: 8d e0 ldi r24, 0x0D ; 13 + 7e2a: c8 d0 rcall .+400 ; 0x7fbc /* Set LED pin as output */ LED_DDR |= _BV(LED); - 7e2a: 25 9a sbi 0x04, 5 ; 4 - 7e2c: 86 e0 ldi r24, 0x06 ; 6 + 7e2c: 25 9a sbi 0x04, 5 ; 4 + 7e2e: 86 e0 ldi r24, 0x06 ; 6 } #if LED_START_FLASHES > 0 void flash_led(uint8_t count) { do { TCNT1 = -(F_CPU/(1024*16)); - 7e2e: 20 e3 ldi r18, 0x30 ; 48 - 7e30: 3c ef ldi r19, 0xFC ; 252 + 7e30: 20 e3 ldi r18, 0x30 ; 48 + 7e32: 3c ef ldi r19, 0xFC ; 252 TIFR1 = _BV(TOV1); - 7e32: 91 e0 ldi r25, 0x01 ; 1 + 7e34: 91 e0 ldi r25, 0x01 ; 1 } #if LED_START_FLASHES > 0 void flash_led(uint8_t count) { do { TCNT1 = -(F_CPU/(1024*16)); - 7e34: 30 93 85 00 sts 0x0085, r19 - 7e38: 20 93 84 00 sts 0x0084, r18 + 7e36: 30 93 85 00 sts 0x0085, r19 + 7e3a: 20 93 84 00 sts 0x0084, r18 TIFR1 = _BV(TOV1); - 7e3c: 96 bb out 0x16, r25 ; 22 + 7e3e: 96 bb out 0x16, r25 ; 22 while(!(TIFR1 & _BV(TOV1))); - 7e3e: b0 9b sbis 0x16, 0 ; 22 - 7e40: fe cf rjmp .-4 ; 0x7e3e + 7e40: b0 9b sbis 0x16, 0 ; 22 + 7e42: fe cf rjmp .-4 ; 0x7e40 LED_PIN |= _BV(LED); - 7e42: 1d 9a sbi 0x03, 5 ; 3 + 7e44: 1d 9a sbi 0x03, 5 ; 3 return getch(); } // Watchdog functions. These are only safe with interrupts turned off. void watchdogReset() { __asm__ __volatile__ ( - 7e44: a8 95 wdr + 7e46: a8 95 wdr TCNT1 = -(F_CPU/(1024*16)); TIFR1 = _BV(TOV1); while(!(TIFR1 & _BV(TOV1))); LED_PIN |= _BV(LED); watchdogReset(); } while (--count); - 7e46: 81 50 subi r24, 0x01 ; 1 - 7e48: a9 f7 brne .-22 ; 0x7e34 + 7e48: 81 50 subi r24, 0x01 ; 1 + 7e4a: a9 f7 brne .-22 ; 0x7e36 /* get character from UART */ ch = getch(); if(ch == STK_GET_PARAMETER) { // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy getNch(1); - 7e4a: dd 24 eor r13, r13 - 7e4c: d3 94 inc r13 + 7e4c: dd 24 eor r13, r13 + 7e4e: d3 94 inc r13 boot_page_fill((uint16_t)(void*)addrPtr,a); addrPtr += 2; } while (--ch); // Write from programming buffer boot_page_write((uint16_t)(void*)address); - 7e4e: a5 e0 ldi r26, 0x05 ; 5 - 7e50: ea 2e mov r14, r26 + 7e50: a5 e0 ldi r26, 0x05 ; 5 + 7e52: ea 2e mov r14, r26 boot_spm_busy_wait(); #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); - 7e52: f1 e1 ldi r31, 0x11 ; 17 - 7e54: ff 2e mov r15, r31 + 7e54: f1 e1 ldi r31, 0x11 ; 17 + 7e56: ff 2e mov r15, r31 #endif /* Forever loop */ for (;;) { /* get character from UART */ ch = getch(); - 7e56: a4 d0 rcall .+328 ; 0x7fa0 + 7e58: a4 d0 rcall .+328 ; 0x7fa2 if(ch == STK_GET_PARAMETER) { - 7e58: 81 34 cpi r24, 0x41 ; 65 - 7e5a: 21 f4 brne .+8 ; 0x7e64 + 7e5a: 81 34 cpi r24, 0x41 ; 65 + 7e5c: 21 f4 brne .+8 ; 0x7e66 // GET PARAMETER returns a generic 0x03 reply - enough to keep Avrdude happy getNch(1); - 7e5c: 81 e0 ldi r24, 0x01 ; 1 - 7e5e: be d0 rcall .+380 ; 0x7fdc + 7e5e: 81 e0 ldi r24, 0x01 ; 1 + 7e60: be d0 rcall .+380 ; 0x7fde putch(0x03); - 7e60: 83 e0 ldi r24, 0x03 ; 3 - 7e62: 24 c0 rjmp .+72 ; 0x7eac + 7e62: 83 e0 ldi r24, 0x03 ; 3 + 7e64: 24 c0 rjmp .+72 ; 0x7eae } else if(ch == STK_SET_DEVICE) { - 7e64: 82 34 cpi r24, 0x42 ; 66 - 7e66: 11 f4 brne .+4 ; 0x7e6c + 7e66: 82 34 cpi r24, 0x42 ; 66 + 7e68: 11 f4 brne .+4 ; 0x7e6e // SET DEVICE is ignored getNch(20); - 7e68: 84 e1 ldi r24, 0x14 ; 20 - 7e6a: 03 c0 rjmp .+6 ; 0x7e72 + 7e6a: 84 e1 ldi r24, 0x14 ; 20 + 7e6c: 03 c0 rjmp .+6 ; 0x7e74 } else if(ch == STK_SET_DEVICE_EXT) { - 7e6c: 85 34 cpi r24, 0x45 ; 69 - 7e6e: 19 f4 brne .+6 ; 0x7e76 + 7e6e: 85 34 cpi r24, 0x45 ; 69 + 7e70: 19 f4 brne .+6 ; 0x7e78 // SET DEVICE EXT is ignored getNch(5); - 7e70: 85 e0 ldi r24, 0x05 ; 5 - 7e72: b4 d0 rcall .+360 ; 0x7fdc - 7e74: 8a c0 rjmp .+276 ; 0x7f8a + 7e72: 85 e0 ldi r24, 0x05 ; 5 + 7e74: b4 d0 rcall .+360 ; 0x7fde + 7e76: 8a c0 rjmp .+276 ; 0x7f8c } else if(ch == STK_LOAD_ADDRESS) { - 7e76: 85 35 cpi r24, 0x55 ; 85 - 7e78: a1 f4 brne .+40 ; 0x7ea2 + 7e78: 85 35 cpi r24, 0x55 ; 85 + 7e7a: a1 f4 brne .+40 ; 0x7ea4 // LOAD ADDRESS address = getch(); - 7e7a: 92 d0 rcall .+292 ; 0x7fa0 - 7e7c: 08 2f mov r16, r24 - 7e7e: 10 e0 ldi r17, 0x00 ; 0 - 7e80: 10 93 01 02 sts 0x0201, r17 - 7e84: 00 93 00 02 sts 0x0200, r16 + 7e7c: 92 d0 rcall .+292 ; 0x7fa2 + 7e7e: 08 2f mov r16, r24 + 7e80: 10 e0 ldi r17, 0x00 ; 0 + 7e82: 10 93 01 02 sts 0x0201, r17 + 7e86: 00 93 00 02 sts 0x0200, r16 address = (address & 0xff) | (getch() << 8); - 7e88: 8b d0 rcall .+278 ; 0x7fa0 - 7e8a: 90 e0 ldi r25, 0x00 ; 0 - 7e8c: 98 2f mov r25, r24 - 7e8e: 88 27 eor r24, r24 - 7e90: 80 2b or r24, r16 - 7e92: 91 2b or r25, r17 + 7e8a: 8b d0 rcall .+278 ; 0x7fa2 + 7e8c: 90 e0 ldi r25, 0x00 ; 0 + 7e8e: 98 2f mov r25, r24 + 7e90: 88 27 eor r24, r24 + 7e92: 80 2b or r24, r16 + 7e94: 91 2b or r25, r17 address += address; // Convert from word address to byte address - 7e94: 88 0f add r24, r24 - 7e96: 99 1f adc r25, r25 - 7e98: 90 93 01 02 sts 0x0201, r25 - 7e9c: 80 93 00 02 sts 0x0200, r24 - 7ea0: 73 c0 rjmp .+230 ; 0x7f88 + 7e96: 88 0f add r24, r24 + 7e98: 99 1f adc r25, r25 + 7e9a: 90 93 01 02 sts 0x0201, r25 + 7e9e: 80 93 00 02 sts 0x0200, r24 + 7ea2: 73 c0 rjmp .+230 ; 0x7f8a verifySpace(); } else if(ch == STK_UNIVERSAL) { - 7ea2: 86 35 cpi r24, 0x56 ; 86 - 7ea4: 29 f4 brne .+10 ; 0x7eb0 + 7ea4: 86 35 cpi r24, 0x56 ; 86 + 7ea6: 29 f4 brne .+10 ; 0x7eb2 // UNIVERSAL command is ignored getNch(4); - 7ea6: 84 e0 ldi r24, 0x04 ; 4 - 7ea8: 99 d0 rcall .+306 ; 0x7fdc + 7ea8: 84 e0 ldi r24, 0x04 ; 4 + 7eaa: 99 d0 rcall .+306 ; 0x7fde putch(0x00); - 7eaa: 80 e0 ldi r24, 0x00 ; 0 - 7eac: 71 d0 rcall .+226 ; 0x7f90 - 7eae: 6d c0 rjmp .+218 ; 0x7f8a + 7eac: 80 e0 ldi r24, 0x00 ; 0 + 7eae: 71 d0 rcall .+226 ; 0x7f92 + 7eb0: 6d c0 rjmp .+218 ; 0x7f8c } /* Write memory, length is big endian and is in bytes */ else if(ch == STK_PROG_PAGE) { - 7eb0: 84 36 cpi r24, 0x64 ; 100 - 7eb2: 09 f0 breq .+2 ; 0x7eb6 - 7eb4: 43 c0 rjmp .+134 ; 0x7f3c + 7eb2: 84 36 cpi r24, 0x64 ; 100 + 7eb4: 09 f0 breq .+2 ; 0x7eb8 + 7eb6: 43 c0 rjmp .+134 ; 0x7f3e // PROGRAM PAGE - we support flash programming only, not EEPROM uint8_t *bufPtr; uint16_t addrPtr; getLen(); - 7eb6: 7c d0 rcall .+248 ; 0x7fb0 + 7eb8: 7c d0 rcall .+248 ; 0x7fb2 // Immediately start page erase - this will 4.5ms boot_page_erase((uint16_t)(void*)address); - 7eb8: e0 91 00 02 lds r30, 0x0200 - 7ebc: f0 91 01 02 lds r31, 0x0201 - 7ec0: 83 e0 ldi r24, 0x03 ; 3 - 7ec2: 80 93 57 00 sts 0x0057, r24 - 7ec6: e8 95 spm - 7ec8: c0 e0 ldi r28, 0x00 ; 0 - 7eca: d1 e0 ldi r29, 0x01 ; 1 + 7eba: e0 91 00 02 lds r30, 0x0200 + 7ebe: f0 91 01 02 lds r31, 0x0201 + 7ec2: 83 e0 ldi r24, 0x03 ; 3 + 7ec4: 80 93 57 00 sts 0x0057, r24 + 7ec8: e8 95 spm + 7eca: c0 e0 ldi r28, 0x00 ; 0 + 7ecc: d1 e0 ldi r29, 0x01 ; 1 // While that is going on, read in page contents bufPtr = buff; do *bufPtr++ = getch(); - 7ecc: 69 d0 rcall .+210 ; 0x7fa0 - 7ece: 89 93 st Y+, r24 + 7ece: 69 d0 rcall .+210 ; 0x7fa2 + 7ed0: 89 93 st Y+, r24 while (--length); - 7ed0: 80 91 02 02 lds r24, 0x0202 - 7ed4: 81 50 subi r24, 0x01 ; 1 - 7ed6: 80 93 02 02 sts 0x0202, r24 - 7eda: 88 23 and r24, r24 - 7edc: b9 f7 brne .-18 ; 0x7ecc + 7ed2: 80 91 02 02 lds r24, 0x0202 + 7ed6: 81 50 subi r24, 0x01 ; 1 + 7ed8: 80 93 02 02 sts 0x0202, r24 + 7edc: 88 23 and r24, r24 + 7ede: b9 f7 brne .-18 ; 0x7ece // Read command terminator, start reply verifySpace(); - 7ede: 78 d0 rcall .+240 ; 0x7fd0 + 7ee0: 78 d0 rcall .+240 ; 0x7fd2 // If only a partial page is to be programmed, the erase might not be complete. // So check that here boot_spm_busy_wait(); - 7ee0: 07 b6 in r0, 0x37 ; 55 - 7ee2: 00 fc sbrc r0, 0 - 7ee4: fd cf rjmp .-6 ; 0x7ee0 + 7ee2: 07 b6 in r0, 0x37 ; 55 + 7ee4: 00 fc sbrc r0, 0 + 7ee6: fd cf rjmp .-6 ; 0x7ee2 } #endif // Copy buffer into programming buffer bufPtr = buff; addrPtr = (uint16_t)(void*)address; - 7ee6: 40 91 00 02 lds r20, 0x0200 - 7eea: 50 91 01 02 lds r21, 0x0201 - 7eee: a0 e0 ldi r26, 0x00 ; 0 - 7ef0: b1 e0 ldi r27, 0x01 ; 1 + 7ee8: 40 91 00 02 lds r20, 0x0200 + 7eec: 50 91 01 02 lds r21, 0x0201 + 7ef0: a0 e0 ldi r26, 0x00 ; 0 + 7ef2: b1 e0 ldi r27, 0x01 ; 1 ch = SPM_PAGESIZE / 2; do { uint16_t a; a = *bufPtr++; - 7ef2: 2c 91 ld r18, X - 7ef4: 30 e0 ldi r19, 0x00 ; 0 + 7ef4: 2c 91 ld r18, X + 7ef6: 30 e0 ldi r19, 0x00 ; 0 a |= (*bufPtr++) << 8; - 7ef6: 11 96 adiw r26, 0x01 ; 1 - 7ef8: 8c 91 ld r24, X - 7efa: 11 97 sbiw r26, 0x01 ; 1 - 7efc: 90 e0 ldi r25, 0x00 ; 0 - 7efe: 98 2f mov r25, r24 - 7f00: 88 27 eor r24, r24 - 7f02: 82 2b or r24, r18 - 7f04: 93 2b or r25, r19 + 7ef8: 11 96 adiw r26, 0x01 ; 1 + 7efa: 8c 91 ld r24, X + 7efc: 11 97 sbiw r26, 0x01 ; 1 + 7efe: 90 e0 ldi r25, 0x00 ; 0 + 7f00: 98 2f mov r25, r24 + 7f02: 88 27 eor r24, r24 + 7f04: 82 2b or r24, r18 + 7f06: 93 2b or r25, r19 #ifdef VIRTUAL_BOOT_PARTITION #define rstVect (*(uint16_t*)(0x204)) #define wdtVect (*(uint16_t*)(0x206)) #endif /* main program starts here */ int main(void) { - 7f06: 12 96 adiw r26, 0x02 ; 2 + 7f08: 12 96 adiw r26, 0x02 ; 2 ch = SPM_PAGESIZE / 2; do { uint16_t a; a = *bufPtr++; a |= (*bufPtr++) << 8; boot_page_fill((uint16_t)(void*)addrPtr,a); - 7f08: fa 01 movw r30, r20 - 7f0a: 0c 01 movw r0, r24 - 7f0c: d0 92 57 00 sts 0x0057, r13 - 7f10: e8 95 spm - 7f12: 11 24 eor r1, r1 + 7f0a: fa 01 movw r30, r20 + 7f0c: 0c 01 movw r0, r24 + 7f0e: d0 92 57 00 sts 0x0057, r13 + 7f12: e8 95 spm + 7f14: 11 24 eor r1, r1 addrPtr += 2; - 7f14: 4e 5f subi r20, 0xFE ; 254 - 7f16: 5f 4f sbci r21, 0xFF ; 255 + 7f16: 4e 5f subi r20, 0xFE ; 254 + 7f18: 5f 4f sbci r21, 0xFF ; 255 } while (--ch); - 7f18: f1 e0 ldi r31, 0x01 ; 1 - 7f1a: a0 38 cpi r26, 0x80 ; 128 - 7f1c: bf 07 cpc r27, r31 - 7f1e: 49 f7 brne .-46 ; 0x7ef2 + 7f1a: f1 e0 ldi r31, 0x01 ; 1 + 7f1c: a0 38 cpi r26, 0x80 ; 128 + 7f1e: bf 07 cpc r27, r31 + 7f20: 49 f7 brne .-46 ; 0x7ef4 // Write from programming buffer boot_page_write((uint16_t)(void*)address); - 7f20: e0 91 00 02 lds r30, 0x0200 - 7f24: f0 91 01 02 lds r31, 0x0201 - 7f28: e0 92 57 00 sts 0x0057, r14 - 7f2c: e8 95 spm + 7f22: e0 91 00 02 lds r30, 0x0200 + 7f26: f0 91 01 02 lds r31, 0x0201 + 7f2a: e0 92 57 00 sts 0x0057, r14 + 7f2e: e8 95 spm boot_spm_busy_wait(); - 7f2e: 07 b6 in r0, 0x37 ; 55 - 7f30: 00 fc sbrc r0, 0 - 7f32: fd cf rjmp .-6 ; 0x7f2e + 7f30: 07 b6 in r0, 0x37 ; 55 + 7f32: 00 fc sbrc r0, 0 + 7f34: fd cf rjmp .-6 ; 0x7f30 #if defined(RWWSRE) // Reenable read access to flash boot_rww_enable(); - 7f34: f0 92 57 00 sts 0x0057, r15 - 7f38: e8 95 spm - 7f3a: 27 c0 rjmp .+78 ; 0x7f8a + 7f36: f0 92 57 00 sts 0x0057, r15 + 7f3a: e8 95 spm + 7f3c: 27 c0 rjmp .+78 ; 0x7f8c #endif } /* Read memory block mode, length is big endian. */ else if(ch == STK_READ_PAGE) { - 7f3c: 84 37 cpi r24, 0x74 ; 116 - 7f3e: b9 f4 brne .+46 ; 0x7f6e + 7f3e: 84 37 cpi r24, 0x74 ; 116 + 7f40: b9 f4 brne .+46 ; 0x7f70 // READ PAGE - we only read flash getLen(); - 7f40: 37 d0 rcall .+110 ; 0x7fb0 + 7f42: 37 d0 rcall .+110 ; 0x7fb2 verifySpace(); - 7f42: 46 d0 rcall .+140 ; 0x7fd0 + 7f44: 46 d0 rcall .+140 ; 0x7fd2 else ch = pgm_read_byte_near(address); address++; putch(ch); } while (--length); #else do putch(pgm_read_byte_near(address++)); - 7f44: e0 91 00 02 lds r30, 0x0200 - 7f48: f0 91 01 02 lds r31, 0x0201 - 7f4c: 31 96 adiw r30, 0x01 ; 1 - 7f4e: f0 93 01 02 sts 0x0201, r31 - 7f52: e0 93 00 02 sts 0x0200, r30 - 7f56: 31 97 sbiw r30, 0x01 ; 1 - 7f58: e4 91 lpm r30, Z+ - 7f5a: 8e 2f mov r24, r30 - 7f5c: 19 d0 rcall .+50 ; 0x7f90 + 7f46: e0 91 00 02 lds r30, 0x0200 + 7f4a: f0 91 01 02 lds r31, 0x0201 + 7f4e: 31 96 adiw r30, 0x01 ; 1 + 7f50: f0 93 01 02 sts 0x0201, r31 + 7f54: e0 93 00 02 sts 0x0200, r30 + 7f58: 31 97 sbiw r30, 0x01 ; 1 + 7f5a: e4 91 lpm r30, Z+ + 7f5c: 8e 2f mov r24, r30 + 7f5e: 19 d0 rcall .+50 ; 0x7f92 while (--length); - 7f5e: 80 91 02 02 lds r24, 0x0202 - 7f62: 81 50 subi r24, 0x01 ; 1 - 7f64: 80 93 02 02 sts 0x0202, r24 - 7f68: 88 23 and r24, r24 - 7f6a: 61 f7 brne .-40 ; 0x7f44 - 7f6c: 0e c0 rjmp .+28 ; 0x7f8a + 7f60: 80 91 02 02 lds r24, 0x0202 + 7f64: 81 50 subi r24, 0x01 ; 1 + 7f66: 80 93 02 02 sts 0x0202, r24 + 7f6a: 88 23 and r24, r24 + 7f6c: 61 f7 brne .-40 ; 0x7f46 + 7f6e: 0e c0 rjmp .+28 ; 0x7f8c #endif } /* Get device signature bytes */ else if(ch == STK_READ_SIGN) { - 7f6e: 85 37 cpi r24, 0x75 ; 117 - 7f70: 39 f4 brne .+14 ; 0x7f80 + 7f70: 85 37 cpi r24, 0x75 ; 117 + 7f72: 39 f4 brne .+14 ; 0x7f82 // READ SIGN - return what Avrdude wants to hear verifySpace(); - 7f72: 2e d0 rcall .+92 ; 0x7fd0 + 7f74: 2e d0 rcall .+92 ; 0x7fd2 putch(SIGNATURE_0); - 7f74: 8e e1 ldi r24, 0x1E ; 30 - 7f76: 0c d0 rcall .+24 ; 0x7f90 + 7f76: 8e e1 ldi r24, 0x1E ; 30 + 7f78: 0c d0 rcall .+24 ; 0x7f92 putch(SIGNATURE_1); - 7f78: 85 e9 ldi r24, 0x95 ; 149 - 7f7a: 0a d0 rcall .+20 ; 0x7f90 + 7f7a: 85 e9 ldi r24, 0x95 ; 149 + 7f7c: 0a d0 rcall .+20 ; 0x7f92 putch(SIGNATURE_2); - 7f7c: 8f e0 ldi r24, 0x0F ; 15 - 7f7e: 96 cf rjmp .-212 ; 0x7eac + 7f7e: 8f e0 ldi r24, 0x0F ; 15 + 7f80: 96 cf rjmp .-212 ; 0x7eae } else if (ch == 'Q') { - 7f80: 81 35 cpi r24, 0x51 ; 81 - 7f82: 11 f4 brne .+4 ; 0x7f88 + 7f82: 81 35 cpi r24, 0x51 ; 81 + 7f84: 11 f4 brne .+4 ; 0x7f8a // Adaboot no-wait mod watchdogConfig(WATCHDOG_16MS); - 7f84: 88 e0 ldi r24, 0x08 ; 8 - 7f86: 19 d0 rcall .+50 ; 0x7fba + 7f86: 88 e0 ldi r24, 0x08 ; 8 + 7f88: 19 d0 rcall .+50 ; 0x7fbc verifySpace(); } else { // This covers the response to commands like STK_ENTER_PROGMODE verifySpace(); - 7f88: 23 d0 rcall .+70 ; 0x7fd0 + 7f8a: 23 d0 rcall .+70 ; 0x7fd2 } putch(STK_OK); - 7f8a: 80 e1 ldi r24, 0x10 ; 16 - 7f8c: 01 d0 rcall .+2 ; 0x7f90 - 7f8e: 63 cf rjmp .-314 ; 0x7e56 + 7f8c: 80 e1 ldi r24, 0x10 ; 16 + 7f8e: 01 d0 rcall .+2 ; 0x7f92 + 7f90: 63 cf rjmp .-314 ; 0x7e58 -00007f90 : +00007f92 : } } void putch(char ch) { - 7f90: 98 2f mov r25, r24 + 7f92: 98 2f mov r25, r24 #ifndef SOFT_UART while (!(UCSR0A & _BV(UDRE0))); - 7f92: 80 91 c0 00 lds r24, 0x00C0 - 7f96: 85 ff sbrs r24, 5 - 7f98: fc cf rjmp .-8 ; 0x7f92 + 7f94: 80 91 c0 00 lds r24, 0x00C0 + 7f98: 85 ff sbrs r24, 5 + 7f9a: fc cf rjmp .-8 ; 0x7f94 UDR0 = ch; - 7f9a: 90 93 c6 00 sts 0x00C6, r25 + 7f9c: 90 93 c6 00 sts 0x00C6, r25 [uartBit] "I" (UART_TX_BIT) : "r25" ); #endif } - 7f9e: 08 95 ret + 7fa0: 08 95 ret -00007fa0 : +00007fa2 : return getch(); } // Watchdog functions. These are only safe with interrupts turned off. void watchdogReset() { __asm__ __volatile__ ( - 7fa0: a8 95 wdr + 7fa2: a8 95 wdr [uartBit] "I" (UART_RX_BIT) : "r25" ); #else while(!(UCSR0A & _BV(RXC0))); - 7fa2: 80 91 c0 00 lds r24, 0x00C0 - 7fa6: 87 ff sbrs r24, 7 - 7fa8: fc cf rjmp .-8 ; 0x7fa2 + 7fa4: 80 91 c0 00 lds r24, 0x00C0 + 7fa8: 87 ff sbrs r24, 7 + 7faa: fc cf rjmp .-8 ; 0x7fa4 ch = UDR0; - 7faa: 80 91 c6 00 lds r24, 0x00C6 + 7fac: 80 91 c6 00 lds r24, 0x00C6 #ifdef LED_DATA_FLASH LED_PIN |= _BV(LED); #endif return ch; } - 7fae: 08 95 ret + 7fb0: 08 95 ret -00007fb0 : +00007fb2 : } while (--count); } #endif uint8_t getLen() { getch(); - 7fb0: f7 df rcall .-18 ; 0x7fa0 + 7fb2: f7 df rcall .-18 ; 0x7fa2 length = getch(); - 7fb2: f6 df rcall .-20 ; 0x7fa0 - 7fb4: 80 93 02 02 sts 0x0202, r24 + 7fb4: f6 df rcall .-20 ; 0x7fa2 + 7fb6: 80 93 02 02 sts 0x0202, r24 return getch(); } - 7fb8: f3 cf rjmp .-26 ; 0x7fa0 + 7fba: f3 cf rjmp .-26 ; 0x7fa2 -00007fba : +00007fbc : "wdr\n" ); } void watchdogConfig(uint8_t x) { WDTCSR = _BV(WDCE) | _BV(WDE); - 7fba: e0 e6 ldi r30, 0x60 ; 96 - 7fbc: f0 e0 ldi r31, 0x00 ; 0 - 7fbe: 98 e1 ldi r25, 0x18 ; 24 - 7fc0: 90 83 st Z, r25 + 7fbc: e0 e6 ldi r30, 0x60 ; 96 + 7fbe: f0 e0 ldi r31, 0x00 ; 0 + 7fc0: 98 e1 ldi r25, 0x18 ; 24 + 7fc2: 90 83 st Z, r25 WDTCSR = x; - 7fc2: 80 83 st Z, r24 + 7fc4: 80 83 st Z, r24 } - 7fc4: 08 95 ret + 7fc6: 08 95 ret -00007fc6 : +00007fc8 : void appStart() { watchdogConfig(WATCHDOG_OFF); - 7fc6: 80 e0 ldi r24, 0x00 ; 0 - 7fc8: f8 df rcall .-16 ; 0x7fba + 7fc8: 80 e0 ldi r24, 0x00 ; 0 + 7fca: f8 df rcall .-16 ; 0x7fbc __asm__ __volatile__ ( - 7fca: ee 27 eor r30, r30 - 7fcc: ff 27 eor r31, r31 - 7fce: 09 94 ijmp + 7fcc: ee 27 eor r30, r30 + 7fce: ff 27 eor r31, r31 + 7fd0: 09 94 ijmp -00007fd0 : +00007fd2 : do getch(); while (--count); verifySpace(); } void verifySpace() { if (getch() != CRC_EOP) appStart(); - 7fd0: e7 df rcall .-50 ; 0x7fa0 - 7fd2: 80 32 cpi r24, 0x20 ; 32 - 7fd4: 09 f0 breq .+2 ; 0x7fd8 - 7fd6: f7 df rcall .-18 ; 0x7fc6 + 7fd2: e7 df rcall .-50 ; 0x7fa2 + 7fd4: 80 32 cpi r24, 0x20 ; 32 + 7fd6: 09 f0 breq .+2 ; 0x7fda + 7fd8: f7 df rcall .-18 ; 0x7fc8 putch(STK_INSYNC); - 7fd8: 84 e1 ldi r24, 0x14 ; 20 + 7fda: 84 e1 ldi r24, 0x14 ; 20 } - 7fda: da cf rjmp .-76 ; 0x7f90 + 7fdc: da cf rjmp .-76 ; 0x7f92 ::[count] "M" (UART_B_VALUE) ); } #endif void getNch(uint8_t count) { - 7fdc: 1f 93 push r17 - 7fde: 18 2f mov r17, r24 + 7fde: 1f 93 push r17 + 7fe0: 18 2f mov r17, r24 -00007fe0 : +00007fe2 : do getch(); while (--count); - 7fe0: df df rcall .-66 ; 0x7fa0 - 7fe2: 11 50 subi r17, 0x01 ; 1 - 7fe4: e9 f7 brne .-6 ; 0x7fe0 + 7fe2: df df rcall .-66 ; 0x7fa2 + 7fe4: 11 50 subi r17, 0x01 ; 1 + 7fe6: e9 f7 brne .-6 ; 0x7fe2 verifySpace(); - 7fe6: f4 df rcall .-24 ; 0x7fd0 + 7fe8: f4 df rcall .-24 ; 0x7fd2 } - 7fe8: 1f 91 pop r17 - 7fea: 08 95 ret + 7fea: 1f 91 pop r17 + 7fec: 08 95 ret From 3696fa044687542ee6b4a9bc488348e184ee3ae2 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Feb 2011 17:53:24 -0500 Subject: [PATCH 02/54] Optimized digitalWrite(), etc. from Alvaro Lopez. --- cores/arduino/pins_arduino.h | 452 ++++++++++++++++++++++++++++++++- cores/arduino/wiring.h | 73 +++++- cores/arduino/wiring_digital.c | 33 ++- 3 files changed, 537 insertions(+), 21 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index bc931c5..63f4257 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -49,6 +49,10 @@ #define TIMER5B 15 #define TIMER5C 16 +#ifndef INLINED +#define INLINED static __attribute__((always_inline)) inline +#endif + #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) const static uint8_t SS = 53; const static uint8_t MOSI = 51; @@ -72,17 +76,447 @@ extern const uint8_t PROGMEM digital_pin_to_port_PGM[]; extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[]; extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; +// inlined versions of lookup-table-based pin mappings. Don't use directly. + +// Don't use PA, so on, might clash with sketch + +#define PORT_INDEX_PA 1 +#define PORT_INDEX_PB 2 +#define PORT_INDEX_PC 3 +#define PORT_INDEX_PD 4 +#define PORT_INDEX_PE 5 +#define PORT_INDEX_PF 6 +#define PORT_INDEX_PG 7 +#define PORT_INDEX_PH 8 +#define PORT_INDEX_PJ 10 +#define PORT_INDEX_PK 11 +#define PORT_INDEX_PL 12 + +__attribute__((error("Invalid pin specified. This pin does not map to any I/O port"))) static void invalidPinSpecified(void); + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) +{ + switch (port_index) { + case 1: return &DDRA; + case 2: return &DDRB; + case 3: return &DDRC; + case 4: return &DDRD; + case 5: return &DDRE; + case 6: return &DDRF; + case 7: return &DDRG; + case 8: return &DDRH; + case 10: return &DDRJ; + case 11: return &DDRK; + case 12: return &DDRL; + default: return NOT_A_PORT; + } +} + +INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index) +{ + switch (port_index) { + case 1: return &PORTA; + case 2: return &PORTB; + case 3: return &PORTC; + case 4: return &PORTD; + case 5: return &PORTE; + case 6: return &PORTF; + case 7: return &PORTG; + case 8: return &PORTH; + case 10: return &PORTJ; + case 11: return &PORTK; + case 12: return &PORTL; + default: return NOT_A_PORT; + } +} + +INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index) +{ + switch (port_index) { + case 1: return &PINA; + case 2: return &PINB; + case 3: return &PINC; + case 4: return &PIND; + case 5: return &PINE; + case 6: return &PINF; + case 7: return &PING; + case 8: return &PINH; + case 10: return &PINJ; + case 11: return &PINK; + case 12: return &PINL; + default: return NOT_A_PIN; + } +}; + +INLINED uint8_t inlined_digitalPinToPort(uint8_t pin) +{ + switch (pin) { + case 0: // PE 0 ** 0 ** USART0_RX + case 1: // PE 1 ** 1 ** USART0_TX + case 2: // PE 4 ** 2 ** PWM2 + case 3: // PE 5 ** 3 ** PWM3 + return PORT_INDEX_PE; + + case 4: // PG 5 ** 4 ** PWM4 + return PORT_INDEX_PG; + + case 5: // PE 3 ** 5 ** PWM5 + return PORT_INDEX_PE; + + case 6: // PH 3 ** 6 ** PWM6 + case 7: // PH 4 ** 7 ** PWM7 + case 8: // PH 5 ** 8 ** PWM8 + case 9: // PH 6 ** 9 ** PWM9 + return PORT_INDEX_PH; + + case 10: // PB 4 ** 10 ** PWM10 + case 11: // PB 5 ** 11 ** PWM11 + case 12: // PB 6 ** 12 ** PWM12 + case 13: // PB 7 ** 13 ** PWM13 + return PORT_INDEX_PB; + + case 14: // PJ 1 ** 14 ** USART3_TX + case 15: // PJ 0 ** 15 ** USART3_RX + return PORT_INDEX_PJ; + + case 16: // PH 1 ** 16 ** USART2_TX + case 17: // PH 0 ** 17 ** USART2_RX + return PORT_INDEX_PH; + + case 18: // PD 3 ** 18 ** USART1_TX + case 19: // PD 2 ** 19 ** USART1_RX + case 20: // PD 1 ** 20 ** I2C_SDA + case 21: // PD 0 ** 21 ** I2C_SCL + return PORT_INDEX_PD; + + case 22: // PA 0 ** 22 ** D22 + case 23: // PA 1 ** 23 ** D23 + case 24: // PA 2 ** 24 ** D24 + case 25: // PA 3 ** 25 ** D25 + case 26: // PA 4 ** 26 ** D26 + case 27: // PA 5 ** 27 ** D27 + case 28: // PA 6 ** 28 ** D28 + case 29: // PA 7 ** 29 ** D29 + return PORT_INDEX_PA; + + case 30: // PC 7 ** 30 ** D30 + case 31: // PC 6 ** 31 ** D31 + case 32: // PC 5 ** 32 ** D32 + case 33: // PC 4 ** 33 ** D33 + case 34: // PC 3 ** 34 ** D34 + case 35: // PC 2 ** 35 ** D35 + case 36: // PC 1 ** 36 ** D36 + case 37: // PC 0 ** 37 ** D37 + return PORT_INDEX_PC; + + case 38: // PD 7 ** 38 ** D38 + return PORT_INDEX_PD; + + case 39: // PG 2 ** 39 ** D39 + case 40: // PG 1 ** 40 ** D40 + case 41: // PG 0 ** 41 ** D41 + return PORT_INDEX_PG; + + case 42: // PL 7 ** 42 ** D42 + case 43: // PL 6 ** 43 ** D43 + case 44: // PL 5 ** 44 ** D44 + case 45: // PL 4 ** 45 ** D45 + case 46: // PL 3 ** 46 ** D46 + case 47: // PL 2 ** 47 ** D47 + case 48: // PL 1 ** 48 ** D48 + case 49: // PL 0 ** 49 ** D49 + return PORT_INDEX_PL; + + case 50: // PB 3 ** 50 ** SPI_MISO + case 51: // PB 2 ** 51 ** SPI_MOSI + case 52: // PB 1 ** 52 ** SPI_SCK + case 53: // PB 0 ** 53 ** SPI_SS + return PORT_INDEX_PB; + + case 54: // PF 0 ** 54 ** A0 + case 55: // PF 1 ** 55 ** A1 + case 56: // PF 2 ** 56 ** A2 + case 57: // PF 3 ** 57 ** A3 + case 58: // PF 4 ** 58 ** A4 + case 59: // PF 5 ** 59 ** A5 + case 60: // PF 6 ** 60 ** A6 + case 61: // PF 7 ** 61 ** A7 + return PORT_INDEX_PF; + + case 62: // PK 0 ** 62 ** A8 + case 63: // PK 1 ** 63 ** A9 + case 64: // PK 2 ** 64 ** A10 + case 65: // PK 3 ** 65 ** A11 + case 66: // PK 4 ** 66 ** A12 + case 67: // PK 5 ** 67 ** A13 + case 68: // PK 6 ** 68 ** A14 + case 69: // PK 7 ** 69 ** A15 + return PORT_INDEX_PK; + default: + invalidPinSpecified(); + } +} + +INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) +{ + switch(pin) { + case 0: return _BV( 0 ); // PE 0 ** 0 ** USART0_RX + case 1: return _BV( 1 ); // PE 1 ** 1 ** USART0_TX + case 2: return _BV( 4 ); // PE 4 ** 2 ** PWM2 + case 3: return _BV( 5 ); // PE 5 ** 3 ** PWM3 + case 4: return _BV( 5 ); // PG 5 ** 4 ** PWM4 + case 5: return _BV( 3 ); // PE 3 ** 5 ** PWM5 + case 6: return _BV( 3 ); // PH 3 ** 6 ** PWM6 + case 7: return _BV( 4 ); // PH 4 ** 7 ** PWM7 + case 8: return _BV( 5 ); // PH 5 ** 8 ** PWM8 + case 9: return _BV( 6 ); // PH 6 ** 9 ** PWM9 + case 10: return _BV( 4 ); // PB 4 ** 10 ** PWM10 + case 11: return _BV( 5 ); // PB 5 ** 11 ** PWM11 + case 12: return _BV( 6 ); // PB 6 ** 12 ** PWM12 + case 13: return _BV( 7 ); // PB 7 ** 13 ** PWM13 + case 14: return _BV( 1 ); // PJ 1 ** 14 ** USART3_TX + case 15: return _BV( 0 ); // PJ 0 ** 15 ** USART3_RX + case 16: return _BV( 1 ); // PH 1 ** 16 ** USART2_TX + case 17: return _BV( 0 ); // PH 0 ** 17 ** USART2_RX + case 18: return _BV( 3 ); // PD 3 ** 18 ** USART1_TX + case 19: return _BV( 2 ); // PD 2 ** 19 ** USART1_RX + case 20: return _BV( 1 ); // PD 1 ** 20 ** I2C_SDA + case 21: return _BV( 0 ); // PD 0 ** 21 ** I2C_SCL + case 22: return _BV( 0 ); // PA 0 ** 22 ** D22 + case 23: return _BV( 1 ); // PA 1 ** 23 ** D23 + case 24: return _BV( 2 ); // PA 2 ** 24 ** D24 + case 25: return _BV( 3 ); // PA 3 ** 25 ** D25 + case 26: return _BV( 4 ); // PA 4 ** 26 ** D26 + case 27: return _BV( 5 ); // PA 5 ** 27 ** D27 + case 28: return _BV( 6 ); // PA 6 ** 28 ** D28 + case 29: return _BV( 7 ); // PA 7 ** 29 ** D29 + case 30: return _BV( 7 ); // PC 7 ** 30 ** D30 + case 31: return _BV( 6 ); // PC 6 ** 31 ** D31 + case 32: return _BV( 5 ); // PC 5 ** 32 ** D32 + case 33: return _BV( 4 ); // PC 4 ** 33 ** D33 + case 34: return _BV( 3 ); // PC 3 ** 34 ** D34 + case 35: return _BV( 2 ); // PC 2 ** 35 ** D35 + case 36: return _BV( 1 ); // PC 1 ** 36 ** D36 + case 37: return _BV( 0 ); // PC 0 ** 37 ** D37 + case 38: return _BV( 7 ); // PD 7 ** 38 ** D38 + case 39: return _BV( 2 ); // PG 2 ** 39 ** D39 + case 40: return _BV( 1 ); // PG 1 ** 40 ** D40 + case 41: return _BV( 0 ); // PG 0 ** 41 ** D41 + case 42: return _BV( 7 ); // PL 7 ** 42 ** D42 + case 43: return _BV( 6 ); // PL 6 ** 43 ** D43 + case 44: return _BV( 5 ); // PL 5 ** 44 ** D44 + case 45: return _BV( 4 ); // PL 4 ** 45 ** D45 + case 46: return _BV( 3 ); // PL 3 ** 46 ** D46 + case 47: return _BV( 2 ); // PL 2 ** 47 ** D47 + case 48: return _BV( 1 ); // PL 1 ** 48 ** D48 + case 49: return _BV( 0 ); // PL 0 ** 49 ** D49 + case 50: return _BV( 3 ); // PB 3 ** 50 ** SPI_MISO + case 51: return _BV( 2 ); // PB 2 ** 51 ** SPI_MOSI + case 52: return _BV( 1 ); // PB 1 ** 52 ** SPI_SCK + case 53: return _BV( 0 ); // PB 0 ** 53 ** SPI_SS + case 54: return _BV( 0 ); // PF 0 ** 54 ** A0 + case 55: return _BV( 1 ); // PF 1 ** 55 ** A1 + case 56: return _BV( 2 ); // PF 2 ** 56 ** A2 + case 57: return _BV( 3 ); // PF 3 ** 57 ** A3 + case 58: return _BV( 4 ); // PF 4 ** 58 ** A4 + case 59: return _BV( 5 ); // PF 5 ** 59 ** A5 + case 60: return _BV( 6 ); // PF 6 ** 60 ** A6 + case 61: return _BV( 7 ); // PF 7 ** 61 ** A7 + case 62: return _BV( 0 ); // PK 0 ** 62 ** A8 + case 63: return _BV( 1 ); // PK 1 ** 63 ** A9 + case 64: return _BV( 2 ); // PK 2 ** 64 ** A10 + case 65: return _BV( 3 ); // PK 3 ** 65 ** A11 + case 66: return _BV( 4 ); // PK 4 ** 66 ** A12 + case 67: return _BV( 5 ); // PK 5 ** 67 ** A13 + case 68: return _BV( 6 ); // PK 6 ** 68 ** A14 + case 69: return _BV( 7 ); // PK 7 ** 69 ** A15 + default: + // TODO: add error here + invalidPinSpecified(); + } +} + +INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) +{ + switch(pin) { + case 2: return TIMER3B; // PE 4 ** 2 ** PWM2 + case 3: return TIMER3C; // PE 5 ** 3 ** PWM3 + case 4: return TIMER0B; // PG 5 ** 4 ** PWM4 + case 5: return TIMER3A; // PE 3 ** 5 ** PWM5 + case 6: return TIMER4A; // PH 3 ** 6 ** PWM6 + case 7: return TIMER4B; // PH 4 ** 7 ** PWM7 + case 8: return TIMER4C; // PH 5 ** 8 ** PWM8 + case 9: return TIMER2B; // PH 6 ** 9 ** PWM9 + case 10: return TIMER2A; // PB 4 ** 10 ** PWM10 + case 11: return TIMER1A; // PB 5 ** 11 ** PWM11 + case 12: return TIMER1B; // PB 6 ** 12 ** PWM12 + case 13: return TIMER0A; // PB 7 ** 13 ** PWM13 + case 44: return TIMER5C; // PL 5 ** 44 ** D44 + case 45: return TIMER5B; // PL 4 ** 45 ** D45 + case 46: return TIMER5A; // PL 3 ** 46 ** D46 + default: invalidPinSpecified(); + } +} + +#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + +INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) +{ + switch (port_index) { + case 2: return &DDRB; + case 3: return &DDRC; + case 4: return &DDRD; + default: invalidPinSpecified(); + } +} + +INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index) +{ + switch (port_index) { + case 2: return &PORTB; + case 3: return &PORTC; + case 4: return &PORTD; + default: invalidPinSpecified(); + } +} + +INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index) +{ + switch (port_index) { + case 2: return &PINB; + case 3: return &PINC; + case 4: return &PIND; + default: invalidPinSpecified(); + } +} + +INLINED uint8_t inlined_digitalPinToPort(uint8_t pin) +{ + switch(pin) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return PORT_INDEX_PD; + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + return PORT_INDEX_PB; + case 14: + case 15: + case 16: + case 17: + case 18: + case 19: + return PORT_INDEX_PC; + default: + invalidPinSpecified(); + } +} + +INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) +{ + switch(pin) { + case 0: return _BV(0); /* 0, port D */ + case 1: return _BV(1); + case 2: return _BV(2); + case 3: return _BV(3); + case 4: return _BV(4); + case 5: return _BV(5); + case 6: return _BV(6); + case 7: return _BV(7); + case 8: return _BV(0); /* 8, port B */ + case 9: return _BV(1); + case 10: return _BV(2); + case 11: return _BV(3); + case 12: return _BV(4); + case 13: return _BV(5); + case 14: return _BV(0); /* 14, port C */ + case 15: return _BV(1); + case 16: return _BV(2); + case 17: return _BV(3); + case 18: return _BV(4); + case 19: return _BV(5); + default: + // TODO: throw error here + invalidPinSpecified(); + } +} + +INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) +{ + switch(pin) { +#if defined(__AVR_ATmega8__) + case 11: return TIMER2; +#else + case 3: return TIMER2B; + case 5: return TIMER0B; + case 6: return TIMER0A; + case 11: return TIMER2A; +#endif + case 9: return TIMER1A; + case 10: return TIMER1B; + default: invalidPinSpecified(); + } +} + +#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + // 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_word( port_to_output_PGM + (P))) ) -#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) -#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) + +INLINED uint8_t digitalPinToPort(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToPort(pin); + else + return pgm_read_byte( digital_pin_to_port_PGM + pin ); +} + +INLINED uint8_t digitalPinToBitMask(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToBitMask(pin); + else + return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); +} + +INLINED uint8_t digitalPinToTimer(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToTimer(pin); + else + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); +} + +INLINED volatile uint8_t *portOutputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portOutputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); +} + +INLINED volatile uint8_t* portInputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portInputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); +} + +INLINED volatile uint8_t* portModeRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portModeRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); +} #endif diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index e29959b..433c87e 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -26,8 +26,10 @@ #define Wiring_h #include +#include #include #include "binary.h" +#include "pins_arduino.h" #ifdef __cplusplus extern "C"{ @@ -106,9 +108,9 @@ typedef uint8_t byte; void init(void); -void pinMode(uint8_t, uint8_t); -void digitalWrite(uint8_t, uint8_t); -int digitalRead(uint8_t); +void pinMode_lookup(uint8_t, uint8_t); +void digitalWrite_lookup(uint8_t, uint8_t); +int digitalRead_lookup(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); @@ -128,6 +130,71 @@ void detachInterrupt(uint8_t); void setup(void); void loop(void); +/* + * Check if a given pin requires locking. + * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However + * other IO ports require load+modify+store and we need to make them atomic by disabling + * interrupts. + */ +INLINED int portWriteNeedsLocking(uint8_t pin) +{ + /* SBI/CBI instructions only work on lower 32 IO ports */ + if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { + return 1; + } + return 0; +} + +/* + * These functions will perform OR/AND on a given register, and are atomic. + */ +extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); +extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); + +INLINED void digitalWrite(uint8_t pin, uint8_t value) +{ + if (__builtin_constant_p(pin)) { + if (portWriteNeedsLocking(pin)) { + if (value==LOW) { + __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); + } else { + __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); + } + } else { + if (value==LOW) { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } + } else { + digitalWrite_lookup(pin,value); + } +} + +INLINED void pinMode(uint8_t pin, uint8_t mode) +{ + if (__builtin_constant_p(pin)) { + if (mode==INPUT) { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } else { + pinMode_lookup(pin,mode); + } +} + +INLINED int digitalRead(uint8_t pin) +{ + if (__builtin_constant_p(pin)) { + return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); + } else { + return digitalRead_lookup(pin); + } +} + + #ifdef __cplusplus } // extern "C" #endif diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 0949da4..95666b1 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -27,7 +27,7 @@ #include "wiring_private.h" #include "pins_arduino.h" -void pinMode(uint8_t pin, uint8_t mode) +void pinMode_lookup(uint8_t pin, uint8_t mode) { uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); @@ -121,7 +121,23 @@ static void turnOffPWM(uint8_t timer) } } -void digitalWrite(uint8_t pin, uint8_t val) +void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit) +{ + uint8_t oldSREG = SREG; + cli(); + *out |= bit; + SREG=oldSREG; +} + +void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit) +{ + uint8_t oldSREG = SREG; + cli(); + *out &= bit; // NOTE - no inversion here, invert before calling!!! + SREG=oldSREG; +} + +void digitalWrite_lookup(uint8_t pin, uint8_t val) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); @@ -136,20 +152,19 @@ void digitalWrite(uint8_t pin, uint8_t val) out = portOutputRegister(port); + uint8_t oldSREG = SREG; + cli(); + if (val == LOW) { - uint8_t oldSREG = SREG; - cli(); *out &= ~bit; - SREG = oldSREG; } else { - uint8_t oldSREG = SREG; - cli(); *out |= bit; - SREG = oldSREG; } + + SREG = oldSREG; } -int digitalRead(uint8_t pin) +int digitalRead_lookup(uint8_t pin) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); From eed15e48d68d10426e015515ec4143849739f2de Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Feb 2011 19:29:46 -0500 Subject: [PATCH 03/54] Changes to optimized digitalWrte(), etc. Factoring out the implementation of digitalWrite(), digitalRead(), and pinMode() into macros that can either be inlined (for constant pin numbers) or executed within a function (non-constant pins). Removing testing for timers on pins in digitalWrite(), digitalRead(), and pinMode(). Moving pin to port macros from pins_arduino.h to wiring.h. --- cores/arduino/pins_arduino.h | 46 +--------- cores/arduino/wiring.h | 148 ++++++++++++++++++++++++--------- cores/arduino/wiring_digital.c | 76 +---------------- 3 files changed, 116 insertions(+), 154 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 63f4257..4bf6470 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -339,6 +339,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } +// XXX: this needs to return false (or -1) if the pin doesn't have a timer, +// rather than throwing a compilation error. INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) { switch(pin) { @@ -453,6 +455,8 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } +// XXX: this needs to return false (or -1) if the pin doesn't have a timer, +// rather than throwing a compilation error. INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) { switch(pin) { @@ -477,46 +481,4 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) #define analogInPinToBit(P) (P) -INLINED uint8_t digitalPinToPort(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToPort(pin); - else - return pgm_read_byte( digital_pin_to_port_PGM + pin ); -} - -INLINED uint8_t digitalPinToBitMask(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToBitMask(pin); - else - return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); -} - -INLINED uint8_t digitalPinToTimer(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToTimer(pin); - else - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); -} - -INLINED volatile uint8_t *portOutputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portOutputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); -} - -INLINED volatile uint8_t* portInputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portInputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); -} - -INLINED volatile uint8_t* portModeRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portModeRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); -} - #endif diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 433c87e..66ce2f7 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -130,68 +130,136 @@ void detachInterrupt(uint8_t); void setup(void); void loop(void); +INLINED uint8_t digitalPinToPort(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToPort(pin); + else + return pgm_read_byte( digital_pin_to_port_PGM + pin ); +} + +INLINED uint8_t digitalPinToBitMask(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToBitMask(pin); + else + return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); +} + +INLINED uint8_t digitalPinToTimer(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToTimer(pin); + else + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); +} + +INLINED volatile uint8_t *portOutputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portOutputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); +} + +INLINED volatile uint8_t* portInputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portInputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); +} + +INLINED volatile uint8_t* portModeRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portModeRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); +} + /* * Check if a given pin requires locking. * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However * other IO ports require load+modify+store and we need to make them atomic by disabling * interrupts. */ -INLINED int portWriteNeedsLocking(uint8_t pin) +INLINED int registerWriteNeedsLocking(volatile uint8_t *reg) { /* SBI/CBI instructions only work on lower 32 IO ports */ - if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { + if (reg > (volatile uint8_t*)&_SFR_IO8(0x1F)) { return 1; } return 0; } -/* - * These functions will perform OR/AND on a given register, and are atomic. - */ -extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); -extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); - +#define digitalWrite_implementation(pin, value)\ +do {\ + uint8_t oldSREG;\ + uint8_t bit = digitalPinToBitMask(pin);\ + uint8_t port = digitalPinToPort(pin);\ + volatile uint8_t *reg = portOutputRegister(port);\ +\ + if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ + oldSREG = SREG;\ + cli();\ + }\ +\ + if (value == LOW) {\ + *reg &= ~bit;\ + } else {\ + *reg |= bit;\ + }\ +\ + if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ + SREG = oldSREG;\ + }\ +} while(0) + INLINED void digitalWrite(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin)) { - if (portWriteNeedsLocking(pin)) { - if (value==LOW) { - __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); - } else { - __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); - } - } else { - if (value==LOW) { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } - } else { - digitalWrite_lookup(pin,value); - } + if (__builtin_constant_p(pin)) digitalWrite_implementation(pin, value); + else digitalWrite_lookup(pin, value); } -INLINED void pinMode(uint8_t pin, uint8_t mode) +#define pinMode_implementation(pin, value)\ +do {\ + uint8_t bit = digitalPinToBitMask(pin);\ + uint8_t oldSREG;\ + uint8_t port = digitalPinToPort(pin);\ + volatile uint8_t *reg = portModeRegister(port);\ +\ + if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ + oldSREG = SREG;\ + cli();\ + }\ +\ + if (value == INPUT) { \ + *reg &= ~bit;\ + } else {\ + *reg |= bit;\ + }\ +\ + if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ + SREG = oldSREG;\ + }\ +} while(0) + +INLINED void pinMode(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin)) { - if (mode==INPUT) { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } else { - pinMode_lookup(pin,mode); - } + if (__builtin_constant_p(pin)) pinMode_implementation(pin, value); + else pinMode_lookup(pin, value); } +#define digitalRead_implementation(pin)\ +do {\ + uint8_t bit = digitalPinToBitMask(pin);\ + uint8_t port = digitalPinToPort(pin);\ +\ + if (port == NOT_A_PIN) return LOW;\ +\ + if (*portInputRegister(port) & bit) return HIGH;\ + return LOW;\ +} while(0) + INLINED int digitalRead(uint8_t pin) { - if (__builtin_constant_p(pin)) { - return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); - } else { - return digitalRead_lookup(pin); - } + if (__builtin_constant_p(pin)) digitalRead_implementation(pin); + else return digitalRead_lookup(pin); } diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 95666b1..9671045 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -27,28 +27,9 @@ #include "wiring_private.h" #include "pins_arduino.h" -void pinMode_lookup(uint8_t pin, uint8_t mode) +void pinMode_lookup(uint8_t pin, uint8_t val) { - 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; - } + pinMode_implementation(pin, val); } // Forcing this inline keeps the callers from having to push their own stuff @@ -121,61 +102,12 @@ static void turnOffPWM(uint8_t timer) } } -void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit) -{ - uint8_t oldSREG = SREG; - cli(); - *out |= bit; - SREG=oldSREG; -} - -void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit) -{ - uint8_t oldSREG = SREG; - cli(); - *out &= bit; // NOTE - no inversion here, invert before calling!!! - SREG=oldSREG; -} - void digitalWrite_lookup(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); - - uint8_t oldSREG = SREG; - cli(); - - if (val == LOW) { - *out &= ~bit; - } else { - *out |= bit; - } - - SREG = oldSREG; + digitalWrite_implementation(pin, val); } int digitalRead_lookup(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; + digitalRead_implementation(pin); } From cd050d05d1fa7ae87da68574a9e50edf6ac1ed8f Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 12 Feb 2011 14:47:08 -0500 Subject: [PATCH 04/54] Adding noAnalogWrite() function to disable PWM. Also, removing the inline version of digitalPinToTimer() (since we're not optimizing the functions that use it anyway). The noAnalogWrite() function is in wiring_analog.c, deriving from the previous turnOffPWM() which has moved from wiring_digital.c. http://code.google.com/p/arduino/issues/detail?id=476 --- cores/arduino/pins_arduino.h | 43 --------------------- cores/arduino/wiring.h | 6 +-- cores/arduino/wiring_analog.c | 56 +++++++++++++++++++++++++++ cores/arduino/wiring_digital.c | 70 ---------------------------------- 4 files changed, 58 insertions(+), 117 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 4bf6470..ca6a821 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -339,30 +339,6 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } -// XXX: this needs to return false (or -1) if the pin doesn't have a timer, -// rather than throwing a compilation error. -INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) -{ - switch(pin) { - case 2: return TIMER3B; // PE 4 ** 2 ** PWM2 - case 3: return TIMER3C; // PE 5 ** 3 ** PWM3 - case 4: return TIMER0B; // PG 5 ** 4 ** PWM4 - case 5: return TIMER3A; // PE 3 ** 5 ** PWM5 - case 6: return TIMER4A; // PH 3 ** 6 ** PWM6 - case 7: return TIMER4B; // PH 4 ** 7 ** PWM7 - case 8: return TIMER4C; // PH 5 ** 8 ** PWM8 - case 9: return TIMER2B; // PH 6 ** 9 ** PWM9 - case 10: return TIMER2A; // PB 4 ** 10 ** PWM10 - case 11: return TIMER1A; // PB 5 ** 11 ** PWM11 - case 12: return TIMER1B; // PB 6 ** 12 ** PWM12 - case 13: return TIMER0A; // PB 7 ** 13 ** PWM13 - case 44: return TIMER5C; // PL 5 ** 44 ** D44 - case 45: return TIMER5B; // PL 4 ** 45 ** D45 - case 46: return TIMER5A; // PL 3 ** 46 ** D46 - default: invalidPinSpecified(); - } -} - #else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) @@ -455,25 +431,6 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } -// XXX: this needs to return false (or -1) if the pin doesn't have a timer, -// rather than throwing a compilation error. -INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) -{ - switch(pin) { -#if defined(__AVR_ATmega8__) - case 11: return TIMER2; -#else - case 3: return TIMER2B; - case 5: return TIMER0B; - case 6: return TIMER0A; - case 11: return TIMER2A; -#endif - case 9: return TIMER1A; - case 10: return TIMER1B; - default: invalidPinSpecified(); - } -} - #endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Get the bit location within the hardware port of the given virtual pin. diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 66ce2f7..2915b63 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -114,6 +114,7 @@ int digitalRead_lookup(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); +void noAnalogWrite(uint8_t); unsigned long millis(void); unsigned long micros(void); @@ -145,10 +146,7 @@ INLINED uint8_t digitalPinToBitMask(uint8_t pin) { } INLINED uint8_t digitalPinToTimer(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToTimer(pin); - else - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); } INLINED volatile uint8_t *portOutputRegister(uint8_t index) { diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index d248f4c..6185022 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -257,3 +257,59 @@ void analogWrite(uint8_t pin, int val) } } } + +void noAnalogWrite(uint8_t pin) +{ + switch (digitalPinToTimer(pin)) + { + #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 + } +} \ No newline at end of file diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 9671045..20930c5 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -32,76 +32,6 @@ void pinMode_lookup(uint8_t pin, uint8_t val) pinMode_implementation(pin, val); } -// 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_lookup(uint8_t pin, uint8_t val) { digitalWrite_implementation(pin, val); From 63515122ca28d9a60e6aba2948fb01765ca1138e Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 18 Feb 2011 10:40:56 -0500 Subject: [PATCH 05/54] Revert "Adding noAnalogWrite() function to disable PWM." This reverts commit 38d4a34fec6925b29a732d13e200f54ee4b42025. --- cores/arduino/pins_arduino.h | 43 +++++++++++++++++++++ cores/arduino/wiring.h | 6 ++- cores/arduino/wiring_analog.c | 56 --------------------------- cores/arduino/wiring_digital.c | 70 ++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 58 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index ca6a821..4bf6470 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -339,6 +339,30 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } +// XXX: this needs to return false (or -1) if the pin doesn't have a timer, +// rather than throwing a compilation error. +INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) +{ + switch(pin) { + case 2: return TIMER3B; // PE 4 ** 2 ** PWM2 + case 3: return TIMER3C; // PE 5 ** 3 ** PWM3 + case 4: return TIMER0B; // PG 5 ** 4 ** PWM4 + case 5: return TIMER3A; // PE 3 ** 5 ** PWM5 + case 6: return TIMER4A; // PH 3 ** 6 ** PWM6 + case 7: return TIMER4B; // PH 4 ** 7 ** PWM7 + case 8: return TIMER4C; // PH 5 ** 8 ** PWM8 + case 9: return TIMER2B; // PH 6 ** 9 ** PWM9 + case 10: return TIMER2A; // PB 4 ** 10 ** PWM10 + case 11: return TIMER1A; // PB 5 ** 11 ** PWM11 + case 12: return TIMER1B; // PB 6 ** 12 ** PWM12 + case 13: return TIMER0A; // PB 7 ** 13 ** PWM13 + case 44: return TIMER5C; // PL 5 ** 44 ** D44 + case 45: return TIMER5B; // PL 4 ** 45 ** D45 + case 46: return TIMER5A; // PL 3 ** 46 ** D46 + default: invalidPinSpecified(); + } +} + #else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) @@ -431,6 +455,25 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } +// XXX: this needs to return false (or -1) if the pin doesn't have a timer, +// rather than throwing a compilation error. +INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) +{ + switch(pin) { +#if defined(__AVR_ATmega8__) + case 11: return TIMER2; +#else + case 3: return TIMER2B; + case 5: return TIMER0B; + case 6: return TIMER0A; + case 11: return TIMER2A; +#endif + case 9: return TIMER1A; + case 10: return TIMER1B; + default: invalidPinSpecified(); + } +} + #endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // Get the bit location within the hardware port of the given virtual pin. diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 2915b63..66ce2f7 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -114,7 +114,6 @@ int digitalRead_lookup(uint8_t); int analogRead(uint8_t); void analogReference(uint8_t mode); void analogWrite(uint8_t, int); -void noAnalogWrite(uint8_t); unsigned long millis(void); unsigned long micros(void); @@ -146,7 +145,10 @@ INLINED uint8_t digitalPinToBitMask(uint8_t pin) { } INLINED uint8_t digitalPinToTimer(uint8_t pin) { - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); + if (__builtin_constant_p(pin)) + return inlined_digitalPinToTimer(pin); + else + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); } INLINED volatile uint8_t *portOutputRegister(uint8_t index) { diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index 6185022..d248f4c 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -257,59 +257,3 @@ void analogWrite(uint8_t pin, int val) } } } - -void noAnalogWrite(uint8_t pin) -{ - switch (digitalPinToTimer(pin)) - { - #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 - } -} \ No newline at end of file diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 20930c5..9671045 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -32,6 +32,76 @@ void pinMode_lookup(uint8_t pin, uint8_t val) pinMode_implementation(pin, val); } +// 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_lookup(uint8_t pin, uint8_t val) { digitalWrite_implementation(pin, val); From 860c6f203103f329d192547c4f62ff2471f99b43 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 18 Feb 2011 10:41:29 -0500 Subject: [PATCH 06/54] Revert "Changes to optimized digitalWrte(), etc." This reverts commit aa1f1cbda9d6bb52785f98b40746920853d6579b. --- cores/arduino/pins_arduino.h | 46 +++++++++- cores/arduino/wiring.h | 148 +++++++++------------------------ cores/arduino/wiring_digital.c | 76 ++++++++++++++++- 3 files changed, 154 insertions(+), 116 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 4bf6470..63f4257 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -339,8 +339,6 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } -// XXX: this needs to return false (or -1) if the pin doesn't have a timer, -// rather than throwing a compilation error. INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) { switch(pin) { @@ -455,8 +453,6 @@ INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) } } -// XXX: this needs to return false (or -1) if the pin doesn't have a timer, -// rather than throwing a compilation error. INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) { switch(pin) { @@ -481,4 +477,46 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) #define analogInPinToBit(P) (P) +INLINED uint8_t digitalPinToPort(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToPort(pin); + else + return pgm_read_byte( digital_pin_to_port_PGM + pin ); +} + +INLINED uint8_t digitalPinToBitMask(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToBitMask(pin); + else + return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); +} + +INLINED uint8_t digitalPinToTimer(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToTimer(pin); + else + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); +} + +INLINED volatile uint8_t *portOutputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portOutputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); +} + +INLINED volatile uint8_t* portInputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portInputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); +} + +INLINED volatile uint8_t* portModeRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portModeRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); +} + #endif diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 66ce2f7..433c87e 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -130,136 +130,68 @@ void detachInterrupt(uint8_t); void setup(void); void loop(void); -INLINED uint8_t digitalPinToPort(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToPort(pin); - else - return pgm_read_byte( digital_pin_to_port_PGM + pin ); -} - -INLINED uint8_t digitalPinToBitMask(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToBitMask(pin); - else - return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); -} - -INLINED uint8_t digitalPinToTimer(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToTimer(pin); - else - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); -} - -INLINED volatile uint8_t *portOutputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portOutputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); -} - -INLINED volatile uint8_t* portInputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portInputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); -} - -INLINED volatile uint8_t* portModeRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portModeRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); -} - /* * Check if a given pin requires locking. * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However * other IO ports require load+modify+store and we need to make them atomic by disabling * interrupts. */ -INLINED int registerWriteNeedsLocking(volatile uint8_t *reg) +INLINED int portWriteNeedsLocking(uint8_t pin) { /* SBI/CBI instructions only work on lower 32 IO ports */ - if (reg > (volatile uint8_t*)&_SFR_IO8(0x1F)) { + if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { return 1; } return 0; } -#define digitalWrite_implementation(pin, value)\ -do {\ - uint8_t oldSREG;\ - uint8_t bit = digitalPinToBitMask(pin);\ - uint8_t port = digitalPinToPort(pin);\ - volatile uint8_t *reg = portOutputRegister(port);\ -\ - if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ - oldSREG = SREG;\ - cli();\ - }\ -\ - if (value == LOW) {\ - *reg &= ~bit;\ - } else {\ - *reg |= bit;\ - }\ -\ - if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ - SREG = oldSREG;\ - }\ -} while(0) - +/* + * These functions will perform OR/AND on a given register, and are atomic. + */ +extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); +extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); + INLINED void digitalWrite(uint8_t pin, uint8_t value) { - if (__builtin_constant_p(pin)) digitalWrite_implementation(pin, value); - else digitalWrite_lookup(pin, value); + if (__builtin_constant_p(pin)) { + if (portWriteNeedsLocking(pin)) { + if (value==LOW) { + __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); + } else { + __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); + } + } else { + if (value==LOW) { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } + } else { + digitalWrite_lookup(pin,value); + } } -#define pinMode_implementation(pin, value)\ -do {\ - uint8_t bit = digitalPinToBitMask(pin);\ - uint8_t oldSREG;\ - uint8_t port = digitalPinToPort(pin);\ - volatile uint8_t *reg = portModeRegister(port);\ -\ - if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ - oldSREG = SREG;\ - cli();\ - }\ -\ - if (value == INPUT) { \ - *reg &= ~bit;\ - } else {\ - *reg |= bit;\ - }\ -\ - if (!__builtin_constant_p(pin) || registerWriteNeedsLocking(reg)) {\ - SREG = oldSREG;\ - }\ -} while(0) - -INLINED void pinMode(uint8_t pin, uint8_t value) +INLINED void pinMode(uint8_t pin, uint8_t mode) { - if (__builtin_constant_p(pin)) pinMode_implementation(pin, value); - else pinMode_lookup(pin, value); + if (__builtin_constant_p(pin)) { + if (mode==INPUT) { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } else { + pinMode_lookup(pin,mode); + } } -#define digitalRead_implementation(pin)\ -do {\ - uint8_t bit = digitalPinToBitMask(pin);\ - uint8_t port = digitalPinToPort(pin);\ -\ - if (port == NOT_A_PIN) return LOW;\ -\ - if (*portInputRegister(port) & bit) return HIGH;\ - return LOW;\ -} while(0) - INLINED int digitalRead(uint8_t pin) { - if (__builtin_constant_p(pin)) digitalRead_implementation(pin); - else return digitalRead_lookup(pin); + if (__builtin_constant_p(pin)) { + return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); + } else { + return digitalRead_lookup(pin); + } } diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 9671045..95666b1 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -27,9 +27,28 @@ #include "wiring_private.h" #include "pins_arduino.h" -void pinMode_lookup(uint8_t pin, uint8_t val) +void pinMode_lookup(uint8_t pin, uint8_t mode) { - pinMode_implementation(pin, val); + 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 @@ -102,12 +121,61 @@ static void turnOffPWM(uint8_t timer) } } +void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit) +{ + uint8_t oldSREG = SREG; + cli(); + *out |= bit; + SREG=oldSREG; +} + +void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit) +{ + uint8_t oldSREG = SREG; + cli(); + *out &= bit; // NOTE - no inversion here, invert before calling!!! + SREG=oldSREG; +} + void digitalWrite_lookup(uint8_t pin, uint8_t val) { - digitalWrite_implementation(pin, 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); + + uint8_t oldSREG = SREG; + cli(); + + if (val == LOW) { + *out &= ~bit; + } else { + *out |= bit; + } + + SREG = oldSREG; } int digitalRead_lookup(uint8_t pin) { - digitalRead_implementation(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; } From c8b8b8724cc94cdd9290033d76513c8f816ad862 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 26 Feb 2011 13:58:03 -0500 Subject: [PATCH 07/54] Removing BYTE keyword (use Serial.write() instead). --- cores/arduino/Print.cpp | 8 ++++---- cores/arduino/Print.h | 9 ++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 4ee556d..eb1a8de 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -55,9 +55,9 @@ void Print::print(const char str[]) write(str); } -void Print::print(char c, int base) +void Print::print(char c) { - print((long) c, base); + write(c); } void Print::print(unsigned char b, int base) @@ -119,9 +119,9 @@ void Print::println(const char c[]) println(); } -void Print::println(char c, int base) +void Print::println(char c) { - print(c, base); + print(c); println(); } diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index b092ae5..c090636 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -29,7 +29,6 @@ #define HEX 16 #define OCT 8 #define BIN 2 -#define BYTE 0 class Print { @@ -43,8 +42,8 @@ class Print void print(const String &); void print(const char[]); - void print(char, int = BYTE); - void print(unsigned char, int = BYTE); + void print(char); + void print(unsigned char, int = DEC); void print(int, int = DEC); void print(unsigned int, int = DEC); void print(long, int = DEC); @@ -53,8 +52,8 @@ class Print void println(const String &s); void println(const char[]); - void println(char, int = BYTE); - void println(unsigned char, int = BYTE); + void println(char); + void println(unsigned char, int = DEC); void println(int, int = DEC); void println(unsigned int, int = DEC); void println(long, int = DEC); From e009c5c6c61da7dcf2683a75e7b17ea4fb3c6e2d Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 1 Mar 2011 19:52:13 -0500 Subject: [PATCH 08/54] Renamed WProgram.h to Arduino.h. --- cores/arduino/{WProgram.h => Arduino.h} | 4 ++-- cores/arduino/WString.cpp | 2 +- cores/arduino/WString.h | 2 +- cores/arduino/main.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename cores/arduino/{WProgram.h => Arduino.h} (97%) diff --git a/cores/arduino/WProgram.h b/cores/arduino/Arduino.h similarity index 97% rename from cores/arduino/WProgram.h rename to cores/arduino/Arduino.h index f73e760..ceaa560 100755 --- a/cores/arduino/WProgram.h +++ b/cores/arduino/Arduino.h @@ -1,5 +1,5 @@ -#ifndef WProgram_h -#define WProgram_h +#ifndef Arduino_h +#define Arduino_h #include #include diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index db5a441..5899798 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -18,7 +18,7 @@ */ #include -#include "WProgram.h" +#include "Arduino.h" #include "WString.h" diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index cadddb9..ff671d8 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -20,7 +20,7 @@ #ifndef String_h #define String_h -//#include "WProgram.h" +//#include "Arduino.h" #include #include #include diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index cc6e81d..a806ebc 100755 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -1,4 +1,4 @@ -#include +#include int main(void) { From 218eb5e80706b53c691da133461830c895e0c8ff Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 1 Mar 2011 20:00:16 -0500 Subject: [PATCH 09/54] Moving wiring.h contents into Arduino.h. --- cores/arduino/Arduino.h | 202 ++++++++++++++++++++++++++----- cores/arduino/HardwareSerial.cpp | 2 +- cores/arduino/Print.cpp | 2 +- cores/arduino/Tone.cpp | 2 +- cores/arduino/pins_arduino.h | 28 +++++ cores/arduino/wiring.h | 173 -------------------------- cores/arduino/wiring_private.h | 2 +- 7 files changed, 205 insertions(+), 206 deletions(-) diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index ceaa560..213f623 100755 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -7,7 +7,179 @@ #include -#include "wiring.h" +#include +#include +#include +#include "binary.h" +#include "pins_arduino.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_lookup(uint8_t, uint8_t); +void digitalWrite_lookup(uint8_t, uint8_t); +int digitalRead_lookup(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); + +/* + * Check if a given pin requires locking. + * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However + * other IO ports require load+modify+store and we need to make them atomic by disabling + * interrupts. + */ +INLINED int portWriteNeedsLocking(uint8_t pin) +{ + /* SBI/CBI instructions only work on lower 32 IO ports */ + if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { + return 1; + } + return 0; +} + +/* + * These functions will perform OR/AND on a given register, and are atomic. + */ +extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); +extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); + +INLINED void digitalWrite(uint8_t pin, uint8_t value) +{ + if (__builtin_constant_p(pin)) { + if (portWriteNeedsLocking(pin)) { + if (value==LOW) { + __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); + } else { + __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); + } + } else { + if (value==LOW) { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } + } else { + digitalWrite_lookup(pin,value); + } +} + +INLINED void pinMode(uint8_t pin, uint8_t mode) +{ + if (__builtin_constant_p(pin)) { + if (mode==INPUT) { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } + } else { + pinMode_lookup(pin,mode); + } +} + +INLINED int digitalRead(uint8_t pin) +{ + if (__builtin_constant_p(pin)) { + return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); + } else { + return digitalRead_lookup(pin); + } +} + + +#ifdef __cplusplus +} // extern "C" +#endif #ifdef __cplusplus #include "WCharacter.h" @@ -30,34 +202,6 @@ 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 \ No newline at end of file diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 4397efb..7cea350 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -24,7 +24,7 @@ #include #include #include -#include "wiring.h" +#include "Arduino.h" #include "wiring_private.h" // this next line disables the entire HardwareSerial.cpp, diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index eb1a8de..62d93a3 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -23,7 +23,7 @@ #include #include #include -#include "wiring.h" +#include "Arduino.h" #include "Print.h" diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index c3910e7..20eed3f 100755 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -33,7 +33,7 @@ Version Modified By Date Comments #include #include -#include "wiring.h" +#include "Arduino.h" #include "pins_arduino.h" #if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 63f4257..f48d5bc 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -65,6 +65,34 @@ const static uint8_t MISO = 12; const static uint8_t SCK = 13; #endif +#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 + // On the ATmega1280, the addresses of some of the port registers are // greater than 255, so we can't store them in uint8_t's. extern const uint16_t PROGMEM port_to_mode_PGM[]; diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h index 433c87e..b8a44ae 100755 --- a/cores/arduino/wiring.h +++ b/cores/arduino/wiring.h @@ -25,178 +25,5 @@ #ifndef Wiring_h #define Wiring_h -#include -#include -#include -#include "binary.h" -#include "pins_arduino.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_lookup(uint8_t, uint8_t); -void digitalWrite_lookup(uint8_t, uint8_t); -int digitalRead_lookup(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); - -/* - * Check if a given pin requires locking. - * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However - * other IO ports require load+modify+store and we need to make them atomic by disabling - * interrupts. - */ -INLINED int portWriteNeedsLocking(uint8_t pin) -{ - /* SBI/CBI instructions only work on lower 32 IO ports */ - if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { - return 1; - } - return 0; -} - -/* - * These functions will perform OR/AND on a given register, and are atomic. - */ -extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); -extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); - -INLINED void digitalWrite(uint8_t pin, uint8_t value) -{ - if (__builtin_constant_p(pin)) { - if (portWriteNeedsLocking(pin)) { - if (value==LOW) { - __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); - } else { - __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); - } - } else { - if (value==LOW) { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } - } else { - digitalWrite_lookup(pin,value); - } -} - -INLINED void pinMode(uint8_t pin, uint8_t mode) -{ - if (__builtin_constant_p(pin)) { - if (mode==INPUT) { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } else { - pinMode_lookup(pin,mode); - } -} - -INLINED int digitalRead(uint8_t pin) -{ - if (__builtin_constant_p(pin)) { - return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); - } else { - return digitalRead_lookup(pin); - } -} - - -#ifdef __cplusplus -} // extern "C" -#endif #endif diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index 11f6f00..74c0d06 100755 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -31,7 +31,7 @@ #include #include -#include "wiring.h" +#include "Arduino.h" #ifdef __cplusplus extern "C"{ From d7a87f18f06481f2ca3c342dfdd1268d934ecedb Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 2 Mar 2011 23:05:25 -0500 Subject: [PATCH 10/54] Re-arranging header files and small fixes to optimized core functions. --- cores/arduino/Arduino.h | 70 ++++++++++++++++++++++++++++++++++-- cores/arduino/WConstants.h | 1 - cores/arduino/WInterrupts.c | 1 - cores/arduino/pins_arduino.h | 51 ++------------------------ cores/arduino/wiring.h | 29 --------------- 5 files changed, 69 insertions(+), 83 deletions(-) delete mode 100644 cores/arduino/WConstants.h delete mode 100755 cores/arduino/wiring.h diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 213f623..d4c1c46 100755 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -112,6 +112,53 @@ void detachInterrupt(uint8_t); void setup(void); void loop(void); +// 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. + +#define analogInPinToBit(P) (P) + +INLINED uint8_t digitalPinToPort(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToPort(pin); + else + return pgm_read_byte( digital_pin_to_port_PGM + pin ); +} + +INLINED uint8_t digitalPinToBitMask(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToBitMask(pin); + else + return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); +} + +INLINED uint8_t digitalPinToTimer(uint8_t pin) { + if (__builtin_constant_p(pin)) + return inlined_digitalPinToTimer(pin); + else + return pgm_read_byte( digital_pin_to_timer_PGM + pin ); +} + +INLINED volatile uint8_t *portOutputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portOutputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); +} + +INLINED volatile uint8_t* portInputRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portInputRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); +} + +INLINED volatile uint8_t* portModeRegister(uint8_t index) { + if (__builtin_constant_p(index)) + return inlined_portModeRegister(index); + else + return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); +} + /* * Check if a given pin requires locking. * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However @@ -127,6 +174,15 @@ INLINED int portWriteNeedsLocking(uint8_t pin) return 0; } +INLINED int portModeNeedsLocking(uint8_t pin) +{ + /* SBI/CBI instructions only work on lower 32 IO ports */ + if (inlined_portModeRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { + return 1; + } + return 0; +} + /* * These functions will perform OR/AND on a given register, and are atomic. */ @@ -157,10 +213,18 @@ INLINED void digitalWrite(uint8_t pin, uint8_t value) INLINED void pinMode(uint8_t pin, uint8_t mode) { if (__builtin_constant_p(pin)) { - if (mode==INPUT) { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + if (portModeNeedsLocking(pin)) { + if (mode==INPUT) { + __digitalWriteAND_locked(inlined_portModeRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); + } else { + __digitalWriteOR_locked(inlined_portModeRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); + } } else { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + if (mode==INPUT) { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); + } else { + *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); + } } } else { pinMode_lookup(pin,mode); diff --git a/cores/arduino/WConstants.h b/cores/arduino/WConstants.h deleted file mode 100644 index 3e19ac4..0000000 --- a/cores/arduino/WConstants.h +++ /dev/null @@ -1 +0,0 @@ -#include "wiring.h" diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 3b3e0c9..75c713b 100755 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -30,7 +30,6 @@ #include #include -#include "WConstants.h" #include "wiring_private.h" volatile static voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index f48d5bc..e9d3fc7 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -385,7 +385,7 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) case 44: return TIMER5C; // PL 5 ** 44 ** D44 case 45: return TIMER5B; // PL 4 ** 45 ** D45 case 46: return TIMER5A; // PL 3 ** 46 ** D46 - default: invalidPinSpecified(); + default: return NOT_ON_TIMER; } } @@ -494,57 +494,10 @@ INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) #endif case 9: return TIMER1A; case 10: return TIMER1B; - default: invalidPinSpecified(); + default: return NOT_ON_TIMER; } } #endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -// 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. - -#define analogInPinToBit(P) (P) - -INLINED uint8_t digitalPinToPort(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToPort(pin); - else - return pgm_read_byte( digital_pin_to_port_PGM + pin ); -} - -INLINED uint8_t digitalPinToBitMask(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToBitMask(pin); - else - return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); -} - -INLINED uint8_t digitalPinToTimer(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToTimer(pin); - else - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); -} - -INLINED volatile uint8_t *portOutputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portOutputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); -} - -INLINED volatile uint8_t* portInputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portInputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); -} - -INLINED volatile uint8_t* portModeRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portModeRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); -} - #endif diff --git a/cores/arduino/wiring.h b/cores/arduino/wiring.h deleted file mode 100755 index b8a44ae..0000000 --- a/cores/arduino/wiring.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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 - - -#endif From 58d683239d80d4620a3ab35c4eac53bbe2c35d50 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 3 Mar 2011 18:46:45 -0500 Subject: [PATCH 11/54] Removing optimized digitalWrite(), digitalRead(), pinMode(). --- cores/arduino/Arduino.h | 148 ++---------- cores/arduino/pins_arduino.h | 407 --------------------------------- cores/arduino/wiring_digital.c | 22 +- 3 files changed, 27 insertions(+), 550 deletions(-) diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index d4c1c46..713347b 100755 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -90,9 +90,9 @@ typedef uint8_t byte; void init(void); -void pinMode_lookup(uint8_t, uint8_t); -void digitalWrite_lookup(uint8_t, uint8_t); -int digitalRead_lookup(uint8_t); +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); @@ -117,129 +117,29 @@ void loop(void); #define analogInPinToBit(P) (P) -INLINED uint8_t digitalPinToPort(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToPort(pin); - else - return pgm_read_byte( digital_pin_to_port_PGM + pin ); -} +// On the ATmega1280, the addresses of some of the port registers are +// greater than 255, so we can't store them in uint8_t's. +extern const uint16_t PROGMEM port_to_mode_PGM[]; +extern const uint16_t PROGMEM port_to_input_PGM[]; +extern const uint16_t PROGMEM port_to_output_PGM[]; -INLINED uint8_t digitalPinToBitMask(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToBitMask(pin); - else - return pgm_read_byte( digital_pin_to_bit_mask_PGM + pin ); -} - -INLINED uint8_t digitalPinToTimer(uint8_t pin) { - if (__builtin_constant_p(pin)) - return inlined_digitalPinToTimer(pin); - else - return pgm_read_byte( digital_pin_to_timer_PGM + pin ); -} - -INLINED volatile uint8_t *portOutputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portOutputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + index ) ); -} - -INLINED volatile uint8_t* portInputRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portInputRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + index) ); -} - -INLINED volatile uint8_t* portModeRegister(uint8_t index) { - if (__builtin_constant_p(index)) - return inlined_portModeRegister(index); - else - return (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + index) ); -} - -/* - * Check if a given pin requires locking. - * When accessing lower 32 IO ports we can use SBI/CBI instructions, which are atomic. However - * other IO ports require load+modify+store and we need to make them atomic by disabling - * interrupts. - */ -INLINED int portWriteNeedsLocking(uint8_t pin) -{ - /* SBI/CBI instructions only work on lower 32 IO ports */ - if (inlined_portOutputRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { - return 1; - } - return 0; -} - -INLINED int portModeNeedsLocking(uint8_t pin) -{ - /* SBI/CBI instructions only work on lower 32 IO ports */ - if (inlined_portModeRegister(inlined_digitalPinToPort(pin)) > (volatile uint8_t*)&_SFR_IO8(0x1F)) { - return 1; - } - return 0; -} - -/* - * These functions will perform OR/AND on a given register, and are atomic. - */ -extern void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit); -extern void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit); - -INLINED void digitalWrite(uint8_t pin, uint8_t value) -{ - if (__builtin_constant_p(pin)) { - if (portWriteNeedsLocking(pin)) { - if (value==LOW) { - __digitalWriteAND_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); - } else { - __digitalWriteOR_locked(inlined_portOutputRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); - } - } else { - if (value==LOW) { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portOutputRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } - } else { - digitalWrite_lookup(pin,value); - } -} - -INLINED void pinMode(uint8_t pin, uint8_t mode) -{ - if (__builtin_constant_p(pin)) { - if (portModeNeedsLocking(pin)) { - if (mode==INPUT) { - __digitalWriteAND_locked(inlined_portModeRegister(inlined_digitalPinToPort(pin)),~inlined_digitalPinToBitMask(pin)); - } else { - __digitalWriteOR_locked(inlined_portModeRegister(inlined_digitalPinToPort(pin)),inlined_digitalPinToBitMask(pin)); - } - } else { - if (mode==INPUT) { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) &= ~(inlined_digitalPinToBitMask(pin)); - } else { - *inlined_portModeRegister(inlined_digitalPinToPort(pin)) |= inlined_digitalPinToBitMask(pin); - } - } - } else { - pinMode_lookup(pin,mode); - } -} - -INLINED int digitalRead(uint8_t pin) -{ - if (__builtin_constant_p(pin)) { - return !! *inlined_portInputRegister(inlined_digitalPinToPort(pin)); - } else { - return digitalRead_lookup(pin); - } -} +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_word( port_to_output_PGM + (P))) ) +#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) +#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) #ifdef __cplusplus } // extern "C" diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index e9d3fc7..98af18e 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -93,411 +93,4 @@ const static uint8_t A6 = 20; const static uint8_t A7 = 21; #endif -// On the ATmega1280, the addresses of some of the port registers are -// greater than 255, so we can't store them in uint8_t's. -extern const uint16_t PROGMEM port_to_mode_PGM[]; -extern const uint16_t PROGMEM port_to_input_PGM[]; -extern const uint16_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[]; - -// inlined versions of lookup-table-based pin mappings. Don't use directly. - -// Don't use PA, so on, might clash with sketch - -#define PORT_INDEX_PA 1 -#define PORT_INDEX_PB 2 -#define PORT_INDEX_PC 3 -#define PORT_INDEX_PD 4 -#define PORT_INDEX_PE 5 -#define PORT_INDEX_PF 6 -#define PORT_INDEX_PG 7 -#define PORT_INDEX_PH 8 -#define PORT_INDEX_PJ 10 -#define PORT_INDEX_PK 11 -#define PORT_INDEX_PL 12 - -__attribute__((error("Invalid pin specified. This pin does not map to any I/O port"))) static void invalidPinSpecified(void); - - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - -INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) -{ - switch (port_index) { - case 1: return &DDRA; - case 2: return &DDRB; - case 3: return &DDRC; - case 4: return &DDRD; - case 5: return &DDRE; - case 6: return &DDRF; - case 7: return &DDRG; - case 8: return &DDRH; - case 10: return &DDRJ; - case 11: return &DDRK; - case 12: return &DDRL; - default: return NOT_A_PORT; - } -} - -INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index) -{ - switch (port_index) { - case 1: return &PORTA; - case 2: return &PORTB; - case 3: return &PORTC; - case 4: return &PORTD; - case 5: return &PORTE; - case 6: return &PORTF; - case 7: return &PORTG; - case 8: return &PORTH; - case 10: return &PORTJ; - case 11: return &PORTK; - case 12: return &PORTL; - default: return NOT_A_PORT; - } -} - -INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index) -{ - switch (port_index) { - case 1: return &PINA; - case 2: return &PINB; - case 3: return &PINC; - case 4: return &PIND; - case 5: return &PINE; - case 6: return &PINF; - case 7: return &PING; - case 8: return &PINH; - case 10: return &PINJ; - case 11: return &PINK; - case 12: return &PINL; - default: return NOT_A_PIN; - } -}; - -INLINED uint8_t inlined_digitalPinToPort(uint8_t pin) -{ - switch (pin) { - case 0: // PE 0 ** 0 ** USART0_RX - case 1: // PE 1 ** 1 ** USART0_TX - case 2: // PE 4 ** 2 ** PWM2 - case 3: // PE 5 ** 3 ** PWM3 - return PORT_INDEX_PE; - - case 4: // PG 5 ** 4 ** PWM4 - return PORT_INDEX_PG; - - case 5: // PE 3 ** 5 ** PWM5 - return PORT_INDEX_PE; - - case 6: // PH 3 ** 6 ** PWM6 - case 7: // PH 4 ** 7 ** PWM7 - case 8: // PH 5 ** 8 ** PWM8 - case 9: // PH 6 ** 9 ** PWM9 - return PORT_INDEX_PH; - - case 10: // PB 4 ** 10 ** PWM10 - case 11: // PB 5 ** 11 ** PWM11 - case 12: // PB 6 ** 12 ** PWM12 - case 13: // PB 7 ** 13 ** PWM13 - return PORT_INDEX_PB; - - case 14: // PJ 1 ** 14 ** USART3_TX - case 15: // PJ 0 ** 15 ** USART3_RX - return PORT_INDEX_PJ; - - case 16: // PH 1 ** 16 ** USART2_TX - case 17: // PH 0 ** 17 ** USART2_RX - return PORT_INDEX_PH; - - case 18: // PD 3 ** 18 ** USART1_TX - case 19: // PD 2 ** 19 ** USART1_RX - case 20: // PD 1 ** 20 ** I2C_SDA - case 21: // PD 0 ** 21 ** I2C_SCL - return PORT_INDEX_PD; - - case 22: // PA 0 ** 22 ** D22 - case 23: // PA 1 ** 23 ** D23 - case 24: // PA 2 ** 24 ** D24 - case 25: // PA 3 ** 25 ** D25 - case 26: // PA 4 ** 26 ** D26 - case 27: // PA 5 ** 27 ** D27 - case 28: // PA 6 ** 28 ** D28 - case 29: // PA 7 ** 29 ** D29 - return PORT_INDEX_PA; - - case 30: // PC 7 ** 30 ** D30 - case 31: // PC 6 ** 31 ** D31 - case 32: // PC 5 ** 32 ** D32 - case 33: // PC 4 ** 33 ** D33 - case 34: // PC 3 ** 34 ** D34 - case 35: // PC 2 ** 35 ** D35 - case 36: // PC 1 ** 36 ** D36 - case 37: // PC 0 ** 37 ** D37 - return PORT_INDEX_PC; - - case 38: // PD 7 ** 38 ** D38 - return PORT_INDEX_PD; - - case 39: // PG 2 ** 39 ** D39 - case 40: // PG 1 ** 40 ** D40 - case 41: // PG 0 ** 41 ** D41 - return PORT_INDEX_PG; - - case 42: // PL 7 ** 42 ** D42 - case 43: // PL 6 ** 43 ** D43 - case 44: // PL 5 ** 44 ** D44 - case 45: // PL 4 ** 45 ** D45 - case 46: // PL 3 ** 46 ** D46 - case 47: // PL 2 ** 47 ** D47 - case 48: // PL 1 ** 48 ** D48 - case 49: // PL 0 ** 49 ** D49 - return PORT_INDEX_PL; - - case 50: // PB 3 ** 50 ** SPI_MISO - case 51: // PB 2 ** 51 ** SPI_MOSI - case 52: // PB 1 ** 52 ** SPI_SCK - case 53: // PB 0 ** 53 ** SPI_SS - return PORT_INDEX_PB; - - case 54: // PF 0 ** 54 ** A0 - case 55: // PF 1 ** 55 ** A1 - case 56: // PF 2 ** 56 ** A2 - case 57: // PF 3 ** 57 ** A3 - case 58: // PF 4 ** 58 ** A4 - case 59: // PF 5 ** 59 ** A5 - case 60: // PF 6 ** 60 ** A6 - case 61: // PF 7 ** 61 ** A7 - return PORT_INDEX_PF; - - case 62: // PK 0 ** 62 ** A8 - case 63: // PK 1 ** 63 ** A9 - case 64: // PK 2 ** 64 ** A10 - case 65: // PK 3 ** 65 ** A11 - case 66: // PK 4 ** 66 ** A12 - case 67: // PK 5 ** 67 ** A13 - case 68: // PK 6 ** 68 ** A14 - case 69: // PK 7 ** 69 ** A15 - return PORT_INDEX_PK; - default: - invalidPinSpecified(); - } -} - -INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) -{ - switch(pin) { - case 0: return _BV( 0 ); // PE 0 ** 0 ** USART0_RX - case 1: return _BV( 1 ); // PE 1 ** 1 ** USART0_TX - case 2: return _BV( 4 ); // PE 4 ** 2 ** PWM2 - case 3: return _BV( 5 ); // PE 5 ** 3 ** PWM3 - case 4: return _BV( 5 ); // PG 5 ** 4 ** PWM4 - case 5: return _BV( 3 ); // PE 3 ** 5 ** PWM5 - case 6: return _BV( 3 ); // PH 3 ** 6 ** PWM6 - case 7: return _BV( 4 ); // PH 4 ** 7 ** PWM7 - case 8: return _BV( 5 ); // PH 5 ** 8 ** PWM8 - case 9: return _BV( 6 ); // PH 6 ** 9 ** PWM9 - case 10: return _BV( 4 ); // PB 4 ** 10 ** PWM10 - case 11: return _BV( 5 ); // PB 5 ** 11 ** PWM11 - case 12: return _BV( 6 ); // PB 6 ** 12 ** PWM12 - case 13: return _BV( 7 ); // PB 7 ** 13 ** PWM13 - case 14: return _BV( 1 ); // PJ 1 ** 14 ** USART3_TX - case 15: return _BV( 0 ); // PJ 0 ** 15 ** USART3_RX - case 16: return _BV( 1 ); // PH 1 ** 16 ** USART2_TX - case 17: return _BV( 0 ); // PH 0 ** 17 ** USART2_RX - case 18: return _BV( 3 ); // PD 3 ** 18 ** USART1_TX - case 19: return _BV( 2 ); // PD 2 ** 19 ** USART1_RX - case 20: return _BV( 1 ); // PD 1 ** 20 ** I2C_SDA - case 21: return _BV( 0 ); // PD 0 ** 21 ** I2C_SCL - case 22: return _BV( 0 ); // PA 0 ** 22 ** D22 - case 23: return _BV( 1 ); // PA 1 ** 23 ** D23 - case 24: return _BV( 2 ); // PA 2 ** 24 ** D24 - case 25: return _BV( 3 ); // PA 3 ** 25 ** D25 - case 26: return _BV( 4 ); // PA 4 ** 26 ** D26 - case 27: return _BV( 5 ); // PA 5 ** 27 ** D27 - case 28: return _BV( 6 ); // PA 6 ** 28 ** D28 - case 29: return _BV( 7 ); // PA 7 ** 29 ** D29 - case 30: return _BV( 7 ); // PC 7 ** 30 ** D30 - case 31: return _BV( 6 ); // PC 6 ** 31 ** D31 - case 32: return _BV( 5 ); // PC 5 ** 32 ** D32 - case 33: return _BV( 4 ); // PC 4 ** 33 ** D33 - case 34: return _BV( 3 ); // PC 3 ** 34 ** D34 - case 35: return _BV( 2 ); // PC 2 ** 35 ** D35 - case 36: return _BV( 1 ); // PC 1 ** 36 ** D36 - case 37: return _BV( 0 ); // PC 0 ** 37 ** D37 - case 38: return _BV( 7 ); // PD 7 ** 38 ** D38 - case 39: return _BV( 2 ); // PG 2 ** 39 ** D39 - case 40: return _BV( 1 ); // PG 1 ** 40 ** D40 - case 41: return _BV( 0 ); // PG 0 ** 41 ** D41 - case 42: return _BV( 7 ); // PL 7 ** 42 ** D42 - case 43: return _BV( 6 ); // PL 6 ** 43 ** D43 - case 44: return _BV( 5 ); // PL 5 ** 44 ** D44 - case 45: return _BV( 4 ); // PL 4 ** 45 ** D45 - case 46: return _BV( 3 ); // PL 3 ** 46 ** D46 - case 47: return _BV( 2 ); // PL 2 ** 47 ** D47 - case 48: return _BV( 1 ); // PL 1 ** 48 ** D48 - case 49: return _BV( 0 ); // PL 0 ** 49 ** D49 - case 50: return _BV( 3 ); // PB 3 ** 50 ** SPI_MISO - case 51: return _BV( 2 ); // PB 2 ** 51 ** SPI_MOSI - case 52: return _BV( 1 ); // PB 1 ** 52 ** SPI_SCK - case 53: return _BV( 0 ); // PB 0 ** 53 ** SPI_SS - case 54: return _BV( 0 ); // PF 0 ** 54 ** A0 - case 55: return _BV( 1 ); // PF 1 ** 55 ** A1 - case 56: return _BV( 2 ); // PF 2 ** 56 ** A2 - case 57: return _BV( 3 ); // PF 3 ** 57 ** A3 - case 58: return _BV( 4 ); // PF 4 ** 58 ** A4 - case 59: return _BV( 5 ); // PF 5 ** 59 ** A5 - case 60: return _BV( 6 ); // PF 6 ** 60 ** A6 - case 61: return _BV( 7 ); // PF 7 ** 61 ** A7 - case 62: return _BV( 0 ); // PK 0 ** 62 ** A8 - case 63: return _BV( 1 ); // PK 1 ** 63 ** A9 - case 64: return _BV( 2 ); // PK 2 ** 64 ** A10 - case 65: return _BV( 3 ); // PK 3 ** 65 ** A11 - case 66: return _BV( 4 ); // PK 4 ** 66 ** A12 - case 67: return _BV( 5 ); // PK 5 ** 67 ** A13 - case 68: return _BV( 6 ); // PK 6 ** 68 ** A14 - case 69: return _BV( 7 ); // PK 7 ** 69 ** A15 - default: - // TODO: add error here - invalidPinSpecified(); - } -} - -INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) -{ - switch(pin) { - case 2: return TIMER3B; // PE 4 ** 2 ** PWM2 - case 3: return TIMER3C; // PE 5 ** 3 ** PWM3 - case 4: return TIMER0B; // PG 5 ** 4 ** PWM4 - case 5: return TIMER3A; // PE 3 ** 5 ** PWM5 - case 6: return TIMER4A; // PH 3 ** 6 ** PWM6 - case 7: return TIMER4B; // PH 4 ** 7 ** PWM7 - case 8: return TIMER4C; // PH 5 ** 8 ** PWM8 - case 9: return TIMER2B; // PH 6 ** 9 ** PWM9 - case 10: return TIMER2A; // PB 4 ** 10 ** PWM10 - case 11: return TIMER1A; // PB 5 ** 11 ** PWM11 - case 12: return TIMER1B; // PB 6 ** 12 ** PWM12 - case 13: return TIMER0A; // PB 7 ** 13 ** PWM13 - case 44: return TIMER5C; // PL 5 ** 44 ** D44 - case 45: return TIMER5B; // PL 4 ** 45 ** D45 - case 46: return TIMER5A; // PL 3 ** 46 ** D46 - default: return NOT_ON_TIMER; - } -} - -#else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - -INLINED volatile uint8_t *inlined_portModeRegister(uint8_t port_index) -{ - switch (port_index) { - case 2: return &DDRB; - case 3: return &DDRC; - case 4: return &DDRD; - default: invalidPinSpecified(); - } -} - -INLINED volatile uint8_t *inlined_portOutputRegister(uint8_t port_index) -{ - switch (port_index) { - case 2: return &PORTB; - case 3: return &PORTC; - case 4: return &PORTD; - default: invalidPinSpecified(); - } -} - -INLINED volatile uint8_t *inlined_portInputRegister(uint8_t port_index) -{ - switch (port_index) { - case 2: return &PINB; - case 3: return &PINC; - case 4: return &PIND; - default: invalidPinSpecified(); - } -} - -INLINED uint8_t inlined_digitalPinToPort(uint8_t pin) -{ - switch(pin) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - return PORT_INDEX_PD; - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - return PORT_INDEX_PB; - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - return PORT_INDEX_PC; - default: - invalidPinSpecified(); - } -} - -INLINED uint8_t inlined_digitalPinToBitMask(uint8_t pin) -{ - switch(pin) { - case 0: return _BV(0); /* 0, port D */ - case 1: return _BV(1); - case 2: return _BV(2); - case 3: return _BV(3); - case 4: return _BV(4); - case 5: return _BV(5); - case 6: return _BV(6); - case 7: return _BV(7); - case 8: return _BV(0); /* 8, port B */ - case 9: return _BV(1); - case 10: return _BV(2); - case 11: return _BV(3); - case 12: return _BV(4); - case 13: return _BV(5); - case 14: return _BV(0); /* 14, port C */ - case 15: return _BV(1); - case 16: return _BV(2); - case 17: return _BV(3); - case 18: return _BV(4); - case 19: return _BV(5); - default: - // TODO: throw error here - invalidPinSpecified(); - } -} - -INLINED uint8_t inlined_digitalPinToTimer(uint8_t pin) -{ - switch(pin) { -#if defined(__AVR_ATmega8__) - case 11: return TIMER2; -#else - case 3: return TIMER2B; - case 5: return TIMER0B; - case 6: return TIMER0A; - case 11: return TIMER2A; -#endif - case 9: return TIMER1A; - case 10: return TIMER1B; - default: return NOT_ON_TIMER; - } -} - -#endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - #endif diff --git a/cores/arduino/wiring_digital.c b/cores/arduino/wiring_digital.c index 95666b1..dd1b949 100755 --- a/cores/arduino/wiring_digital.c +++ b/cores/arduino/wiring_digital.c @@ -27,7 +27,7 @@ #include "wiring_private.h" #include "pins_arduino.h" -void pinMode_lookup(uint8_t pin, uint8_t mode) +void pinMode(uint8_t pin, uint8_t mode) { uint8_t bit = digitalPinToBitMask(pin); uint8_t port = digitalPinToPort(pin); @@ -121,23 +121,7 @@ static void turnOffPWM(uint8_t timer) } } -void __digitalWriteOR_locked(volatile uint8_t*out, uint8_t bit) -{ - uint8_t oldSREG = SREG; - cli(); - *out |= bit; - SREG=oldSREG; -} - -void __digitalWriteAND_locked(volatile uint8_t*out, uint8_t bit) -{ - uint8_t oldSREG = SREG; - cli(); - *out &= bit; // NOTE - no inversion here, invert before calling!!! - SREG=oldSREG; -} - -void digitalWrite_lookup(uint8_t pin, uint8_t val) +void digitalWrite(uint8_t pin, uint8_t val) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); @@ -164,7 +148,7 @@ void digitalWrite_lookup(uint8_t pin, uint8_t val) SREG = oldSREG; } -int digitalRead_lookup(uint8_t pin) +int digitalRead(uint8_t pin) { uint8_t timer = digitalPinToTimer(pin); uint8_t bit = digitalPinToBitMask(pin); From b0ab2bc48bd3edd3b42d3a52f0995f220f77f814 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 3 Mar 2011 18:57:05 -0500 Subject: [PATCH 12/54] Rearranging internal #defines in headers. --- cores/arduino/pins_arduino.h | 26 -------------------------- cores/arduino/wiring_private.h | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 98af18e..4f0c1c3 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -27,32 +27,6 @@ #include -#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 - -#define TIMER3A 8 -#define TIMER3B 9 -#define TIMER3C 10 -#define TIMER4A 11 -#define TIMER4B 12 -#define TIMER4C 13 -#define TIMER5A 14 -#define TIMER5B 15 -#define TIMER5C 16 - -#ifndef INLINED -#define INLINED static __attribute__((always_inline)) inline -#endif - #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) const static uint8_t SS = 53; const static uint8_t MOSI = 51; diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index 74c0d06..b131ba0 100755 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -44,6 +44,28 @@ extern "C"{ #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif +#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 + +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER5A 14 +#define TIMER5B 15 +#define TIMER5C 16 + #define EXTERNAL_INT_0 0 #define EXTERNAL_INT_1 1 #define EXTERNAL_INT_2 2 From 6cd58c57dbf8b52d94b4fda3cb565856530b377d Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 3 Mar 2011 23:54:33 -0500 Subject: [PATCH 13/54] Moving all pin definitions into pins_arduino.h. This is a step towards providing portability across AVR's by simply including an appropriate header file. --- cores/arduino/Arduino.h | 30 ++- cores/arduino/main.cpp | 1 + cores/arduino/pins_arduino.c | 465 --------------------------------- cores/arduino/pins_arduino.h | 442 +++++++++++++++++++++++++++++++ cores/arduino/wiring_private.h | 22 -- 5 files changed, 469 insertions(+), 491 deletions(-) delete mode 100755 cores/arduino/pins_arduino.c diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index 713347b..e877970 100755 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -5,13 +5,11 @@ #include #include -#include - +#include #include #include -#include + #include "binary.h" -#include "pins_arduino.h" #ifdef __cplusplus extern "C"{ @@ -141,6 +139,28 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; #define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) ) #define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) ) +#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 + +#define TIMER3A 8 +#define TIMER3B 9 +#define TIMER3C 10 +#define TIMER4A 11 +#define TIMER4B 12 +#define TIMER4C 13 +#define TIMER5A 14 +#define TIMER5B 15 +#define TIMER5C 16 + #ifdef __cplusplus } // extern "C" #endif @@ -168,4 +188,6 @@ long map(long, long, long, long, long); #endif +#include "pins_arduino.h" + #endif \ No newline at end of file diff --git a/cores/arduino/main.cpp b/cores/arduino/main.cpp index a806ebc..3c46f1e 100755 --- a/cores/arduino/main.cpp +++ b/cores/arduino/main.cpp @@ -1,3 +1,4 @@ +#define ARDUINO_MAIN #include int main(void) diff --git a/cores/arduino/pins_arduino.c b/cores/arduino/pins_arduino.c deleted file mode 100755 index 0c816e9..0000000 --- a/cores/arduino/pins_arduino.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - 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$ -*/ - -#include -#include "wiring_private.h" -#include "pins_arduino.h" - -// On the Arduino board, digital pins are also used -// for the analog output (software PWM). Analog input -// pins are a separate set. - -// ATMEL ATMEGA8 & 168 / ARDUINO -// -// +-\/-+ -// PC6 1| |28 PC5 (AI 5) -// (D 0) PD0 2| |27 PC4 (AI 4) -// (D 1) PD1 3| |26 PC3 (AI 3) -// (D 2) PD2 4| |25 PC2 (AI 2) -// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) -// (D 4) PD4 6| |23 PC0 (AI 0) -// VCC 7| |22 GND -// GND 8| |21 AREF -// PB6 9| |20 AVCC -// PB7 10| |19 PB5 (D 13) -// PWM+ (D 5) PD5 11| |18 PB4 (D 12) -// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM -// (D 7) PD7 13| |16 PB2 (D 10) PWM -// (D 8) PB0 14| |15 PB1 (D 9) PWM -// +----+ -// -// (PWM+ indicates the additional PWM pins on the ATmega168.) - -// ATMEL ATMEGA1280 / ARDUINO -// -// 0-7 PE0-PE7 works -// 8-13 PB0-PB5 works -// 14-21 PA0-PA7 works -// 22-29 PH0-PH7 works -// 30-35 PG5-PG0 works -// 36-43 PC7-PC0 works -// 44-51 PJ7-PJ0 works -// 52-59 PL7-PL0 works -// 60-67 PD7-PD0 works -// A0-A7 PF0-PF7 -// A8-A15 PK0-PK7 - -#define PA 1 -#define PB 2 -#define PC 3 -#define PD 4 -#define PE 5 -#define PF 6 -#define PG 7 -#define PH 8 -#define PJ 10 -#define PK 11 -#define PL 12 - - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - &DDRA, - &DDRB, - &DDRC, - &DDRD, - &DDRE, - &DDRF, - &DDRG, - &DDRH, - NOT_A_PORT, - &DDRJ, - &DDRK, - &DDRL, -}; - -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - &PORTA, - &PORTB, - &PORTC, - &PORTD, - &PORTE, - &PORTF, - &PORTG, - &PORTH, - NOT_A_PORT, - &PORTJ, - &PORTK, - &PORTL, -}; - -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PIN, - &PINA, - &PINB, - &PINC, - &PIND, - &PINE, - &PINF, - &PING, - &PINH, - NOT_A_PIN, - &PINJ, - &PINK, - &PINL, -}; - -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - // PORTLIST - // ------------------------------------------- - PE , // PE 0 ** 0 ** USART0_RX - PE , // PE 1 ** 1 ** USART0_TX - PE , // PE 4 ** 2 ** PWM2 - PE , // PE 5 ** 3 ** PWM3 - PG , // PG 5 ** 4 ** PWM4 - PE , // PE 3 ** 5 ** PWM5 - PH , // PH 3 ** 6 ** PWM6 - PH , // PH 4 ** 7 ** PWM7 - PH , // PH 5 ** 8 ** PWM8 - PH , // PH 6 ** 9 ** PWM9 - PB , // PB 4 ** 10 ** PWM10 - PB , // PB 5 ** 11 ** PWM11 - PB , // PB 6 ** 12 ** PWM12 - PB , // PB 7 ** 13 ** PWM13 - PJ , // PJ 1 ** 14 ** USART3_TX - PJ , // PJ 0 ** 15 ** USART3_RX - PH , // PH 1 ** 16 ** USART2_TX - PH , // PH 0 ** 17 ** USART2_RX - PD , // PD 3 ** 18 ** USART1_TX - PD , // PD 2 ** 19 ** USART1_RX - PD , // PD 1 ** 20 ** I2C_SDA - PD , // PD 0 ** 21 ** I2C_SCL - PA , // PA 0 ** 22 ** D22 - PA , // PA 1 ** 23 ** D23 - PA , // PA 2 ** 24 ** D24 - PA , // PA 3 ** 25 ** D25 - PA , // PA 4 ** 26 ** D26 - PA , // PA 5 ** 27 ** D27 - PA , // PA 6 ** 28 ** D28 - PA , // PA 7 ** 29 ** D29 - PC , // PC 7 ** 30 ** D30 - PC , // PC 6 ** 31 ** D31 - PC , // PC 5 ** 32 ** D32 - PC , // PC 4 ** 33 ** D33 - PC , // PC 3 ** 34 ** D34 - PC , // PC 2 ** 35 ** D35 - PC , // PC 1 ** 36 ** D36 - PC , // PC 0 ** 37 ** D37 - PD , // PD 7 ** 38 ** D38 - PG , // PG 2 ** 39 ** D39 - PG , // PG 1 ** 40 ** D40 - PG , // PG 0 ** 41 ** D41 - PL , // PL 7 ** 42 ** D42 - PL , // PL 6 ** 43 ** D43 - PL , // PL 5 ** 44 ** D44 - PL , // PL 4 ** 45 ** D45 - PL , // PL 3 ** 46 ** D46 - PL , // PL 2 ** 47 ** D47 - PL , // PL 1 ** 48 ** D48 - PL , // PL 0 ** 49 ** D49 - PB , // PB 3 ** 50 ** SPI_MISO - PB , // PB 2 ** 51 ** SPI_MOSI - PB , // PB 1 ** 52 ** SPI_SCK - PB , // PB 0 ** 53 ** SPI_SS - PF , // PF 0 ** 54 ** A0 - PF , // PF 1 ** 55 ** A1 - PF , // PF 2 ** 56 ** A2 - PF , // PF 3 ** 57 ** A3 - PF , // PF 4 ** 58 ** A4 - PF , // PF 5 ** 59 ** A5 - PF , // PF 6 ** 60 ** A6 - PF , // PF 7 ** 61 ** A7 - PK , // PK 0 ** 62 ** A8 - PK , // PK 1 ** 63 ** A9 - PK , // PK 2 ** 64 ** A10 - PK , // PK 3 ** 65 ** A11 - PK , // PK 4 ** 66 ** A12 - PK , // PK 5 ** 67 ** A13 - PK , // PK 6 ** 68 ** A14 - PK , // PK 7 ** 69 ** A15 -}; - -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - // PIN IN PORT - // ------------------------------------------- - _BV( 0 ) , // PE 0 ** 0 ** USART0_RX - _BV( 1 ) , // PE 1 ** 1 ** USART0_TX - _BV( 4 ) , // PE 4 ** 2 ** PWM2 - _BV( 5 ) , // PE 5 ** 3 ** PWM3 - _BV( 5 ) , // PG 5 ** 4 ** PWM4 - _BV( 3 ) , // PE 3 ** 5 ** PWM5 - _BV( 3 ) , // PH 3 ** 6 ** PWM6 - _BV( 4 ) , // PH 4 ** 7 ** PWM7 - _BV( 5 ) , // PH 5 ** 8 ** PWM8 - _BV( 6 ) , // PH 6 ** 9 ** PWM9 - _BV( 4 ) , // PB 4 ** 10 ** PWM10 - _BV( 5 ) , // PB 5 ** 11 ** PWM11 - _BV( 6 ) , // PB 6 ** 12 ** PWM12 - _BV( 7 ) , // PB 7 ** 13 ** PWM13 - _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX - _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX - _BV( 1 ) , // PH 1 ** 16 ** USART2_TX - _BV( 0 ) , // PH 0 ** 17 ** USART2_RX - _BV( 3 ) , // PD 3 ** 18 ** USART1_TX - _BV( 2 ) , // PD 2 ** 19 ** USART1_RX - _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA - _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL - _BV( 0 ) , // PA 0 ** 22 ** D22 - _BV( 1 ) , // PA 1 ** 23 ** D23 - _BV( 2 ) , // PA 2 ** 24 ** D24 - _BV( 3 ) , // PA 3 ** 25 ** D25 - _BV( 4 ) , // PA 4 ** 26 ** D26 - _BV( 5 ) , // PA 5 ** 27 ** D27 - _BV( 6 ) , // PA 6 ** 28 ** D28 - _BV( 7 ) , // PA 7 ** 29 ** D29 - _BV( 7 ) , // PC 7 ** 30 ** D30 - _BV( 6 ) , // PC 6 ** 31 ** D31 - _BV( 5 ) , // PC 5 ** 32 ** D32 - _BV( 4 ) , // PC 4 ** 33 ** D33 - _BV( 3 ) , // PC 3 ** 34 ** D34 - _BV( 2 ) , // PC 2 ** 35 ** D35 - _BV( 1 ) , // PC 1 ** 36 ** D36 - _BV( 0 ) , // PC 0 ** 37 ** D37 - _BV( 7 ) , // PD 7 ** 38 ** D38 - _BV( 2 ) , // PG 2 ** 39 ** D39 - _BV( 1 ) , // PG 1 ** 40 ** D40 - _BV( 0 ) , // PG 0 ** 41 ** D41 - _BV( 7 ) , // PL 7 ** 42 ** D42 - _BV( 6 ) , // PL 6 ** 43 ** D43 - _BV( 5 ) , // PL 5 ** 44 ** D44 - _BV( 4 ) , // PL 4 ** 45 ** D45 - _BV( 3 ) , // PL 3 ** 46 ** D46 - _BV( 2 ) , // PL 2 ** 47 ** D47 - _BV( 1 ) , // PL 1 ** 48 ** D48 - _BV( 0 ) , // PL 0 ** 49 ** D49 - _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO - _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI - _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK - _BV( 0 ) , // PB 0 ** 53 ** SPI_SS - _BV( 0 ) , // PF 0 ** 54 ** A0 - _BV( 1 ) , // PF 1 ** 55 ** A1 - _BV( 2 ) , // PF 2 ** 56 ** A2 - _BV( 3 ) , // PF 3 ** 57 ** A3 - _BV( 4 ) , // PF 4 ** 58 ** A4 - _BV( 5 ) , // PF 5 ** 59 ** A5 - _BV( 6 ) , // PF 6 ** 60 ** A6 - _BV( 7 ) , // PF 7 ** 61 ** A7 - _BV( 0 ) , // PK 0 ** 62 ** A8 - _BV( 1 ) , // PK 1 ** 63 ** A9 - _BV( 2 ) , // PK 2 ** 64 ** A10 - _BV( 3 ) , // PK 3 ** 65 ** A11 - _BV( 4 ) , // PK 4 ** 66 ** A12 - _BV( 5 ) , // PK 5 ** 67 ** A13 - _BV( 6 ) , // PK 6 ** 68 ** A14 - _BV( 7 ) , // PK 7 ** 69 ** A15 -}; - -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - // TIMERS - // ------------------------------------------- - NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX - NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX - TIMER3B , // PE 4 ** 2 ** PWM2 - TIMER3C , // PE 5 ** 3 ** PWM3 - TIMER0B , // PG 5 ** 4 ** PWM4 - TIMER3A , // PE 3 ** 5 ** PWM5 - TIMER4A , // PH 3 ** 6 ** PWM6 - TIMER4B , // PH 4 ** 7 ** PWM7 - TIMER4C , // PH 5 ** 8 ** PWM8 - TIMER2B , // PH 6 ** 9 ** PWM9 - TIMER2A , // PB 4 ** 10 ** PWM10 - TIMER1A , // PB 5 ** 11 ** PWM11 - TIMER1B , // PB 6 ** 12 ** PWM12 - TIMER0A , // PB 7 ** 13 ** PWM13 - NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX - NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX - NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX - NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX - NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX - NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX - NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA - NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL - NOT_ON_TIMER , // PA 0 ** 22 ** D22 - NOT_ON_TIMER , // PA 1 ** 23 ** D23 - NOT_ON_TIMER , // PA 2 ** 24 ** D24 - NOT_ON_TIMER , // PA 3 ** 25 ** D25 - NOT_ON_TIMER , // PA 4 ** 26 ** D26 - NOT_ON_TIMER , // PA 5 ** 27 ** D27 - NOT_ON_TIMER , // PA 6 ** 28 ** D28 - NOT_ON_TIMER , // PA 7 ** 29 ** D29 - NOT_ON_TIMER , // PC 7 ** 30 ** D30 - NOT_ON_TIMER , // PC 6 ** 31 ** D31 - NOT_ON_TIMER , // PC 5 ** 32 ** D32 - NOT_ON_TIMER , // PC 4 ** 33 ** D33 - NOT_ON_TIMER , // PC 3 ** 34 ** D34 - NOT_ON_TIMER , // PC 2 ** 35 ** D35 - NOT_ON_TIMER , // PC 1 ** 36 ** D36 - NOT_ON_TIMER , // PC 0 ** 37 ** D37 - NOT_ON_TIMER , // PD 7 ** 38 ** D38 - NOT_ON_TIMER , // PG 2 ** 39 ** D39 - NOT_ON_TIMER , // PG 1 ** 40 ** D40 - NOT_ON_TIMER , // PG 0 ** 41 ** D41 - NOT_ON_TIMER , // PL 7 ** 42 ** D42 - NOT_ON_TIMER , // PL 6 ** 43 ** D43 - TIMER5C , // PL 5 ** 44 ** D44 - TIMER5B , // PL 4 ** 45 ** D45 - TIMER5A , // PL 3 ** 46 ** D46 - NOT_ON_TIMER , // PL 2 ** 47 ** D47 - NOT_ON_TIMER , // PL 1 ** 48 ** D48 - NOT_ON_TIMER , // PL 0 ** 49 ** D49 - NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO - NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI - NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK - NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS - NOT_ON_TIMER , // PF 0 ** 54 ** A0 - NOT_ON_TIMER , // PF 1 ** 55 ** A1 - NOT_ON_TIMER , // PF 2 ** 56 ** A2 - NOT_ON_TIMER , // PF 3 ** 57 ** A3 - NOT_ON_TIMER , // PF 4 ** 58 ** A4 - NOT_ON_TIMER , // PF 5 ** 59 ** A5 - NOT_ON_TIMER , // PF 6 ** 60 ** A6 - NOT_ON_TIMER , // PF 7 ** 61 ** A7 - NOT_ON_TIMER , // PK 0 ** 62 ** A8 - NOT_ON_TIMER , // PK 1 ** 63 ** A9 - NOT_ON_TIMER , // PK 2 ** 64 ** A10 - NOT_ON_TIMER , // PK 3 ** 65 ** A11 - NOT_ON_TIMER , // PK 4 ** 66 ** A12 - NOT_ON_TIMER , // PK 5 ** 67 ** A13 - NOT_ON_TIMER , // PK 6 ** 68 ** A14 - NOT_ON_TIMER , // PK 7 ** 69 ** A15 -}; -#else -// these arrays map port names (e.g. port B) to the -// appropriate addresses for various functions (e.g. reading -// and writing) -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - &DDRB, - &DDRC, - &DDRD, -}; - -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - &PORTB, - &PORTC, - &PORTD, -}; - -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - &PINB, - &PINC, - &PIND, -}; - -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - PD, /* 0 */ - PD, - PD, - PD, - PD, - PD, - PD, - PD, - PB, /* 8 */ - PB, - PB, - PB, - PB, - PB, - PC, /* 14 */ - PC, - PC, - PC, - PC, - PC, -}; - -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - _BV(0), /* 0, port D */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(6), - _BV(7), - _BV(0), /* 8, port B */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(0), /* 14, port C */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), -}; - -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - NOT_ON_TIMER, /* 0 - port D */ - NOT_ON_TIMER, - NOT_ON_TIMER, - // on the ATmega168, digital pin 3 has hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, -#else - TIMER2B, -#endif - NOT_ON_TIMER, - // on the ATmega168, digital pins 5 and 6 have hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, - NOT_ON_TIMER, -#else - TIMER0B, - TIMER0A, -#endif - NOT_ON_TIMER, - NOT_ON_TIMER, /* 8 - port B */ - TIMER1A, - TIMER1B, -#if defined(__AVR_ATmega8__) - TIMER2, -#else - TIMER2A, -#endif - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, /* 14 - port C */ - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, -}; -#endif diff --git a/cores/arduino/pins_arduino.h b/cores/arduino/pins_arduino.h index 4f0c1c3..169e734 100644 --- a/cores/arduino/pins_arduino.h +++ b/cores/arduino/pins_arduino.h @@ -67,4 +67,446 @@ const static uint8_t A6 = 20; const static uint8_t A7 = 21; #endif +#ifdef ARDUINO_MAIN + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA8 & 168 / ARDUINO +// +// +-\/-+ +// PC6 1| |28 PC5 (AI 5) +// (D 0) PD0 2| |27 PC4 (AI 4) +// (D 1) PD1 3| |26 PC3 (AI 3) +// (D 2) PD2 4| |25 PC2 (AI 2) +// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) +// (D 4) PD4 6| |23 PC0 (AI 0) +// VCC 7| |22 GND +// GND 8| |21 AREF +// PB6 9| |20 AVCC +// PB7 10| |19 PB5 (D 13) +// PWM+ (D 5) PD5 11| |18 PB4 (D 12) +// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM +// (D 7) PD7 13| |16 PB2 (D 10) PWM +// (D 8) PB0 14| |15 PB1 (D 9) PWM +// +----+ +// +// (PWM+ indicates the additional PWM pins on the ATmega168.) + +// ATMEL ATMEGA1280 / ARDUINO +// +// 0-7 PE0-PE7 works +// 8-13 PB0-PB5 works +// 14-21 PA0-PA7 works +// 22-29 PH0-PH7 works +// 30-35 PG5-PG0 works +// 36-43 PC7-PC0 works +// 44-51 PJ7-PJ0 works +// 52-59 PL7-PL0 works +// 60-67 PD7-PD0 works +// A0-A7 PF0-PF7 +// A8-A15 PK0-PK7 + +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + + +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + (uint16_t) &DDRA, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, + (uint16_t) &DDRE, + (uint16_t) &DDRF, + (uint16_t) &DDRG, + (uint16_t) &DDRH, + NOT_A_PORT, + (uint16_t) &DDRJ, + (uint16_t) &DDRK, + (uint16_t) &DDRL, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + (uint16_t) &PORTA, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, + (uint16_t) &PORTE, + (uint16_t) &PORTF, + (uint16_t) &PORTG, + (uint16_t) &PORTH, + NOT_A_PORT, + (uint16_t) &PORTJ, + (uint16_t) &PORTK, + (uint16_t) &PORTL, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PIN, + (uint16_t) &PINA, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, + (uint16_t) &PINE, + (uint16_t) &PINF, + (uint16_t) &PING, + (uint16_t) &PINH, + NOT_A_PIN, + (uint16_t) &PINJ, + (uint16_t) &PINK, + (uint16_t) &PINL, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + // PORTLIST + // ------------------------------------------- + PE , // PE 0 ** 0 ** USART0_RX + PE , // PE 1 ** 1 ** USART0_TX + PE , // PE 4 ** 2 ** PWM2 + PE , // PE 5 ** 3 ** PWM3 + PG , // PG 5 ** 4 ** PWM4 + PE , // PE 3 ** 5 ** PWM5 + PH , // PH 3 ** 6 ** PWM6 + PH , // PH 4 ** 7 ** PWM7 + PH , // PH 5 ** 8 ** PWM8 + PH , // PH 6 ** 9 ** PWM9 + PB , // PB 4 ** 10 ** PWM10 + PB , // PB 5 ** 11 ** PWM11 + PB , // PB 6 ** 12 ** PWM12 + PB , // PB 7 ** 13 ** PWM13 + PJ , // PJ 1 ** 14 ** USART3_TX + PJ , // PJ 0 ** 15 ** USART3_RX + PH , // PH 1 ** 16 ** USART2_TX + PH , // PH 0 ** 17 ** USART2_RX + PD , // PD 3 ** 18 ** USART1_TX + PD , // PD 2 ** 19 ** USART1_RX + PD , // PD 1 ** 20 ** I2C_SDA + PD , // PD 0 ** 21 ** I2C_SCL + PA , // PA 0 ** 22 ** D22 + PA , // PA 1 ** 23 ** D23 + PA , // PA 2 ** 24 ** D24 + PA , // PA 3 ** 25 ** D25 + PA , // PA 4 ** 26 ** D26 + PA , // PA 5 ** 27 ** D27 + PA , // PA 6 ** 28 ** D28 + PA , // PA 7 ** 29 ** D29 + PC , // PC 7 ** 30 ** D30 + PC , // PC 6 ** 31 ** D31 + PC , // PC 5 ** 32 ** D32 + PC , // PC 4 ** 33 ** D33 + PC , // PC 3 ** 34 ** D34 + PC , // PC 2 ** 35 ** D35 + PC , // PC 1 ** 36 ** D36 + PC , // PC 0 ** 37 ** D37 + PD , // PD 7 ** 38 ** D38 + PG , // PG 2 ** 39 ** D39 + PG , // PG 1 ** 40 ** D40 + PG , // PG 0 ** 41 ** D41 + PL , // PL 7 ** 42 ** D42 + PL , // PL 6 ** 43 ** D43 + PL , // PL 5 ** 44 ** D44 + PL , // PL 4 ** 45 ** D45 + PL , // PL 3 ** 46 ** D46 + PL , // PL 2 ** 47 ** D47 + PL , // PL 1 ** 48 ** D48 + PL , // PL 0 ** 49 ** D49 + PB , // PB 3 ** 50 ** SPI_MISO + PB , // PB 2 ** 51 ** SPI_MOSI + PB , // PB 1 ** 52 ** SPI_SCK + PB , // PB 0 ** 53 ** SPI_SS + PF , // PF 0 ** 54 ** A0 + PF , // PF 1 ** 55 ** A1 + PF , // PF 2 ** 56 ** A2 + PF , // PF 3 ** 57 ** A3 + PF , // PF 4 ** 58 ** A4 + PF , // PF 5 ** 59 ** A5 + PF , // PF 6 ** 60 ** A6 + PF , // PF 7 ** 61 ** A7 + PK , // PK 0 ** 62 ** A8 + PK , // PK 1 ** 63 ** A9 + PK , // PK 2 ** 64 ** A10 + PK , // PK 3 ** 65 ** A11 + PK , // PK 4 ** 66 ** A12 + PK , // PK 5 ** 67 ** A13 + PK , // PK 6 ** 68 ** A14 + PK , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + // PIN IN PORT + // ------------------------------------------- + _BV( 0 ) , // PE 0 ** 0 ** USART0_RX + _BV( 1 ) , // PE 1 ** 1 ** USART0_TX + _BV( 4 ) , // PE 4 ** 2 ** PWM2 + _BV( 5 ) , // PE 5 ** 3 ** PWM3 + _BV( 5 ) , // PG 5 ** 4 ** PWM4 + _BV( 3 ) , // PE 3 ** 5 ** PWM5 + _BV( 3 ) , // PH 3 ** 6 ** PWM6 + _BV( 4 ) , // PH 4 ** 7 ** PWM7 + _BV( 5 ) , // PH 5 ** 8 ** PWM8 + _BV( 6 ) , // PH 6 ** 9 ** PWM9 + _BV( 4 ) , // PB 4 ** 10 ** PWM10 + _BV( 5 ) , // PB 5 ** 11 ** PWM11 + _BV( 6 ) , // PB 6 ** 12 ** PWM12 + _BV( 7 ) , // PB 7 ** 13 ** PWM13 + _BV( 1 ) , // PJ 1 ** 14 ** USART3_TX + _BV( 0 ) , // PJ 0 ** 15 ** USART3_RX + _BV( 1 ) , // PH 1 ** 16 ** USART2_TX + _BV( 0 ) , // PH 0 ** 17 ** USART2_RX + _BV( 3 ) , // PD 3 ** 18 ** USART1_TX + _BV( 2 ) , // PD 2 ** 19 ** USART1_RX + _BV( 1 ) , // PD 1 ** 20 ** I2C_SDA + _BV( 0 ) , // PD 0 ** 21 ** I2C_SCL + _BV( 0 ) , // PA 0 ** 22 ** D22 + _BV( 1 ) , // PA 1 ** 23 ** D23 + _BV( 2 ) , // PA 2 ** 24 ** D24 + _BV( 3 ) , // PA 3 ** 25 ** D25 + _BV( 4 ) , // PA 4 ** 26 ** D26 + _BV( 5 ) , // PA 5 ** 27 ** D27 + _BV( 6 ) , // PA 6 ** 28 ** D28 + _BV( 7 ) , // PA 7 ** 29 ** D29 + _BV( 7 ) , // PC 7 ** 30 ** D30 + _BV( 6 ) , // PC 6 ** 31 ** D31 + _BV( 5 ) , // PC 5 ** 32 ** D32 + _BV( 4 ) , // PC 4 ** 33 ** D33 + _BV( 3 ) , // PC 3 ** 34 ** D34 + _BV( 2 ) , // PC 2 ** 35 ** D35 + _BV( 1 ) , // PC 1 ** 36 ** D36 + _BV( 0 ) , // PC 0 ** 37 ** D37 + _BV( 7 ) , // PD 7 ** 38 ** D38 + _BV( 2 ) , // PG 2 ** 39 ** D39 + _BV( 1 ) , // PG 1 ** 40 ** D40 + _BV( 0 ) , // PG 0 ** 41 ** D41 + _BV( 7 ) , // PL 7 ** 42 ** D42 + _BV( 6 ) , // PL 6 ** 43 ** D43 + _BV( 5 ) , // PL 5 ** 44 ** D44 + _BV( 4 ) , // PL 4 ** 45 ** D45 + _BV( 3 ) , // PL 3 ** 46 ** D46 + _BV( 2 ) , // PL 2 ** 47 ** D47 + _BV( 1 ) , // PL 1 ** 48 ** D48 + _BV( 0 ) , // PL 0 ** 49 ** D49 + _BV( 3 ) , // PB 3 ** 50 ** SPI_MISO + _BV( 2 ) , // PB 2 ** 51 ** SPI_MOSI + _BV( 1 ) , // PB 1 ** 52 ** SPI_SCK + _BV( 0 ) , // PB 0 ** 53 ** SPI_SS + _BV( 0 ) , // PF 0 ** 54 ** A0 + _BV( 1 ) , // PF 1 ** 55 ** A1 + _BV( 2 ) , // PF 2 ** 56 ** A2 + _BV( 3 ) , // PF 3 ** 57 ** A3 + _BV( 4 ) , // PF 4 ** 58 ** A4 + _BV( 5 ) , // PF 5 ** 59 ** A5 + _BV( 6 ) , // PF 6 ** 60 ** A6 + _BV( 7 ) , // PF 7 ** 61 ** A7 + _BV( 0 ) , // PK 0 ** 62 ** A8 + _BV( 1 ) , // PK 1 ** 63 ** A9 + _BV( 2 ) , // PK 2 ** 64 ** A10 + _BV( 3 ) , // PK 3 ** 65 ** A11 + _BV( 4 ) , // PK 4 ** 66 ** A12 + _BV( 5 ) , // PK 5 ** 67 ** A13 + _BV( 6 ) , // PK 6 ** 68 ** A14 + _BV( 7 ) , // PK 7 ** 69 ** A15 +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + // TIMERS + // ------------------------------------------- + NOT_ON_TIMER , // PE 0 ** 0 ** USART0_RX + NOT_ON_TIMER , // PE 1 ** 1 ** USART0_TX + TIMER3B , // PE 4 ** 2 ** PWM2 + TIMER3C , // PE 5 ** 3 ** PWM3 + TIMER0B , // PG 5 ** 4 ** PWM4 + TIMER3A , // PE 3 ** 5 ** PWM5 + TIMER4A , // PH 3 ** 6 ** PWM6 + TIMER4B , // PH 4 ** 7 ** PWM7 + TIMER4C , // PH 5 ** 8 ** PWM8 + TIMER2B , // PH 6 ** 9 ** PWM9 + TIMER2A , // PB 4 ** 10 ** PWM10 + TIMER1A , // PB 5 ** 11 ** PWM11 + TIMER1B , // PB 6 ** 12 ** PWM12 + TIMER0A , // PB 7 ** 13 ** PWM13 + NOT_ON_TIMER , // PJ 1 ** 14 ** USART3_TX + NOT_ON_TIMER , // PJ 0 ** 15 ** USART3_RX + NOT_ON_TIMER , // PH 1 ** 16 ** USART2_TX + NOT_ON_TIMER , // PH 0 ** 17 ** USART2_RX + NOT_ON_TIMER , // PD 3 ** 18 ** USART1_TX + NOT_ON_TIMER , // PD 2 ** 19 ** USART1_RX + NOT_ON_TIMER , // PD 1 ** 20 ** I2C_SDA + NOT_ON_TIMER , // PD 0 ** 21 ** I2C_SCL + NOT_ON_TIMER , // PA 0 ** 22 ** D22 + NOT_ON_TIMER , // PA 1 ** 23 ** D23 + NOT_ON_TIMER , // PA 2 ** 24 ** D24 + NOT_ON_TIMER , // PA 3 ** 25 ** D25 + NOT_ON_TIMER , // PA 4 ** 26 ** D26 + NOT_ON_TIMER , // PA 5 ** 27 ** D27 + NOT_ON_TIMER , // PA 6 ** 28 ** D28 + NOT_ON_TIMER , // PA 7 ** 29 ** D29 + NOT_ON_TIMER , // PC 7 ** 30 ** D30 + NOT_ON_TIMER , // PC 6 ** 31 ** D31 + NOT_ON_TIMER , // PC 5 ** 32 ** D32 + NOT_ON_TIMER , // PC 4 ** 33 ** D33 + NOT_ON_TIMER , // PC 3 ** 34 ** D34 + NOT_ON_TIMER , // PC 2 ** 35 ** D35 + NOT_ON_TIMER , // PC 1 ** 36 ** D36 + NOT_ON_TIMER , // PC 0 ** 37 ** D37 + NOT_ON_TIMER , // PD 7 ** 38 ** D38 + NOT_ON_TIMER , // PG 2 ** 39 ** D39 + NOT_ON_TIMER , // PG 1 ** 40 ** D40 + NOT_ON_TIMER , // PG 0 ** 41 ** D41 + NOT_ON_TIMER , // PL 7 ** 42 ** D42 + NOT_ON_TIMER , // PL 6 ** 43 ** D43 + TIMER5C , // PL 5 ** 44 ** D44 + TIMER5B , // PL 4 ** 45 ** D45 + TIMER5A , // PL 3 ** 46 ** D46 + NOT_ON_TIMER , // PL 2 ** 47 ** D47 + NOT_ON_TIMER , // PL 1 ** 48 ** D48 + NOT_ON_TIMER , // PL 0 ** 49 ** D49 + NOT_ON_TIMER , // PB 3 ** 50 ** SPI_MISO + NOT_ON_TIMER , // PB 2 ** 51 ** SPI_MOSI + NOT_ON_TIMER , // PB 1 ** 52 ** SPI_SCK + NOT_ON_TIMER , // PB 0 ** 53 ** SPI_SS + NOT_ON_TIMER , // PF 0 ** 54 ** A0 + NOT_ON_TIMER , // PF 1 ** 55 ** A1 + NOT_ON_TIMER , // PF 2 ** 56 ** A2 + NOT_ON_TIMER , // PF 3 ** 57 ** A3 + NOT_ON_TIMER , // PF 4 ** 58 ** A4 + NOT_ON_TIMER , // PF 5 ** 59 ** A5 + NOT_ON_TIMER , // PF 6 ** 60 ** A6 + NOT_ON_TIMER , // PF 7 ** 61 ** A7 + NOT_ON_TIMER , // PK 0 ** 62 ** A8 + NOT_ON_TIMER , // PK 1 ** 63 ** A9 + NOT_ON_TIMER , // PK 2 ** 64 ** A10 + NOT_ON_TIMER , // PK 3 ** 65 ** A11 + NOT_ON_TIMER , // PK 4 ** 66 ** A12 + NOT_ON_TIMER , // PK 5 ** 67 ** A13 + NOT_ON_TIMER , // PK 6 ** 68 ** A14 + NOT_ON_TIMER , // PK 7 ** 69 ** A15 +}; +#else +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, /* 0 */ + PD, + PD, + PD, + PD, + PD, + PD, + PD, + PB, /* 8 */ + PB, + PB, + PB, + PB, + PB, + PC, /* 14 */ + PC, + PC, + PC, + PC, + PC, +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(0), /* 0, port D */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(0), /* 8, port B */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(0), /* 14, port C */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, /* 0 - port D */ + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, +#else + TIMER2B, #endif + NOT_ON_TIMER, + // on the ATmega168, digital pins 5 and 6 have hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, + NOT_ON_TIMER, +#else + TIMER0B, + TIMER0A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, /* 8 - port B */ + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega8__) + TIMER2, +#else + TIMER2A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, /* 14 - port C */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; +#endif + +#endif + +#endif \ No newline at end of file diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index b131ba0..74c0d06 100755 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h @@ -44,28 +44,6 @@ extern "C"{ #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) #endif -#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 - -#define TIMER3A 8 -#define TIMER3B 9 -#define TIMER3C 10 -#define TIMER4A 11 -#define TIMER4B 12 -#define TIMER4C 13 -#define TIMER5A 14 -#define TIMER5B 15 -#define TIMER5C 16 - #define EXTERNAL_INT_0 0 #define EXTERNAL_INT_1 1 #define EXTERNAL_INT_2 2 From a19a23ff92bffd2d32fa2c2c84026bdfd711c6ac Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 4 Mar 2011 21:05:05 -0500 Subject: [PATCH 14/54] Factoring pin definitions out of the core. That is, there's now a pins/ directory in a platform, which includes multiple directories, each of which has its own pins_arduino.h. The boards.txt gets a new preferences, .build.pins, whose values is a sub-directory of the pins/ directory (possibly with a "platform:" prefix). That sub-directory is then placed in the include path during compilation. --- boards.txt | 20 +- cores/arduino/Arduino.h | 12 ++ {cores/arduino => pins/mega}/pins_arduino.h | 183 ------------------ pins/standard/pins_arduino.h | 199 ++++++++++++++++++++ 4 files changed, 229 insertions(+), 185 deletions(-) rename {cores/arduino => pins/mega}/pins_arduino.h (73%) create mode 100644 pins/standard/pins_arduino.h diff --git a/boards.txt b/boards.txt index 0ae40d3..40c13a7 100644 --- a/boards.txt +++ b/boards.txt @@ -14,6 +14,7 @@ uno.bootloader.lock_bits=0x0F uno.build.mcu=atmega328p uno.build.f_cpu=16000000L uno.build.core=arduino +uno.build.pins=standard ############################################################## @@ -34,6 +35,7 @@ atmega328.bootloader.lock_bits=0x0F atmega328.build.mcu=atmega328p atmega328.build.f_cpu=16000000L atmega328.build.core=arduino +atmega328..build.pins=standard ############################################################## @@ -54,6 +56,7 @@ diecimila.bootloader.lock_bits=0x0F diecimila.build.mcu=atmega168 diecimila.build.f_cpu=16000000L diecimila.build.core=arduino +diecimila.build.pins=standard ############################################################## @@ -74,6 +77,7 @@ mega2560.bootloader.lock_bits=0x0F mega2560.build.mcu=atmega2560 mega2560.build.f_cpu=16000000L mega2560.build.core=arduino +mega2560.build.pins=mega ############################################################## @@ -94,6 +98,7 @@ mega.bootloader.lock_bits=0x0F mega.build.mcu=atmega1280 mega.build.f_cpu=16000000L mega.build.core=arduino +mega.build.pins=mega ############################################################## @@ -114,6 +119,7 @@ mini.bootloader.lock_bits=0x0F mini.build.mcu=atmega168 mini.build.f_cpu=16000000L mini.build.core=arduino +mini.build.pins=standard ############################################################## @@ -133,7 +139,8 @@ fio.bootloader.lock_bits=0x0F fio.build.mcu=atmega328p fio.build.f_cpu=8000000L -fio.build.core=arduino:arduino +fio.build.core=arduino +fio.build.pins=standard ############################################################## @@ -155,6 +162,7 @@ bt328.bootloader.lock_bits=0x0F bt328.build.mcu=atmega328p bt328.build.f_cpu=16000000L bt328.build.core=arduino +bt328.build.pins=standard ############################################################## @@ -176,6 +184,7 @@ bt.bootloader.lock_bits=0x0F bt.build.mcu=atmega168 bt.build.f_cpu=16000000L bt.build.core=arduino +bt.build.pins=standard ############################################################## @@ -196,6 +205,7 @@ lilypad328.bootloader.lock_bits=0x0F lilypad328.build.mcu=atmega328p lilypad328.build.f_cpu=8000000L lilypad328.build.core=arduino +lilypad328.build.pins=standard ############################################################## @@ -216,6 +226,7 @@ lilypad.bootloader.lock_bits=0x0F lilypad.build.mcu=atmega168 lilypad.build.f_cpu=8000000L lilypad.build.core=arduino +lilypad.build.pins=standard ############################################################## @@ -236,6 +247,7 @@ pro5v328.bootloader.lock_bits=0x0F pro5v328.build.mcu=atmega328p pro5v328.build.f_cpu=16000000L pro5v328.build.core=arduino +pro5v328.build.pins=standard ############################################################## @@ -256,6 +268,7 @@ pro5v.bootloader.lock_bits=0x0F pro5v.build.mcu=atmega168 pro5v.build.f_cpu=16000000L pro5v.build.core=arduino +pro5v.build.pins=standard ############################################################## @@ -276,6 +289,7 @@ pro328.bootloader.lock_bits=0x0F pro328.build.mcu=atmega328p pro328.build.f_cpu=8000000L pro328.build.core=arduino +pro328.build.pins=standard ############################################################## @@ -296,6 +310,7 @@ pro.bootloader.lock_bits=0x0F pro.build.mcu=atmega168 pro.build.f_cpu=8000000L pro.build.core=arduino +pro.build.pins=standard ############################################################## @@ -316,6 +331,7 @@ atmega168.bootloader.lock_bits=0x0F atmega168.build.mcu=atmega168 atmega168.build.f_cpu=16000000L atmega168.build.core=arduino +atmega168.build.pins=standard ############################################################## @@ -335,4 +351,4 @@ atmega8.bootloader.lock_bits=0x0F atmega8.build.mcu=atmega8 atmega8.build.f_cpu=16000000L atmega8.build.core=arduino - +atmega8.build.pins=standard diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index e877970..ebdbe9a 100755 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -142,6 +142,18 @@ extern const uint8_t PROGMEM digital_pin_to_timer_PGM[]; #define NOT_A_PIN 0 #define NOT_A_PORT 0 +#define PA 1 +#define PB 2 +#define PC 3 +#define PD 4 +#define PE 5 +#define PF 6 +#define PG 7 +#define PH 8 +#define PJ 10 +#define PK 11 +#define PL 12 + #define NOT_ON_TIMER 0 #define TIMER0A 1 #define TIMER0B 2 diff --git a/cores/arduino/pins_arduino.h b/pins/mega/pins_arduino.h similarity index 73% rename from cores/arduino/pins_arduino.h rename to pins/mega/pins_arduino.h index 169e734..e3785e4 100644 --- a/cores/arduino/pins_arduino.h +++ b/pins/mega/pins_arduino.h @@ -27,19 +27,11 @@ #include -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) const static uint8_t SS = 53; const static uint8_t MOSI = 51; const static uint8_t MISO = 50; const static uint8_t SCK = 52; -#else -const static uint8_t SS = 10; -const static uint8_t MOSI = 11; -const static uint8_t MISO = 12; -const static uint8_t SCK = 13; -#endif -#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; @@ -56,72 +48,9 @@ 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 #ifdef ARDUINO_MAIN -// On the Arduino board, digital pins are also used -// for the analog output (software PWM). Analog input -// pins are a separate set. - -// ATMEL ATMEGA8 & 168 / ARDUINO -// -// +-\/-+ -// PC6 1| |28 PC5 (AI 5) -// (D 0) PD0 2| |27 PC4 (AI 4) -// (D 1) PD1 3| |26 PC3 (AI 3) -// (D 2) PD2 4| |25 PC2 (AI 2) -// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) -// (D 4) PD4 6| |23 PC0 (AI 0) -// VCC 7| |22 GND -// GND 8| |21 AREF -// PB6 9| |20 AVCC -// PB7 10| |19 PB5 (D 13) -// PWM+ (D 5) PD5 11| |18 PB4 (D 12) -// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM -// (D 7) PD7 13| |16 PB2 (D 10) PWM -// (D 8) PB0 14| |15 PB1 (D 9) PWM -// +----+ -// -// (PWM+ indicates the additional PWM pins on the ATmega168.) - -// ATMEL ATMEGA1280 / ARDUINO -// -// 0-7 PE0-PE7 works -// 8-13 PB0-PB5 works -// 14-21 PA0-PA7 works -// 22-29 PH0-PH7 works -// 30-35 PG5-PG0 works -// 36-43 PC7-PC0 works -// 44-51 PJ7-PJ0 works -// 52-59 PL7-PL0 works -// 60-67 PD7-PD0 works -// A0-A7 PF0-PF7 -// A8-A15 PK0-PK7 - -#define PA 1 -#define PB 2 -#define PC 3 -#define PD 4 -#define PE 5 -#define PF 6 -#define PG 7 -#define PH 8 -#define PJ 10 -#define PK 11 -#define PL 12 - - -#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) const uint16_t PROGMEM port_to_mode_PGM[] = { NOT_A_PORT, (uint16_t) &DDRA, @@ -394,118 +323,6 @@ const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { NOT_ON_TIMER , // PK 6 ** 68 ** A14 NOT_ON_TIMER , // PK 7 ** 69 ** A15 }; -#else -// these arrays map port names (e.g. port B) to the -// appropriate addresses for various functions (e.g. reading -// and writing) -const uint16_t PROGMEM port_to_mode_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &DDRB, - (uint16_t) &DDRC, - (uint16_t) &DDRD, -}; - -const uint16_t PROGMEM port_to_output_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PORTB, - (uint16_t) &PORTC, - (uint16_t) &PORTD, -}; - -const uint16_t PROGMEM port_to_input_PGM[] = { - NOT_A_PORT, - NOT_A_PORT, - (uint16_t) &PINB, - (uint16_t) &PINC, - (uint16_t) &PIND, -}; - -const uint8_t PROGMEM digital_pin_to_port_PGM[] = { - PD, /* 0 */ - PD, - PD, - PD, - PD, - PD, - PD, - PD, - PB, /* 8 */ - PB, - PB, - PB, - PB, - PB, - PC, /* 14 */ - PC, - PC, - PC, - PC, - PC, -}; - -const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { - _BV(0), /* 0, port D */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(6), - _BV(7), - _BV(0), /* 8, port B */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), - _BV(0), /* 14, port C */ - _BV(1), - _BV(2), - _BV(3), - _BV(4), - _BV(5), -}; - -const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { - NOT_ON_TIMER, /* 0 - port D */ - NOT_ON_TIMER, - NOT_ON_TIMER, - // on the ATmega168, digital pin 3 has hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, -#else - TIMER2B, -#endif - NOT_ON_TIMER, - // on the ATmega168, digital pins 5 and 6 have hardware pwm -#if defined(__AVR_ATmega8__) - NOT_ON_TIMER, - NOT_ON_TIMER, -#else - TIMER0B, - TIMER0A, -#endif - NOT_ON_TIMER, - NOT_ON_TIMER, /* 8 - port B */ - TIMER1A, - TIMER1B, -#if defined(__AVR_ATmega8__) - TIMER2, -#else - TIMER2A, -#endif - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, /* 14 - port C */ - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, - NOT_ON_TIMER, -}; -#endif #endif diff --git a/pins/standard/pins_arduino.h b/pins/standard/pins_arduino.h new file mode 100644 index 0000000..8fabb17 --- /dev/null +++ b/pins/standard/pins_arduino.h @@ -0,0 +1,199 @@ +/* + 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 + +const static uint8_t SS = 10; +const static uint8_t MOSI = 11; +const static uint8_t MISO = 12; +const static uint8_t SCK = 13; + +const static uint8_t 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; + +#ifdef ARDUINO_MAIN + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA8 & 168 / ARDUINO +// +// +-\/-+ +// PC6 1| |28 PC5 (AI 5) +// (D 0) PD0 2| |27 PC4 (AI 4) +// (D 1) PD1 3| |26 PC3 (AI 3) +// (D 2) PD2 4| |25 PC2 (AI 2) +// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) +// (D 4) PD4 6| |23 PC0 (AI 0) +// VCC 7| |22 GND +// GND 8| |21 AREF +// PB6 9| |20 AVCC +// PB7 10| |19 PB5 (D 13) +// PWM+ (D 5) PD5 11| |18 PB4 (D 12) +// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM +// (D 7) PD7 13| |16 PB2 (D 10) PWM +// (D 8) PB0 14| |15 PB1 (D 9) PWM +// +----+ +// +// (PWM+ indicates the additional PWM pins on the ATmega168.) + +// ATMEL ATMEGA1280 / ARDUINO +// +// 0-7 PE0-PE7 works +// 8-13 PB0-PB5 works +// 14-21 PA0-PA7 works +// 22-29 PH0-PH7 works +// 30-35 PG5-PG0 works +// 36-43 PC7-PC0 works +// 44-51 PJ7-PJ0 works +// 52-59 PL7-PL0 works +// 60-67 PD7-PD0 works +// A0-A7 PF0-PF7 +// A8-A15 PK0-PK7 + + +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, /* 0 */ + PD, + PD, + PD, + PD, + PD, + PD, + PD, + PB, /* 8 */ + PB, + PB, + PB, + PB, + PB, + PC, /* 14 */ + PC, + PC, + PC, + PC, + PC, +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(0), /* 0, port D */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(0), /* 8, port B */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(0), /* 14, port C */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, /* 0 - port D */ + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, +#else + TIMER2B, +#endif + NOT_ON_TIMER, + // on the ATmega168, digital pins 5 and 6 have hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, + NOT_ON_TIMER, +#else + TIMER0B, + TIMER0A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, /* 8 - port B */ + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega8__) + TIMER2, +#else + TIMER2A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, /* 14 - port C */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +#endif + +#endif \ No newline at end of file From d8d233ad3e4513cb5378dca459c251e0a127e129 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 5 Mar 2011 14:17:26 -0500 Subject: [PATCH 15/54] Implemented serial transmit buffering. Now Serial.write() places characters in the transmit buffer, and the data register empty interrupt reads and transmit them. Based loosely on the implementation here: ftp://wookey.org.uk/arduino. http://code.google.com/p/arduino/issues/detail?id=262 --- cores/arduino/HardwareSerial.cpp | 160 ++++++++++++++++++++++++++----- cores/arduino/HardwareSerial.h | 7 +- 2 files changed, 138 insertions(+), 29 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 7cea350..1cd8cc5 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -34,46 +34,50 @@ #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. +// using a ring buffer (I think), in which head is the index of the location +// to which to write the next incoming character and tail is the index of the +// location from which to read. #if (RAMEND < 1000) - #define RX_BUFFER_SIZE 32 + #define SERIAL_BUFFER_SIZE 16 #else - #define RX_BUFFER_SIZE 128 + #define SERIAL_BUFFER_SIZE 64 #endif struct ring_buffer { - unsigned char buffer[RX_BUFFER_SIZE]; - int head; - int tail; + unsigned char buffer[SERIAL_BUFFER_SIZE]; + volatile int head; + volatile int tail; }; #if defined(UBRRH) || defined(UBRR0H) ring_buffer rx_buffer = { { 0 }, 0, 0 }; + ring_buffer tx_buffer = { { 0 }, 0, 0 }; #endif #if defined(UBRR1H) ring_buffer rx_buffer1 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer1 = { { 0 }, 0, 0 }; #endif #if defined(UBRR2H) ring_buffer rx_buffer2 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer2 = { { 0 }, 0, 0 }; #endif #if defined(UBRR3H) ring_buffer rx_buffer3 = { { 0 }, 0, 0 }; + ring_buffer tx_buffer3 = { { 0 }, 0, 0 }; #endif -inline void store_char(unsigned char c, ring_buffer *rx_buffer) +inline void store_char(unsigned char c, ring_buffer *buffer) { - int i = (unsigned int)(rx_buffer->head + 1) % RX_BUFFER_SIZE; + int i = (unsigned int)(buffer->head + 1) % SERIAL_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; + if (i != buffer->tail) { + buffer->buffer[buffer->head] = c; + buffer->head = i; } } @@ -167,16 +171,105 @@ inline void store_char(unsigned char c, ring_buffer *rx_buffer) #endif +#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect) + #error Don't know what the Data Register Empty vector is called for the first UART +#else +#if defined(UART0_UDRE_vect) +ISR(UART0_UDRE_vect) +#elif defined(UART_UDRE_vect) +ISR(UART_UDRE_vect) +#elif defined(USART0_UDRE_vect) +ISR(USART0_UDRE_vect) +#elif defined(USART_UDRE_vect) +ISR(USART_UDRE_vect) +#endif +{ + if (tx_buffer.head == tx_buffer.tail) { + // Buffer empty, so disable interrupts +#if defined(UCSR0B) + cbi(UCSR0B, UDRIE0); +#else + cbi(UCSRB, UDRIE); +#endif + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer.buffer[tx_buffer.tail]; + tx_buffer.tail = (tx_buffer.tail + 1) % SERIAL_BUFFER_SIZE; + + #if defined(UDR0) + UDR0 = c; + #elif defined(UDR) + UDR = c; + #else + #error UDR not defined + #endif + } +} +#endif + +#ifdef USART1_UDRE_vect +ISR(USART1_UDRE_vect) +{ + if (tx_buffer1.head == tx_buffer1.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR1B, UDRIE1); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer1.buffer[tx_buffer1.tail]; + tx_buffer1.tail = (tx_buffer1.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR1 = c; + } +} +#endif + +#ifdef USART2_UDRE_vect +ISR(USART2_UDRE_vect) +{ + if (tx_buffer2.head == tx_buffer2.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR2B, UDRIE2); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer2.buffer[tx_buffer2.tail]; + tx_buffer2.tail = (tx_buffer2.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR2 = c; + } +} +#endif + +#ifdef USART3_UDRE_vect +ISR(USART3_UDRE_vect) +{ + if (tx_buffer3.head == tx_buffer3.tail) { + // Buffer empty, so disable interrupts + cbi(UCSR3B, UDRIE3); + } + else { + // There is more data in the output buffer. Send the next byte + unsigned char c = tx_buffer3.buffer[tx_buffer3.tail]; + tx_buffer3.tail = (tx_buffer3.tail + 1) % SERIAL_BUFFER_SIZE; + + UDR3 = c; + } +} +#endif + // Constructors //////////////////////////////////////////////////////////////// -HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, +HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_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) + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x) { _rx_buffer = rx_buffer; + _tx_buffer = tx_buffer; _ubrrh = ubrrh; _ubrrl = ubrrl; _ucsra = ucsra; @@ -185,7 +278,7 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, _rxen = rxen; _txen = txen; _rxcie = rxcie; - _udre = udre; + _udrie = udrie; _u2x = u2x; } @@ -220,18 +313,21 @@ void HardwareSerial::begin(long baud) sbi(*_ucsrb, _rxen); sbi(*_ucsrb, _txen); sbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); // XXX: what if there's already data in the tx buffer? } +// XXX: should we empty the rx and tx buffers here? void HardwareSerial::end() { cbi(*_ucsrb, _rxen); cbi(*_ucsrb, _txen); cbi(*_ucsrb, _rxcie); + cbi(*_ucsrb, _udrie); } int HardwareSerial::available(void) { - return (unsigned int)(RX_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % RX_BUFFER_SIZE; + return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE; } int HardwareSerial::peek(void) @@ -250,7 +346,7 @@ int HardwareSerial::read(void) return -1; } else { unsigned char c = _rx_buffer->buffer[_rx_buffer->tail]; - _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % RX_BUFFER_SIZE; + _rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE; return c; } } @@ -271,18 +367,30 @@ void HardwareSerial::flush() void HardwareSerial::write(uint8_t c) { - while (!((*_ucsra) & (1 << _udre))) + bool empty = (_tx_buffer->head == _tx_buffer->tail); + int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; + + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (i == _tx_buffer->tail) ; - - *_udr = c; + + _tx_buffer->buffer[_tx_buffer->head] = c; + _tx_buffer->head = i; + + if (empty) { + // The buffer was empty, so enable interrupt on + // USART Data Register empty. The interrupt handler will take it from there + sbi(*_ucsrb, _udrie); + } } // Preinstantiate Objects ////////////////////////////////////////////////////// #if defined(UBRRH) && defined(UBRRL) - HardwareSerial Serial(&rx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRE, U2X); + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRRH, &UBRRL, &UCSRA, &UCSRB, &UDR, RXEN, TXEN, RXCIE, UDRIE, U2X); #elif defined(UBRR0H) && defined(UBRR0L) - HardwareSerial Serial(&rx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRE0, U2X0); + HardwareSerial Serial(&rx_buffer, &tx_buffer, &UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UDR0, RXEN0, TXEN0, RXCIE0, UDRIE0, U2X0); #elif defined(USBCON) #warning no serial port defined (port 0) #else @@ -290,13 +398,13 @@ void HardwareSerial::write(uint8_t c) #endif #if defined(UBRR1H) - HardwareSerial Serial1(&rx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRE1, U2X1); + HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, &UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UDR1, RXEN1, TXEN1, RXCIE1, UDRIE1, U2X1); #endif #if defined(UBRR2H) - HardwareSerial Serial2(&rx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRE2, U2X2); + HardwareSerial Serial2(&rx_buffer2, &tx_buffer2, &UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UDR2, RXEN2, TXEN2, RXCIE2, UDRIE2, U2X2); #endif #if defined(UBRR3H) - HardwareSerial Serial3(&rx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRE3, U2X3); + HardwareSerial Serial3(&rx_buffer3, &tx_buffer3, &UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UDR3, RXEN3, TXEN3, RXCIE3, UDRIE3, U2X3); #endif #endif // whole file diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 3efa775..d229373 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -32,6 +32,7 @@ class HardwareSerial : public Stream { private: ring_buffer *_rx_buffer; + ring_buffer *_tx_buffer; volatile uint8_t *_ubrrh; volatile uint8_t *_ubrrl; volatile uint8_t *_ucsra; @@ -40,14 +41,14 @@ class HardwareSerial : public Stream uint8_t _rxen; uint8_t _txen; uint8_t _rxcie; - uint8_t _udre; + uint8_t _udrie; uint8_t _u2x; public: - HardwareSerial(ring_buffer *rx_buffer, + HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_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); + uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); void begin(long); void end(); virtual int available(void); From bc416b14bd62937a96bd6eb28d3755282fdeb941 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 6 Mar 2011 11:29:35 -0500 Subject: [PATCH 16/54] Moving TCCR1B reset into #ifdef check. --- cores/arduino/wiring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index b90d07e..ce4cad6 100755 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -212,10 +212,10 @@ void init() // note, however, that fast pwm mode can achieve a frequency of up // 8 MHz (with a 16 MHz clock) at 50% duty cycle +#if defined(TCCR1B) && defined(CS11) && defined(CS10) 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) From 01d82d82770de18628b0fc9f9be1c85c7abc294e Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 6 Mar 2011 11:47:18 -0500 Subject: [PATCH 17/54] Fixing race condition in Serial write (Brian Cook). --- cores/arduino/HardwareSerial.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 1cd8cc5..6738675 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -367,7 +367,6 @@ void HardwareSerial::flush() void HardwareSerial::write(uint8_t c) { - bool empty = (_tx_buffer->head == _tx_buffer->tail); int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to @@ -378,11 +377,7 @@ void HardwareSerial::write(uint8_t c) _tx_buffer->buffer[_tx_buffer->head] = c; _tx_buffer->head = i; - if (empty) { - // The buffer was empty, so enable interrupt on - // USART Data Register empty. The interrupt handler will take it from there - sbi(*_ucsrb, _udrie); - } + sbi(*_ucsrb, _udrie); } // Preinstantiate Objects ////////////////////////////////////////////////////// From 0ba1f0ec5040b68d2b09266c461d1a22b64c7e1b Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 6 Mar 2011 12:20:42 -0500 Subject: [PATCH 18/54] Flushing outgoing and incoming data in Serial.end(). That is, waiting for outgoing data to transmit and dropping any received data. --- cores/arduino/HardwareSerial.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 6738675..1154ae7 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -313,16 +313,22 @@ void HardwareSerial::begin(long baud) sbi(*_ucsrb, _rxen); sbi(*_ucsrb, _txen); sbi(*_ucsrb, _rxcie); - cbi(*_ucsrb, _udrie); // XXX: what if there's already data in the tx buffer? + cbi(*_ucsrb, _udrie); } -// XXX: should we empty the rx and tx buffers here? void HardwareSerial::end() { + // wait for transmission of outgoing data + while (_tx_buffer->head != _tx_buffer->tail) + ; + cbi(*_ucsrb, _rxen); cbi(*_ucsrb, _txen); cbi(*_ucsrb, _rxcie); cbi(*_ucsrb, _udrie); + + // clear any received data + _rx_buffer->head = _rx_buffer->tail; } int HardwareSerial::available(void) From ba3d26dcaee4245912e49125b847d29a771bd08b Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 9 Mar 2011 21:22:04 -0500 Subject: [PATCH 19/54] Fixing typo in boards.txt. --- boards.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards.txt b/boards.txt index 40c13a7..88a7143 100644 --- a/boards.txt +++ b/boards.txt @@ -35,7 +35,7 @@ atmega328.bootloader.lock_bits=0x0F atmega328.build.mcu=atmega328p atmega328.build.f_cpu=16000000L atmega328.build.core=arduino -atmega328..build.pins=standard +atmega328.build.pins=standard ############################################################## From 438bca3cb270b0d882b6b3b0bc42d57d72307c76 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Mar 2011 17:56:10 -0500 Subject: [PATCH 20/54] Rewrite of the String class by Paul Stoffregen. http://www.pjrc.com/teensy/string_class_experimental.html --- cores/arduino/WString.cpp | 857 +++++++++++++++++++++++++------------- cores/arduino/WString.h | 235 +++++++---- 2 files changed, 714 insertions(+), 378 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 5899798..c980e24 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -1,6 +1,8 @@ /* WString.cpp - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,427 +19,680 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include -#include "Arduino.h" #include "WString.h" -String::String( const char *value ) +/*********************************************/ +/* Constructors */ +/*********************************************/ + +String::String(const char *cstr) { - if ( value == NULL ) - value = ""; - getBuffer( _length = strlen( value ) ); - if ( _buffer != NULL ) - strcpy( _buffer, value ); + init(); + if (cstr) copy(cstr, strlen(cstr)); } -String::String( const String &value ) +String::String(const __FlashStringHelper *pgmstr) { - getBuffer( _length = value._length ); - if ( _buffer != NULL ) - strcpy( _buffer, value._buffer ); + init(); + *this = pgmstr; } -String::String( const char value ) +String::String(const String &value) { - _length = 1; - getBuffer(1); - if ( _buffer != NULL ) { - _buffer[0] = value; - _buffer[1] = 0; - } + init(); + *this = value; } -String::String( const unsigned char value ) +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String::String(String &&rval) { - _length = 1; - getBuffer(1); - if ( _buffer != NULL) { - _buffer[0] = value; - _buffer[1] = 0; - } + init(); + move(rval); +} +String::String(StringSumHelper &&rval) +{ + init(); + move(rval); +} +#endif + +String::String(char c) +{ + init(); + *this = c; } -String::String( const int value, const int base ) +String::String(unsigned char c) { - char buf[33]; - itoa((signed long)value, buf, base); - getBuffer( _length = strlen(buf) ); - if ( _buffer != NULL ) - strcpy( _buffer, buf ); + init(); + *this = (char)c; } -String::String( const unsigned int value, const int base ) +String::String(const int value, unsigned char base) { - char buf[33]; - ultoa((unsigned long)value, buf, base); - getBuffer( _length = strlen(buf) ); - if ( _buffer != NULL ) - strcpy( _buffer, buf ); + init(); + char buf[18]; + itoa(value, buf, base); + *this = buf; } -String::String( const long value, const int base ) +String::String(unsigned int value, unsigned char base) { - char buf[33]; - ltoa(value, buf, base); - getBuffer( _length = strlen(buf) ); - if ( _buffer != NULL ) - strcpy( _buffer, buf ); + init(); + char buf[17]; + utoa(value, buf, base); + *this = buf; } -String::String( const unsigned long value, const int base ) +String::String(long value, unsigned char base) { - char buf[33]; - ultoa(value, buf, 10); - getBuffer( _length = strlen(buf) ); - if ( _buffer != NULL ) - strcpy( _buffer, buf ); + init(); + char buf[34]; + ltoa(value, buf, base); + *this = buf; } -char String::charAt( unsigned int loc ) const +String::String(unsigned long value, unsigned char base) { - return operator[]( loc ); + init(); + char buf[33]; + ultoa(value, buf, base); + *this = buf; } -void String::setCharAt( unsigned int loc, const char aChar ) +String::~String() { - if(_buffer == NULL) return; - if(_length > loc) { - _buffer[loc] = aChar; - } + free(buffer); } -int String::compareTo( const String &s2 ) const +/*********************************************/ +/* Memory Management */ +/*********************************************/ + +inline void String::init(void) { - return strcmp( _buffer, s2._buffer ); + buffer = NULL; + capacity = 0; + len = 0; + flags = 0; } -const String & String::concat( const String &s2 ) +unsigned char String::reserve(unsigned int size) { - return (*this) += s2; + if (capacity >= size) return 1; + if (changeBuffer(size)) { + if (len == 0) buffer[0] = 0; + return 1; + } + return 0; } -const String & String::operator=( const String &rhs ) +unsigned char String::changeBuffer(unsigned int maxStrLen) { - 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; + char *newbuffer = (char *)realloc(buffer, maxStrLen + 1); + if (newbuffer) { + buffer = newbuffer; + capacity = maxStrLen; + return 1; + } + return 0; } -//const String & String::operator+=( const char aChar ) -//{ -// if ( _length == _capacity ) -// doubleBuffer(); -// -// _buffer[ _length++ ] = aChar; -// _buffer[ _length ] = '\0'; -// return *this; -//} +/*********************************************/ +/* Copy and Move */ +/*********************************************/ -const String & String::operator+=( const String &other ) +String & String::copy(const char *cstr, unsigned int length) { - _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; + if (length == 0) { + if (buffer) buffer[0] = 0; + len = 0; + return *this; + } + if (!reserve(length)) { + if (buffer) { + free(buffer); + buffer = NULL; + } + len = capacity = 0; + return *this; + } + len = length; + strcpy(buffer, cstr); + return *this; } - -int String::operator==( const String &rhs ) const +String & String::copy(const __FlashStringHelper *pgmstr) { - return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 ); + unsigned int length = strlen_P((const prog_char *)pgmstr); + if (!reserve(length)) { + if (buffer) { + free(buffer); + buffer = NULL; + } + len = capacity = 0; + return *this; + } + len = length; + strcpy_P(buffer, (const prog_char *)pgmstr); + return *this; } -int String::operator!=( const String &rhs ) const +void String::move(String &rhs) { - return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 ); + if (buffer) { + if (capacity >= rhs.len) { + strcpy(buffer, rhs.buffer); + len = rhs.len; + rhs.len = 0; + return; + } else { + free(buffer); + } + } + buffer = rhs.buffer; + capacity = rhs.capacity; + len = rhs.len; + rhs.buffer = NULL; + rhs.capacity = 0; + rhs.len = 0; } -int String::operator<( const String &rhs ) const +String & String::operator = (const String &rhs) { - return strcmp( _buffer, rhs._buffer ) < 0; + if (this == &rhs) return *this; + return copy(rhs.buffer, rhs.len); } -int String::operator>( const String &rhs ) const +#ifdef __GXX_EXPERIMENTAL_CXX0X__ +String & String::operator = (String &&rval) { - return strcmp( _buffer, rhs._buffer ) > 0; + if (this != &rval) move(rval); + return *this; } -int String::operator<=( const String &rhs ) const +String & String::operator = (StringSumHelper &&rval) { - return strcmp( _buffer, rhs._buffer ) <= 0; + if (this != &rval) move(rval); + return *this; +} +#endif + +String & String::operator = (const char *cstr) +{ + if (cstr) { + copy(cstr, strlen(cstr)); + } else { + len = 0; + } + return *this; } -int String::operator>=( const String & rhs ) const +String & String::operator = (const __FlashStringHelper *pgmstr) { - return strcmp( _buffer, rhs._buffer ) >= 0; + copy(pgmstr); + return *this; } -char & String::operator[]( unsigned int index ) +String & String::operator = (char c) { - static char dummy_writable_char; - if (index >= _length || !_buffer) { - dummy_writable_char = 0; - return dummy_writable_char; - } - return _buffer[ index ]; + char buf[2]; + buf[0] = c; + buf[1] = 0; + return copy(buf, 1); +} + +/*********************************************/ +/* Append */ +/*********************************************/ + +String & String::append(const String &s) +{ + return append(s.buffer, s.len); +} + +String & String::append(const char *cstr, unsigned int length) +{ + unsigned int newlen = len + length; + if (length == 0 || !reserve(newlen)) return *this; + strcpy(buffer + len, cstr); + len = newlen; + return *this; +} + +String & String::append(const char *cstr) +{ + if (cstr) append(cstr, strlen(cstr)); + return *this; +} + +String & String::append(const __FlashStringHelper *pgmstr) +{ + unsigned int length = strlen_P((const prog_char *)pgmstr); + unsigned int newlen = len + length; + if (length == 0 || !reserve(newlen)) return *this; + strcpy_P(buffer + len, (const prog_char *)pgmstr); + len = newlen; + return *this; +} + +String & String::append(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + append(buf, 1); + return *this; +} + +String & String::append(int num) +{ + char buf[7]; + itoa(num, buf, 10); + append(buf, strlen(buf)); + return *this; +} + +String & String::append(unsigned int num) +{ + char buf[6]; + utoa(num, buf, 10); + append(buf, strlen(buf)); + return *this; +} + +String & String::append(long num) +{ + char buf[12]; + ltoa(num, buf, 10); + append(buf, strlen(buf)); + return *this; +} + +String & String::append(unsigned long num) +{ + char buf[11]; + ultoa(num, buf, 10); + append(buf, strlen(buf)); + return *this; +} + +/*********************************************/ +/* Concatenate */ +/*********************************************/ + +StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) +{ + StringSumHelper &a = const_cast(lhs); + a.append(rhs.buffer, rhs.len); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) +{ + StringSumHelper &a = const_cast(lhs); + if (cstr) a.append(cstr, strlen(cstr)); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr) +{ + StringSumHelper &a = const_cast(lhs); + a.append(pgmstr); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + a.append(c); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c) +{ + StringSumHelper &a = const_cast(lhs); + a.append(c); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + a.append(num); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + a.append(num); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + a.append(num); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + a.append(num); + return a; +} + +/*********************************************/ +/* Comparison */ +/*********************************************/ + +int String::compareTo(const String &s) const +{ + if (!buffer || !s.buffer) { + if (s.buffer && s.len > 0) return 0 - *(unsigned char *)s.buffer; + if (buffer && len > 0) return *(unsigned char *)buffer; + return 0; + } + return strcmp(buffer, s.buffer); +} + +unsigned char String::equals(const String &s2) const +{ + return (len == s2.len && compareTo(s2) == 0); +} + +unsigned char String::equals(const char *cstr) const +{ + if (len == 0) return (cstr == NULL || *cstr == 0); + if (cstr == NULL) return buffer[0] == 0; + return strcmp(buffer, cstr) == 0; +} + +unsigned char String::equals(const __FlashStringHelper *pgmstr) const +{ + if (len == 0) return pgm_read_byte(pgmstr) == 0; + return strcmp_P(buffer, (const prog_char *)pgmstr) == 0; +} + +unsigned char String::operator<(const String &rhs) const +{ + return compareTo(rhs) < 0; +} + +unsigned char String::operator>(const String &rhs) const +{ + return compareTo(rhs) > 0; +} + +unsigned char String::operator<=(const String &rhs) const +{ + return compareTo(rhs) <= 0; +} + +unsigned char String::operator>=(const String &rhs) const +{ + return compareTo(rhs) >= 0; +} + +unsigned char String::equalsIgnoreCase( const String &s2 ) const +{ + if (this == &s2) return 1; + if (len != s2.len) return 0; + if (len == 0) return 1; + const char *p1 = buffer; + const char *p2 = s2.buffer; + while (*p1) { + if (tolower(*p1++) != tolower(*p2++)) return 0; + } + return 1; +} + +unsigned char String::startsWith( const String &s2 ) const +{ + if (len < s2.len) return 0; + return startsWith(s2, 0); +} + +unsigned char String::startsWith( const String &s2, unsigned int offset ) const +{ + if (offset > len - s2.len || !buffer || !s2.buffer) return 0; + return strncmp( &buffer[offset], s2.buffer, s2.len ) == 0; +} + +unsigned char String::endsWith( const String &s2 ) const +{ + if ( len < s2.len || !buffer || !s2.buffer) return 0; + return strcmp(&buffer[len - s2.len], s2.buffer) == 0; +} + +/*********************************************/ +/* Character Access */ +/*********************************************/ + +char String::charAt(unsigned int loc) const +{ + return operator[](loc); +} + +void String::setCharAt(unsigned int loc, char c) +{ + if (loc < len) buffer[loc] = c; +} + +char & String::operator[](unsigned int index) +{ + static char dummy_writable_char; + if (index >= len || !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 ]; + if (index >= len || !buffer) return 0; + return buffer[index]; } -boolean String::endsWith( const String &s2 ) const +void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const { - if ( _length < s2._length ) - return 0; - - return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0; + if (!bufsize || !buf) return; + if (index >= len) { + buf[0] = 0; + return; + } + unsigned int n = bufsize - 1; + if (n > len - index) n = len - index; + strncpy((char *)buf, buffer + index, n); + buf[n] = 0; } -boolean String::equals( const String &s2 ) const +/*********************************************/ +/* Search */ +/*********************************************/ + +int String::indexOf(char c) 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 ); + return indexOf(c, 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; + if (fromIndex >= len) return -1; + const char* temp = strchr(buffer + fromIndex, ch); + if (temp == NULL) return -1; + return temp - buffer; } -int String::indexOf( const String &s2 ) const +int String::indexOf(const String &s2) const { - return indexOf( s2, 0 ); + return indexOf(s2, 0); } -int String::indexOf( const String &s2, unsigned int fromIndex ) const +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 + if (fromIndex >= len) return -1; + const char *found = strstr(buffer + fromIndex, s2.buffer); + if (found == NULL) return -1; + return found - buffer; } int String::lastIndexOf( char theChar ) const { - return lastIndexOf( theChar, _length - 1 ); + return lastIndexOf(theChar, len - 1); } -int String::lastIndexOf( char ch, unsigned int fromIndex ) const +int String::lastIndexOf(char ch, 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; + if (fromIndex >= len || fromIndex < 0) 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 +int String::lastIndexOf(const String &s2) const { - return lastIndexOf( s2, _length - s2._length ); + return lastIndexOf(s2, len - s2.len); } -int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const +int String::lastIndexOf(const String &s2, 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; + if (s2.len == 0 || len == 0 || s2.len > len || fromIndex < 0) return -1; + if (fromIndex >= len) fromIndex = len - 1; + int found = -1; + for (char *p = buffer; p <= buffer + fromIndex; p++) { + p = strstr(p, s2.buffer); + if (!p) break; + if (p - buffer <= fromIndex) found = p - buffer; + } + return found; } String String::substring( unsigned int left ) const { - return substring( left, _length ); + return substring(left, len); } -String String::substring( unsigned int left, unsigned int right ) const +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; + if (left > right) { + unsigned int temp = right; + right = left; + left = temp; + } + String out; + if (left > len) return out; + if (right > len) right = len; + char temp = buffer[right]; // save the replaced character + buffer[right] = '\0'; + out = buffer + left; // pointer arithmetic + buffer[right] = temp; //restore character + return out; } -String String::toLowerCase() const +/*********************************************/ +/* Modification */ +/*********************************************/ + +String & String::replace(char find, char replace) { - String temp = _buffer; - - for ( unsigned int i = 0; i < _length; i++ ) - temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] ); - return temp; + if (!buffer) return *this; + for (char *p = buffer; *p; p++) { + if (*p == find) *p = replace; + } + return *this; } -String String::toUpperCase() const +String & String::replace(const String& find, const String& replace) { - String temp = _buffer; - - for ( unsigned int i = 0; i < _length; i++ ) - temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] ); - return temp; + if (len == 0 || find.len == 0) return *this; + int diff = replace.len - find.len; + char *readFrom = buffer; + char *foundAt; + if (diff == 0) { + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + memcpy(foundAt, replace.buffer, replace.len); + readFrom = foundAt + replace.len; + } + } else if (diff < 0) { + char *writeTo = buffer; + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + unsigned int n = foundAt - readFrom; + memcpy(writeTo, readFrom, n); + writeTo += n; + memcpy(writeTo, replace.buffer, replace.len); + writeTo += replace.len; + readFrom = foundAt + find.len; + len += diff; + } + strcpy(writeTo, readFrom); + } else { + unsigned int size = len; // compute size needed for result + while ((foundAt = strstr(readFrom, find.buffer)) != NULL) { + readFrom = foundAt + find.len; + size += diff; + } + if (size == len) return *this; + if (size > capacity && !changeBuffer(size)) return *this; + int index = len - 1; + while ((index = lastIndexOf(find, index)) >= 0) { + readFrom = buffer + index + find.len; + memmove(readFrom + diff, readFrom, len - (readFrom - buffer)); + len += diff; + buffer[len] = 0; + memcpy(buffer + index, replace.buffer, replace.len); + index--; + } + } + return *this; } -String String::trim() const +String & String::toLowerCase(void) { - 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); + if (!buffer) return *this; + for (char *p = buffer; *p; p++) { + *p = tolower(*p); + } + return *this; } -void String::getBytes(unsigned char *buf, unsigned int bufsize) +String & String::toUpperCase(void) { - if (!bufsize || !buf) return; - unsigned int len = bufsize - 1; - if (len > _length) len = _length; - strncpy((char *)buf, _buffer, len); - buf[len] = 0; + if (!buffer) return *this; + for (char *p = buffer; *p; p++) { + *p = toupper(*p); + } + return *this; } -void String::toCharArray(char *buf, unsigned int bufsize) +String & String::trim(void) { - if (!bufsize || !buf) return; - unsigned int len = bufsize - 1; - if (len > _length) len = _length; - strncpy(buf, _buffer, len); - buf[len] = 0; + if (!buffer || len == 0) return *this; + char *begin = buffer; + while (isspace(*begin)) begin++; + char *end = buffer + len - 1; + while (isspace(*end) && end >= begin) end--; + len = end + 1 - begin; + if (begin > buffer) memcpy(buffer, begin, len); + buffer[len] = 0; + return *this; +} + +/*********************************************/ +/* Parsing / Conversion */ +/*********************************************/ + +long String::toInt(void) const +{ + if (buffer) return atol(buffer); + return 0; } -long String::toInt() { - return atol(_buffer); -} diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index ff671d8..541a118 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -1,6 +1,8 @@ /* WString.h - String library for Wiring & Arduino + ...mostly rewritten by Paul Stoffregen... Copyright (c) 2009-10 Hernando Barragan. All right reserved. + Copyright 2011, Paul Stoffregen, paul@pjrc.com This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -17,96 +19,175 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef String_h -#define String_h +#ifndef String_class_h +#define String_class_h +#ifdef __cplusplus -//#include "Arduino.h" #include #include #include +#include +// When compiling programs with this class, the following gcc parameters +// dramatically increase performance and memory (RAM) efficiency, typically +// with little or no increase in code size. +// -felide-constructors +// -std=c++0x + +// Brian Cook's "no overhead" Flash String type (message on Dec 14, 2010) +// modified by Mikal Hart for his FlashString library +class __FlashStringHelper; +#ifndef F +#define F(string_literal) (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal))) +#endif + +// An inherited class for holding the result of a concatenation. These +// result objects are assumed to be writable by subsequent concatenations. +class StringSumHelper; + +// The string class 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; +public: + // constructors + String(const char *cstr = NULL); + String(const __FlashStringHelper *pgmstr); + String(const String &str); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String(String &&rval); + String(StringSumHelper &&rval); + #endif + String(char c); + String(unsigned char c); + String(int, unsigned char base=10); + String(unsigned int, unsigned char base=10); + String(long, unsigned char base=10); + String(unsigned long, unsigned char base=10); + ~String(void); - // 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 ); + // memory management + unsigned char reserve(unsigned int size); + inline unsigned int length(void) const {return len;} - 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') + // copy and move + String & copy(const char *cstr, unsigned int length); + String & copy(const __FlashStringHelper *pgmstr); + void move(String &rhs); + String & operator = (const String &rhs); + String & operator = (const char *cstr); + String & operator = (const __FlashStringHelper *pgmstr); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + String & operator = (String &&rval); + String & operator = (StringSumHelper &&rval); + #endif + String & operator = (char c); - void getBuffer(unsigned int maxStrLen); + // append + String & append(const String &str); + String & append(const char *cstr); + String & append(const __FlashStringHelper *pgmstr); + String & append(char c); + String & append(unsigned char c) {return append((char)c);} + String & append(int num); + String & append(unsigned int num); + String & append(long num); + String & append(unsigned long num); + String & operator += (const String &rhs) {return append(rhs);} + String & operator += (const char *cstr) {return append(cstr);} + String & operator += (const __FlashStringHelper *pgmstr) {return append(pgmstr);} + String & operator += (char c) {return append(c);} + String & operator += (unsigned char c) {return append((char)c);} + String & operator += (int num) {return append(num);} + String & operator += (unsigned int num) {return append(num);} + String & operator += (long num) {return append(num);} + String & operator += (unsigned long num) {return append(num);} - private: + // concatenate + friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); + // comparison + int compareTo(const String &s) const; + unsigned char equals(const String &s) const; + unsigned char equals(const char *cstr) const; + unsigned char equals(const __FlashStringHelper *pgmstr) const; + unsigned char operator == (const String &rhs) const {return equals(rhs);} + unsigned char operator == (const char *cstr) const {return equals(cstr);} + unsigned char operator == (const __FlashStringHelper *pgmstr) const {return equals(pgmstr);} + unsigned char operator != (const String &rhs) const {return !equals(rhs);} + unsigned char operator != (const char *cstr) const {return !equals(cstr);} + unsigned char operator != (const __FlashStringHelper *pgmstr) const {return !equals(pgmstr);} + unsigned char operator < (const String &rhs) const; + unsigned char operator > (const String &rhs) const; + unsigned char operator <= (const String &rhs) const; + unsigned char operator >= (const String &rhs) const; + unsigned char equalsIgnoreCase(const String &s) const; + unsigned char startsWith( const String &prefix) const; + unsigned char startsWith(const String &prefix, unsigned int offset) const; + unsigned char endsWith(const String &suffix) const; + + // character acccess + char charAt(unsigned int index) const; + void setCharAt(unsigned int index, char c); + char operator [] (unsigned int index) const; + char& operator [] (unsigned int index); + void getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index=0) const; + void toCharArray(char *buf, unsigned int bufsize, unsigned int index=0) const + {getBytes((unsigned char *)buf, bufsize, index);} + + // search + 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, int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, int fromIndex ) const; + String substring( unsigned int beginIndex ) const; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + + // modification + String & replace(char find, char replace); + String & replace(const String& find, const String& replace); + String & toLowerCase(void); + String & toUpperCase(void); + String & trim(void); + + // parsing/conversion + long toInt(void) const; + +protected: + char *buffer; // the actual char array + unsigned int capacity; // the array length minus one (for the '\0') + unsigned int len; // the String length (not counting the '\0') + unsigned char flags; // unused, for future features +protected: + void init(void); + unsigned char changeBuffer(unsigned int maxStrLen); + String & append(const char *cstr, unsigned int length); }; -// allocate buffer space -inline void String::getBuffer(unsigned int maxStrLen) +class StringSumHelper : public String { - _capacity = maxStrLen; - _buffer = (char *) malloc(_capacity + 1); - if (_buffer == NULL) _length = _capacity = 0; -} +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(const __FlashStringHelper *pgmstr) : String(pgmstr) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char c) : String(c) {} + StringSumHelper(int num) : String(num, 10) {} + StringSumHelper(unsigned int num) : String(num, 10) {} + StringSumHelper(long num) : String(num, 10) {} + StringSumHelper(unsigned long num) : String(num, 10) {} +}; -inline String operator+( String lhs, const String &rhs ) -{ - return lhs += rhs; -} - - -#endif +#endif // __cplusplus +#endif // String_class_h From 22786eaed2494bf6fcd9b934f857dec1202b3148 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Mar 2011 18:01:40 -0500 Subject: [PATCH 21/54] Removing F("string") syntax for now. We should probably add something like this back in later, but I want to do one thing at a time. This removes the __FlashStringHelper class as well. --- cores/arduino/WString.cpp | 51 --------------------------------------- cores/arduino/WString.h | 17 ------------- 2 files changed, 68 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index c980e24..b988acc 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -32,12 +32,6 @@ String::String(const char *cstr) if (cstr) copy(cstr, strlen(cstr)); } -String::String(const __FlashStringHelper *pgmstr) -{ - init(); - *this = pgmstr; -} - String::String(const String &value) { init(); @@ -163,22 +157,6 @@ String & String::copy(const char *cstr, unsigned int length) return *this; } -String & String::copy(const __FlashStringHelper *pgmstr) -{ - unsigned int length = strlen_P((const prog_char *)pgmstr); - if (!reserve(length)) { - if (buffer) { - free(buffer); - buffer = NULL; - } - len = capacity = 0; - return *this; - } - len = length; - strcpy_P(buffer, (const prog_char *)pgmstr); - return *this; -} - void String::move(String &rhs) { if (buffer) { @@ -229,12 +207,6 @@ String & String::operator = (const char *cstr) return *this; } -String & String::operator = (const __FlashStringHelper *pgmstr) -{ - copy(pgmstr); - return *this; -} - String & String::operator = (char c) { char buf[2]; @@ -267,16 +239,6 @@ String & String::append(const char *cstr) return *this; } -String & String::append(const __FlashStringHelper *pgmstr) -{ - unsigned int length = strlen_P((const prog_char *)pgmstr); - unsigned int newlen = len + length; - if (length == 0 || !reserve(newlen)) return *this; - strcpy_P(buffer + len, (const prog_char *)pgmstr); - len = newlen; - return *this; -} - String & String::append(char c) { char buf[2]; @@ -336,13 +298,6 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) return a; } -StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr) -{ - StringSumHelper &a = const_cast(lhs); - a.append(pgmstr); - return a; -} - StringSumHelper & operator + (const StringSumHelper &lhs, char c) { StringSumHelper &a = const_cast(lhs); @@ -411,12 +366,6 @@ unsigned char String::equals(const char *cstr) const return strcmp(buffer, cstr) == 0; } -unsigned char String::equals(const __FlashStringHelper *pgmstr) const -{ - if (len == 0) return pgm_read_byte(pgmstr) == 0; - return strcmp_P(buffer, (const prog_char *)pgmstr) == 0; -} - unsigned char String::operator<(const String &rhs) const { return compareTo(rhs) < 0; diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 541a118..6111e20 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -34,13 +34,6 @@ // -felide-constructors // -std=c++0x -// Brian Cook's "no overhead" Flash String type (message on Dec 14, 2010) -// modified by Mikal Hart for his FlashString library -class __FlashStringHelper; -#ifndef F -#define F(string_literal) (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal))) -#endif - // An inherited class for holding the result of a concatenation. These // result objects are assumed to be writable by subsequent concatenations. class StringSumHelper; @@ -51,7 +44,6 @@ class String public: // constructors String(const char *cstr = NULL); - String(const __FlashStringHelper *pgmstr); String(const String &str); #ifdef __GXX_EXPERIMENTAL_CXX0X__ String(String &&rval); @@ -71,11 +63,9 @@ public: // copy and move String & copy(const char *cstr, unsigned int length); - String & copy(const __FlashStringHelper *pgmstr); void move(String &rhs); String & operator = (const String &rhs); String & operator = (const char *cstr); - String & operator = (const __FlashStringHelper *pgmstr); #ifdef __GXX_EXPERIMENTAL_CXX0X__ String & operator = (String &&rval); String & operator = (StringSumHelper &&rval); @@ -85,7 +75,6 @@ public: // append String & append(const String &str); String & append(const char *cstr); - String & append(const __FlashStringHelper *pgmstr); String & append(char c); String & append(unsigned char c) {return append((char)c);} String & append(int num); @@ -94,7 +83,6 @@ public: String & append(unsigned long num); String & operator += (const String &rhs) {return append(rhs);} String & operator += (const char *cstr) {return append(cstr);} - String & operator += (const __FlashStringHelper *pgmstr) {return append(pgmstr);} String & operator += (char c) {return append(c);} String & operator += (unsigned char c) {return append((char)c);} String & operator += (int num) {return append(num);} @@ -105,7 +93,6 @@ public: // concatenate friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); - friend StringSumHelper & operator + (const StringSumHelper &lhs, const __FlashStringHelper *pgmstr); friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c); friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); @@ -117,13 +104,10 @@ public: int compareTo(const String &s) const; unsigned char equals(const String &s) const; unsigned char equals(const char *cstr) const; - unsigned char equals(const __FlashStringHelper *pgmstr) const; unsigned char operator == (const String &rhs) const {return equals(rhs);} unsigned char operator == (const char *cstr) const {return equals(cstr);} - unsigned char operator == (const __FlashStringHelper *pgmstr) const {return equals(pgmstr);} unsigned char operator != (const String &rhs) const {return !equals(rhs);} unsigned char operator != (const char *cstr) const {return !equals(cstr);} - unsigned char operator != (const __FlashStringHelper *pgmstr) const {return !equals(pgmstr);} unsigned char operator < (const String &rhs) const; unsigned char operator > (const String &rhs) const; unsigned char operator <= (const String &rhs) const; @@ -180,7 +164,6 @@ class StringSumHelper : public String public: StringSumHelper(const String &s) : String(s) {} StringSumHelper(const char *p) : String(p) {} - StringSumHelper(const __FlashStringHelper *pgmstr) : String(pgmstr) {} StringSumHelper(char c) : String(c) {} StringSumHelper(unsigned char c) : String(c) {} StringSumHelper(int num) : String(num, 10) {} From 99e0c131fc0bc286e42e848d56beceb3add66e93 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Mar 2011 18:04:31 -0500 Subject: [PATCH 22/54] Renaming append() back to concat(). --- cores/arduino/WString.cpp | 48 +++++++++++++++++++-------------------- cores/arduino/WString.h | 36 ++++++++++++++--------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index b988acc..46efbf5 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -216,15 +216,15 @@ String & String::operator = (char c) } /*********************************************/ -/* Append */ +/* concat */ /*********************************************/ -String & String::append(const String &s) +String & String::concat(const String &s) { - return append(s.buffer, s.len); + return concat(s.buffer, s.len); } -String & String::append(const char *cstr, unsigned int length) +String & String::concat(const char *cstr, unsigned int length) { unsigned int newlen = len + length; if (length == 0 || !reserve(newlen)) return *this; @@ -233,50 +233,50 @@ String & String::append(const char *cstr, unsigned int length) return *this; } -String & String::append(const char *cstr) +String & String::concat(const char *cstr) { - if (cstr) append(cstr, strlen(cstr)); + if (cstr) concat(cstr, strlen(cstr)); return *this; } -String & String::append(char c) +String & String::concat(char c) { char buf[2]; buf[0] = c; buf[1] = 0; - append(buf, 1); + concat(buf, 1); return *this; } -String & String::append(int num) +String & String::concat(int num) { char buf[7]; itoa(num, buf, 10); - append(buf, strlen(buf)); + concat(buf, strlen(buf)); return *this; } -String & String::append(unsigned int num) +String & String::concat(unsigned int num) { char buf[6]; utoa(num, buf, 10); - append(buf, strlen(buf)); + concat(buf, strlen(buf)); return *this; } -String & String::append(long num) +String & String::concat(long num) { char buf[12]; ltoa(num, buf, 10); - append(buf, strlen(buf)); + concat(buf, strlen(buf)); return *this; } -String & String::append(unsigned long num) +String & String::concat(unsigned long num) { char buf[11]; ultoa(num, buf, 10); - append(buf, strlen(buf)); + concat(buf, strlen(buf)); return *this; } @@ -287,56 +287,56 @@ String & String::append(unsigned long num) StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) { StringSumHelper &a = const_cast(lhs); - a.append(rhs.buffer, rhs.len); + a.concat(rhs.buffer, rhs.len); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) { StringSumHelper &a = const_cast(lhs); - if (cstr) a.append(cstr, strlen(cstr)); + if (cstr) a.concat(cstr, strlen(cstr)); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, char c) { StringSumHelper &a = const_cast(lhs); - a.append(c); + a.concat(c); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c) { StringSumHelper &a = const_cast(lhs); - a.append(c); + a.concat(c); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, int num) { StringSumHelper &a = const_cast(lhs); - a.append(num); + a.concat(num); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) { StringSumHelper &a = const_cast(lhs); - a.append(num); + a.concat(num); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, long num) { StringSumHelper &a = const_cast(lhs); - a.append(num); + a.concat(num); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) { StringSumHelper &a = const_cast(lhs); - a.append(num); + a.concat(num); return a; } diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 6111e20..4a680e2 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -72,23 +72,23 @@ public: #endif String & operator = (char c); - // append - String & append(const String &str); - String & append(const char *cstr); - String & append(char c); - String & append(unsigned char c) {return append((char)c);} - String & append(int num); - String & append(unsigned int num); - String & append(long num); - String & append(unsigned long num); - String & operator += (const String &rhs) {return append(rhs);} - String & operator += (const char *cstr) {return append(cstr);} - String & operator += (char c) {return append(c);} - String & operator += (unsigned char c) {return append((char)c);} - String & operator += (int num) {return append(num);} - String & operator += (unsigned int num) {return append(num);} - String & operator += (long num) {return append(num);} - String & operator += (unsigned long num) {return append(num);} + // concat + String & concat(const String &str); + String & concat(const char *cstr); + String & concat(char c); + String & concat(unsigned char c) {return concat((char)c);} + String & concat(int num); + String & concat(unsigned int num); + String & concat(long num); + String & concat(unsigned long num); + String & operator += (const String &rhs) {return concat(rhs);} + String & operator += (const char *cstr) {return concat(cstr);} + String & operator += (char c) {return concat(c);} + String & operator += (unsigned char c) {return concat((char)c);} + String & operator += (int num) {return concat(num);} + String & operator += (unsigned int num) {return concat(num);} + String & operator += (long num) {return concat(num);} + String & operator += (unsigned long num) {return concat(num);} // concatenate friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); @@ -156,7 +156,7 @@ protected: protected: void init(void); unsigned char changeBuffer(unsigned int maxStrLen); - String & append(const char *cstr, unsigned int length); + String & concat(const char *cstr, unsigned int length); }; class StringSumHelper : public String From b4b32f60f1c156e76117dab69479c193a861be23 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 11 Mar 2011 18:54:58 -0500 Subject: [PATCH 23/54] Don't return the string when modifying its value. Changing toLowerCase(), toUpperCase(), trim() and replace() to return void instead of a reference to the string that's just been changed. That way, it's clear that the functions modify the string they've been called on. --- cores/arduino/WString.cpp | 29 ++++++++++++----------------- cores/arduino/WString.h | 10 +++++----- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 46efbf5..e9f71d1 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -550,18 +550,17 @@ String String::substring(unsigned int left, unsigned int right) const /* Modification */ /*********************************************/ -String & String::replace(char find, char replace) +void String::replace(char find, char replace) { - if (!buffer) return *this; + if (!buffer) return; for (char *p = buffer; *p; p++) { if (*p == find) *p = replace; } - return *this; } -String & String::replace(const String& find, const String& replace) +void String::replace(const String& find, const String& replace) { - if (len == 0 || find.len == 0) return *this; + if (len == 0 || find.len == 0) return; int diff = replace.len - find.len; char *readFrom = buffer; char *foundAt; @@ -588,8 +587,8 @@ String & String::replace(const String& find, const String& replace) readFrom = foundAt + find.len; size += diff; } - if (size == len) return *this; - if (size > capacity && !changeBuffer(size)) return *this; + if (size == len) return; + if (size > capacity && !changeBuffer(size)) return; // XXX: tell user! int index = len - 1; while ((index = lastIndexOf(find, index)) >= 0) { readFrom = buffer + index + find.len; @@ -600,30 +599,27 @@ String & String::replace(const String& find, const String& replace) index--; } } - return *this; } -String & String::toLowerCase(void) +void String::toLowerCase(void) { - if (!buffer) return *this; + if (!buffer) return; for (char *p = buffer; *p; p++) { *p = tolower(*p); } - return *this; } -String & String::toUpperCase(void) +void String::toUpperCase(void) { - if (!buffer) return *this; + if (!buffer) return; for (char *p = buffer; *p; p++) { *p = toupper(*p); } - return *this; } -String & String::trim(void) +void String::trim(void) { - if (!buffer || len == 0) return *this; + if (!buffer || len == 0) return; char *begin = buffer; while (isspace(*begin)) begin++; char *end = buffer + len - 1; @@ -631,7 +627,6 @@ String & String::trim(void) len = end + 1 - begin; if (begin > buffer) memcpy(buffer, begin, len); buffer[len] = 0; - return *this; } /*********************************************/ diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 4a680e2..164eeac 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -139,11 +139,11 @@ public: String substring( unsigned int beginIndex, unsigned int endIndex ) const; // modification - String & replace(char find, char replace); - String & replace(const String& find, const String& replace); - String & toLowerCase(void); - String & toUpperCase(void); - String & trim(void); + void replace(char find, char replace); + void replace(const String& find, const String& replace); + void toLowerCase(void); + void toUpperCase(void); + void trim(void); // parsing/conversion long toInt(void) const; From 98b403114c3d9edcb6b74938f07c68dccc3c2489 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 12 Mar 2011 14:03:34 -0500 Subject: [PATCH 24/54] Modifying String.concat() to return success or failure, not this. Which means you can't chain multiple concat() calls together, but you can check if they succeeded or not. --- cores/arduino/WString.cpp | 40 ++++++++++++++++++--------------------- cores/arduino/WString.h | 34 ++++++++++++++++----------------- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index e9f71d1..5dcf585 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -219,65 +219,61 @@ String & String::operator = (char c) /* concat */ /*********************************************/ -String & String::concat(const String &s) +unsigned char String::concat(const String &s) { return concat(s.buffer, s.len); } -String & String::concat(const char *cstr, unsigned int length) +unsigned char String::concat(const char *cstr, unsigned int length) { unsigned int newlen = len + length; - if (length == 0 || !reserve(newlen)) return *this; + if (!cstr || length == 0) return 1; // nothing to append = success + if (!reserve(newlen)) return 0; strcpy(buffer + len, cstr); len = newlen; - return *this; + return 1; } -String & String::concat(const char *cstr) +unsigned char String::concat(const char *cstr) { - if (cstr) concat(cstr, strlen(cstr)); - return *this; + if (!cstr) return 1; // nothing to append = success + return concat(cstr, strlen(cstr)); } -String & String::concat(char c) +unsigned char String::concat(char c) { char buf[2]; buf[0] = c; buf[1] = 0; - concat(buf, 1); - return *this; + return concat(buf, 1); } -String & String::concat(int num) +unsigned char String::concat(int num) { char buf[7]; itoa(num, buf, 10); - concat(buf, strlen(buf)); - return *this; + return concat(buf, strlen(buf)); } -String & String::concat(unsigned int num) +unsigned char String::concat(unsigned int num) { char buf[6]; utoa(num, buf, 10); - concat(buf, strlen(buf)); - return *this; + return concat(buf, strlen(buf)); } -String & String::concat(long num) +unsigned char String::concat(long num) { char buf[12]; ltoa(num, buf, 10); - concat(buf, strlen(buf)); - return *this; + return concat(buf, strlen(buf)); } -String & String::concat(unsigned long num) +unsigned char String::concat(unsigned long num) { char buf[11]; ultoa(num, buf, 10); - concat(buf, strlen(buf)); - return *this; + return concat(buf, strlen(buf)); } /*********************************************/ diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 164eeac..f797861 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -73,22 +73,22 @@ public: String & operator = (char c); // concat - String & concat(const String &str); - String & concat(const char *cstr); - String & concat(char c); - String & concat(unsigned char c) {return concat((char)c);} - String & concat(int num); - String & concat(unsigned int num); - String & concat(long num); - String & concat(unsigned long num); - String & operator += (const String &rhs) {return concat(rhs);} - String & operator += (const char *cstr) {return concat(cstr);} - String & operator += (char c) {return concat(c);} - String & operator += (unsigned char c) {return concat((char)c);} - String & operator += (int num) {return concat(num);} - String & operator += (unsigned int num) {return concat(num);} - String & operator += (long num) {return concat(num);} - String & operator += (unsigned long num) {return concat(num);} + unsigned char concat(const String &str); + unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c) {return concat((char)c);} + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); + String & operator += (const String &rhs) {concat(rhs); return (*this);} + String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char c) {concat((char)c); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} // concatenate friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); @@ -156,7 +156,7 @@ protected: protected: void init(void); unsigned char changeBuffer(unsigned int maxStrLen); - String & concat(const char *cstr, unsigned int length); + unsigned char concat(const char *cstr, unsigned int length); }; class StringSumHelper : public String From 76776e7a46b30ee84f48db146bf8dd642de2927a Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 13 Mar 2011 16:46:06 -0400 Subject: [PATCH 25/54] Moving move() to __GXX_EXPERIMENTAL_CXX0X__ only, adding operator bool(). --- cores/arduino/WString.cpp | 7 +++++++ cores/arduino/WString.h | 3 +++ 2 files changed, 10 insertions(+) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 5dcf585..41c80e8 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -157,6 +157,7 @@ String & String::copy(const char *cstr, unsigned int length) return *this; } +#ifdef __GXX_EXPERIMENTAL_CXX0X__ void String::move(String &rhs) { if (buffer) { @@ -176,6 +177,7 @@ void String::move(String &rhs) rhs.capacity = 0; rhs.len = 0; } +#endif String & String::operator = (const String &rhs) { @@ -340,6 +342,11 @@ StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) /* Comparison */ /*********************************************/ +String::operator bool() const +{ + return !!buffer; +} + int String::compareTo(const String &s) const { if (!buffer || !s.buffer) { diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index f797861..5e78ee5 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -63,7 +63,9 @@ public: // copy and move String & copy(const char *cstr, unsigned int length); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ void move(String &rhs); + #endif String & operator = (const String &rhs); String & operator = (const char *cstr); #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -101,6 +103,7 @@ public: friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); // comparison + operator bool() const; int compareTo(const String &s) const; unsigned char equals(const String &s) const; unsigned char equals(const char *cstr) const; From a5f6e6524282e23860ace324dcf81598287f9944 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 13 Mar 2011 19:31:10 -0400 Subject: [PATCH 26/54] Adding additional String + operators for disambiguation. The operator bool() means that you could implicitly convert a String to a bool and then add it to it an int, for example. Which means our operator+ has to match exactly or it will be ambiguous. --- cores/arduino/WString.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 5e78ee5..5a35101 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -175,5 +175,40 @@ public: StringSumHelper(unsigned long num) : String(num, 10) {} }; +inline StringSumHelper operator + (const String &lhs, const String &rhs) + { return StringSumHelper(lhs) + rhs; } + +inline StringSumHelper operator + (const String &lhs, const char *cstr) + { return StringSumHelper(lhs) + cstr; } +inline StringSumHelper operator + (const String &lhs, char c) + { return StringSumHelper(lhs) + c; } +inline StringSumHelper operator + (const String &lhs, unsigned char c) + { return StringSumHelper(lhs) + c; } +inline StringSumHelper operator + (const String &lhs, int num) + { return StringSumHelper(lhs) + num; } +inline StringSumHelper operator + (const String &lhs, unsigned int num) + { return StringSumHelper(lhs) + num; } +inline StringSumHelper operator + (const String &lhs, long num) + { return StringSumHelper(lhs) + num; } +inline StringSumHelper operator + (const String &lhs, unsigned long num) + { return StringSumHelper(lhs) + num; } + +inline StringSumHelper operator + (const char *cstr, const String &rhs) + { return StringSumHelper(cstr) + rhs; } +inline StringSumHelper operator + (char c, const String &rhs) + { return StringSumHelper(c) + rhs; } +inline StringSumHelper operator + (unsigned char c, const String &rhs) + { return StringSumHelper(c) + rhs; } +inline StringSumHelper operator + (int num, const String &rhs) + { return StringSumHelper(num) + rhs; } +inline StringSumHelper operator + (unsigned int num, const String &rhs) + { return StringSumHelper(num) + rhs; } +inline StringSumHelper operator + (long num, const String &rhs) + { return StringSumHelper(num) + rhs; } +inline StringSumHelper operator + (unsigned long num, const String &rhs) + { return StringSumHelper(num) + rhs; } + + + #endif // __cplusplus #endif // String_class_h From 45884b1231e43acdce51b381975977a3601e77d0 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 13 Mar 2011 19:39:04 -0400 Subject: [PATCH 27/54] Protecting String copy() and move(). --- cores/arduino/WString.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 5a35101..6c07427 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -61,11 +61,6 @@ public: unsigned char reserve(unsigned int size); inline unsigned int length(void) const {return len;} - // copy and move - String & copy(const char *cstr, unsigned int length); - #ifdef __GXX_EXPERIMENTAL_CXX0X__ - void move(String &rhs); - #endif String & operator = (const String &rhs); String & operator = (const char *cstr); #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -160,6 +155,12 @@ protected: void init(void); unsigned char changeBuffer(unsigned int maxStrLen); unsigned char concat(const char *cstr, unsigned int length); + + // copy and move + String & copy(const char *cstr, unsigned int length); + #ifdef __GXX_EXPERIMENTAL_CXX0X__ + void move(String &rhs); + #endif }; class StringSumHelper : public String From 7dea0522f48641106f92b1511b9e62ee46f8e2dc Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 18 Mar 2011 21:45:27 -0400 Subject: [PATCH 28/54] Starting to distinguish between empty strings and invalid (null) ones. --- cores/arduino/WString.cpp | 12 ++++++------ cores/arduino/WString.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 41c80e8..516bd20 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -114,7 +114,7 @@ inline void String::init(void) unsigned char String::reserve(unsigned int size) { - if (capacity >= size) return 1; + if (buffer && capacity >= size) return 1; if (changeBuffer(size)) { if (len == 0) buffer[0] = 0; return 1; @@ -139,11 +139,6 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) String & String::copy(const char *cstr, unsigned int length) { - if (length == 0) { - if (buffer) buffer[0] = 0; - len = 0; - return *this; - } if (!reserve(length)) { if (buffer) { free(buffer); @@ -204,6 +199,11 @@ String & String::operator = (const char *cstr) if (cstr) { copy(cstr, strlen(cstr)); } else { + if (buffer) { + free(buffer); + capacity = 0; + buffer = NULL; + } len = 0; } return *this; diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 6c07427..18b6541 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -43,7 +43,7 @@ class String { public: // constructors - String(const char *cstr = NULL); + String(const char *cstr = ""); String(const String &str); #ifdef __GXX_EXPERIMENTAL_CXX0X__ String(String &&rval); From 58d04ab3a3a0b13524a862168bed1c3d0708766e Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 19 Mar 2011 11:14:17 -0400 Subject: [PATCH 29/54] Return an invalid string (not a partial one) when operator+() fails. --- cores/arduino/WString.cpp | 53 ++++++++++++++++++++------------------- cores/arduino/WString.h | 1 + 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 516bd20..61ce375 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -112,6 +112,13 @@ inline void String::init(void) flags = 0; } +void String::invalidate(void) +{ + if (buffer) free(buffer); + buffer = NULL; + capacity = len = 0; +} + unsigned char String::reserve(unsigned int size) { if (buffer && capacity >= size) return 1; @@ -140,11 +147,7 @@ unsigned char String::changeBuffer(unsigned int maxStrLen) String & String::copy(const char *cstr, unsigned int length) { if (!reserve(length)) { - if (buffer) { - free(buffer); - buffer = NULL; - } - len = capacity = 0; + invalidate(); return *this; } len = length; @@ -177,7 +180,11 @@ void String::move(String &rhs) String & String::operator = (const String &rhs) { if (this == &rhs) return *this; - return copy(rhs.buffer, rhs.len); + + if (rhs.buffer) copy(rhs.buffer, rhs.len); + else invalidate(); + + return *this; } #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -196,16 +203,9 @@ String & String::operator = (StringSumHelper &&rval) String & String::operator = (const char *cstr) { - if (cstr) { - copy(cstr, strlen(cstr)); - } else { - if (buffer) { - free(buffer); - capacity = 0; - buffer = NULL; - } - len = 0; - } + if (cstr) copy(cstr, strlen(cstr)); + else invalidate(); + return *this; } @@ -229,7 +229,8 @@ unsigned char String::concat(const String &s) unsigned char String::concat(const char *cstr, unsigned int length) { unsigned int newlen = len + length; - if (!cstr || length == 0) return 1; // nothing to append = success + if (!cstr) return 0; + if (length == 0) return 1; if (!reserve(newlen)) return 0; strcpy(buffer + len, cstr); len = newlen; @@ -238,7 +239,7 @@ unsigned char String::concat(const char *cstr, unsigned int length) unsigned char String::concat(const char *cstr) { - if (!cstr) return 1; // nothing to append = success + if (!cstr) return 0; return concat(cstr, strlen(cstr)); } @@ -285,56 +286,56 @@ unsigned char String::concat(unsigned long num) StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs) { StringSumHelper &a = const_cast(lhs); - a.concat(rhs.buffer, rhs.len); + if (!a.concat(rhs.buffer, rhs.len)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) { StringSumHelper &a = const_cast(lhs); - if (cstr) a.concat(cstr, strlen(cstr)); + if (!cstr || !a.concat(cstr, strlen(cstr))) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, char c) { StringSumHelper &a = const_cast(lhs); - a.concat(c); + if (!a.concat(c)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c) { StringSumHelper &a = const_cast(lhs); - a.concat(c); + if (!a.concat(c)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, int num) { StringSumHelper &a = const_cast(lhs); - a.concat(num); + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) { StringSumHelper &a = const_cast(lhs); - a.concat(num); + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, long num) { StringSumHelper &a = const_cast(lhs); - a.concat(num); + if (!a.concat(num)) a.invalidate(); return a; } StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) { StringSumHelper &a = const_cast(lhs); - a.concat(num); + if (!a.concat(num)) a.invalidate(); return a; } diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 18b6541..d707309 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -153,6 +153,7 @@ protected: unsigned char flags; // unused, for future features protected: void init(void); + void invalidate(void); unsigned char changeBuffer(unsigned int maxStrLen); unsigned char concat(const char *cstr, unsigned int length); From cedea72273a1d0b70c83f46808342b23ddaddca7 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 23 Mar 2011 22:42:05 -0400 Subject: [PATCH 30/54] Commenting String API behavior. --- cores/arduino/WString.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index d707309..180f58e 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -43,6 +43,10 @@ class String { public: // constructors + // creates a copy of the initial value. + // if the initial value is null or invalid, or if memory allocation + // fails, the string will be marked as invalid (i.e. operator bool() + // will return false). String(const char *cstr = ""); String(const String &str); #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -58,9 +62,15 @@ public: ~String(void); // memory management + // return true on success, false on failure (in which case, the string + // is left unchanged). reserve(0), if successful, will validate an + // invalid string (i.e., operator bool() will return true afterwards) unsigned char reserve(unsigned int size); inline unsigned int length(void) const {return len;} + // creates a copy of the assigned value. if the value is null or + // invalid, or if the memory allocation fails, the string will be + // marked as invalid (operator bool() will return false). String & operator = (const String &rhs); String & operator = (const char *cstr); #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -70,6 +80,9 @@ public: String & operator = (char c); // concat + // returns true on success, false on failure (in which case, the string + // is left unchanged). if the argument is null or invalid, the + // concatenation is considered unsucessful. unsigned char concat(const String &str); unsigned char concat(const char *cstr); unsigned char concat(char c); @@ -78,6 +91,9 @@ public: unsigned char concat(unsigned int num); unsigned char concat(long num); unsigned char concat(unsigned long num); + + // if there's not enough memory for the concatenated value, the string + // will be left unchanged (but this isn't signalled in any way) String & operator += (const String &rhs) {concat(rhs); return (*this);} String & operator += (const char *cstr) {concat(cstr); return (*this);} String & operator += (char c) {concat(c); return (*this);} From 99e642a26dc2a406cdfa2d43665f45749b63d5c8 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 26 Mar 2011 18:52:54 -0400 Subject: [PATCH 31/54] String: removing implicit numeric conversions and new approach to "if (s)". This makes explicit the String constructors that take numeric types and chars and removes the versions of concat() and operator=() and operator+() that accept numberic types. It also replaces the operator bool() with a operator that converts to a function pointer. This allows for uses like "if (s)" but not "s + 123". See: http://www.artima.com/cppsource/safebool.html. This allowed removing the disambiguating operator+() functions and relying solely on StringSumHelper and anonymous temporaries once again. Also, now treating unsigned char's like int when constructing Strings from them, i.e. String(byte(65)) is now "65" not "A". This is consistent with the new behavior of Serial.print(byte). --- cores/arduino/WString.cpp | 106 ++++---------------------------------- cores/arduino/WString.h | 81 +++++------------------------ 2 files changed, 24 insertions(+), 163 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index 61ce375..d057849 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -54,16 +54,21 @@ String::String(StringSumHelper &&rval) String::String(char c) { init(); - *this = c; + char buf[2]; + buf[0] = c; + buf[1] = 0; + *this = buf; } -String::String(unsigned char c) +String::String(unsigned char value, unsigned char base) { init(); - *this = (char)c; + char buf[9]; + utoa(value, buf, base); + *this = buf; } -String::String(const int value, unsigned char base) +String::String(int value, unsigned char base) { init(); char buf[18]; @@ -75,7 +80,7 @@ String::String(unsigned int value, unsigned char base) { init(); char buf[17]; - utoa(value, buf, base); + utoa(value, buf, base); *this = buf; } @@ -209,14 +214,6 @@ String & String::operator = (const char *cstr) return *this; } -String & String::operator = (char c) -{ - char buf[2]; - buf[0] = c; - buf[1] = 0; - return copy(buf, 1); -} - /*********************************************/ /* concat */ /*********************************************/ @@ -243,42 +240,6 @@ unsigned char String::concat(const char *cstr) return concat(cstr, strlen(cstr)); } -unsigned char String::concat(char c) -{ - char buf[2]; - buf[0] = c; - buf[1] = 0; - return concat(buf, 1); -} - -unsigned char String::concat(int num) -{ - char buf[7]; - itoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - -unsigned char String::concat(unsigned int num) -{ - char buf[6]; - utoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - -unsigned char String::concat(long num) -{ - char buf[12]; - ltoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - -unsigned char String::concat(unsigned long num) -{ - char buf[11]; - ultoa(num, buf, 10); - return concat(buf, strlen(buf)); -} - /*********************************************/ /* Concatenate */ /*********************************************/ @@ -297,57 +258,10 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) return a; } -StringSumHelper & operator + (const StringSumHelper &lhs, char c) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(c)) a.invalidate(); - return a; -} - -StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(c)) a.invalidate(); - return a; -} - -StringSumHelper & operator + (const StringSumHelper &lhs, int num) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; -} - -StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; -} - -StringSumHelper & operator + (const StringSumHelper &lhs, long num) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; -} - -StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) -{ - StringSumHelper &a = const_cast(lhs); - if (!a.concat(num)) a.invalidate(); - return a; -} - /*********************************************/ /* Comparison */ /*********************************************/ -String::operator bool() const -{ - return !!buffer; -} - int String::compareTo(const String &s) const { if (!buffer || !s.buffer) { diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 180f58e..bbbe7e8 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -41,6 +41,12 @@ class StringSumHelper; // The string class class String { + // use a function pointer to allow for "if (s)" without the + // complications of an operator bool(). for more information, see: + // http://www.artima.com/cppsource/safebool.html + typedef void (String::*StringIfHelperType)() const; + void StringIfHelper() const {} + public: // constructors // creates a copy of the initial value. @@ -53,12 +59,12 @@ public: String(String &&rval); String(StringSumHelper &&rval); #endif - String(char c); - String(unsigned char c); - String(int, unsigned char base=10); - String(unsigned int, unsigned char base=10); - String(long, unsigned char base=10); - String(unsigned long, unsigned char base=10); + explicit String(char c); + explicit String(unsigned char, unsigned char base=10); + explicit String(int, unsigned char base=10); + explicit String(unsigned int, unsigned char base=10); + explicit String(long, unsigned char base=10); + explicit String(unsigned long, unsigned char base=10); ~String(void); // memory management @@ -77,7 +83,6 @@ public: String & operator = (String &&rval); String & operator = (StringSumHelper &&rval); #endif - String & operator = (char c); // concat // returns true on success, false on failure (in which case, the string @@ -85,36 +90,19 @@ public: // concatenation is considered unsucessful. unsigned char concat(const String &str); unsigned char concat(const char *cstr); - unsigned char concat(char c); - unsigned char concat(unsigned char c) {return concat((char)c);} - unsigned char concat(int num); - unsigned char concat(unsigned int num); - unsigned char concat(long num); - unsigned char concat(unsigned long num); // if there's not enough memory for the concatenated value, the string // will be left unchanged (but this isn't signalled in any way) String & operator += (const String &rhs) {concat(rhs); return (*this);} String & operator += (const char *cstr) {concat(cstr); return (*this);} - String & operator += (char c) {concat(c); return (*this);} - String & operator += (unsigned char c) {concat((char)c); return (*this);} - String & operator += (int num) {concat(num); return (*this);} - String & operator += (unsigned int num) {concat(num); return (*this);} - String & operator += (long num) {concat(num); return (*this);} - String & operator += (unsigned long num) {concat(num); return (*this);} // concatenate friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); - friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char c); - friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); - friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); // comparison - operator bool() const; + operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } + int compareTo(const String &s) const; unsigned char equals(const String &s) const; unsigned char equals(const char *cstr) const; @@ -185,48 +173,7 @@ class StringSumHelper : public String public: StringSumHelper(const String &s) : String(s) {} StringSumHelper(const char *p) : String(p) {} - StringSumHelper(char c) : String(c) {} - StringSumHelper(unsigned char c) : String(c) {} - StringSumHelper(int num) : String(num, 10) {} - StringSumHelper(unsigned int num) : String(num, 10) {} - StringSumHelper(long num) : String(num, 10) {} - StringSumHelper(unsigned long num) : String(num, 10) {} }; -inline StringSumHelper operator + (const String &lhs, const String &rhs) - { return StringSumHelper(lhs) + rhs; } - -inline StringSumHelper operator + (const String &lhs, const char *cstr) - { return StringSumHelper(lhs) + cstr; } -inline StringSumHelper operator + (const String &lhs, char c) - { return StringSumHelper(lhs) + c; } -inline StringSumHelper operator + (const String &lhs, unsigned char c) - { return StringSumHelper(lhs) + c; } -inline StringSumHelper operator + (const String &lhs, int num) - { return StringSumHelper(lhs) + num; } -inline StringSumHelper operator + (const String &lhs, unsigned int num) - { return StringSumHelper(lhs) + num; } -inline StringSumHelper operator + (const String &lhs, long num) - { return StringSumHelper(lhs) + num; } -inline StringSumHelper operator + (const String &lhs, unsigned long num) - { return StringSumHelper(lhs) + num; } - -inline StringSumHelper operator + (const char *cstr, const String &rhs) - { return StringSumHelper(cstr) + rhs; } -inline StringSumHelper operator + (char c, const String &rhs) - { return StringSumHelper(c) + rhs; } -inline StringSumHelper operator + (unsigned char c, const String &rhs) - { return StringSumHelper(c) + rhs; } -inline StringSumHelper operator + (int num, const String &rhs) - { return StringSumHelper(num) + rhs; } -inline StringSumHelper operator + (unsigned int num, const String &rhs) - { return StringSumHelper(num) + rhs; } -inline StringSumHelper operator + (long num, const String &rhs) - { return StringSumHelper(num) + rhs; } -inline StringSumHelper operator + (unsigned long num, const String &rhs) - { return StringSumHelper(num) + rhs; } - - - #endif // __cplusplus #endif // String_class_h From ffe7bc53c1862866bf38e01174bd35d20632608c Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sun, 27 Mar 2011 15:06:20 -0400 Subject: [PATCH 32/54] Adding F("foo") syntax for flash strings. --- cores/arduino/Print.cpp | 18 +++++++++++++++++- cores/arduino/Print.h | 2 ++ cores/arduino/WString.h | 11 +++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 62d93a3..eac145f 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -43,6 +43,16 @@ void Print::write(const uint8_t *buffer, size_t size) write(*buffer++); } +void Print::print(const __FlashStringHelper *ifsh) +{ + const prog_char *p = (const prog_char *)ifsh; + while (1) { + unsigned char c = pgm_read_byte(p++); + if (c == 0) return; + write(c); + } +} + void Print::print(const String &s) { for (int i = 0; i < s.length(); i++) { @@ -101,10 +111,16 @@ void Print::print(double n, int digits) printFloat(n, digits); } +void Print::println(const __FlashStringHelper *ifsh) +{ + print(ifsh); + println(); +} + void Print::println(void) { print('\r'); - print('\n'); + print('\n'); } void Print::println(const String &s) diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index c090636..a447753 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -40,6 +40,7 @@ class Print virtual void write(const char *str); virtual void write(const uint8_t *buffer, size_t size); + void print(const __FlashStringHelper *); void print(const String &); void print(const char[]); void print(char); @@ -50,6 +51,7 @@ class Print void print(unsigned long, int = DEC); void print(double, int = 2); + void println(const __FlashStringHelper *); void println(const String &s); void println(const char[]); void println(char); diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index bbbe7e8..673e51b 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -34,6 +34,9 @@ // -felide-constructors // -std=c++0x +class __FlashStringHelper; +#define F(string_literal) (reinterpret_cast<__FlashStringHelper *>(PSTR(string_literal))) + // An inherited class for holding the result of a concatenation. These // result objects are assumed to be writable by subsequent concatenations. class StringSumHelper; @@ -51,8 +54,8 @@ public: // constructors // creates a copy of the initial value. // if the initial value is null or invalid, or if memory allocation - // fails, the string will be marked as invalid (i.e. operator bool() - // will return false). + // fails, the string will be marked as invalid (i.e. "if (s)" will + // be false). String(const char *cstr = ""); String(const String &str); #ifdef __GXX_EXPERIMENTAL_CXX0X__ @@ -70,13 +73,13 @@ public: // memory management // return true on success, false on failure (in which case, the string // is left unchanged). reserve(0), if successful, will validate an - // invalid string (i.e., operator bool() will return true afterwards) + // invalid string (i.e., "if (s)" will be true afterwards) unsigned char reserve(unsigned int size); inline unsigned int length(void) const {return len;} // creates a copy of the assigned value. if the value is null or // invalid, or if the memory allocation fails, the string will be - // marked as invalid (operator bool() will return false). + // marked as invalid ("if (s)" will be false). String & operator = (const String &rhs); String & operator = (const char *cstr); #ifdef __GXX_EXPERIMENTAL_CXX0X__ From 1cac0f3eb738119f53b8fdd07bcd6d1158235476 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 31 Mar 2011 10:56:14 -0400 Subject: [PATCH 33/54] Restoring concatenation of built-in types with String. --- cores/arduino/WString.cpp | 85 +++++++++++++++++++++++++++++++++++++++ cores/arduino/WString.h | 31 ++++++++++++-- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/cores/arduino/WString.cpp b/cores/arduino/WString.cpp index d057849..f90cef0 100644 --- a/cores/arduino/WString.cpp +++ b/cores/arduino/WString.cpp @@ -240,6 +240,49 @@ unsigned char String::concat(const char *cstr) return concat(cstr, strlen(cstr)); } +unsigned char String::concat(char c) +{ + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); +} + +unsigned char String::concat(unsigned char num) +{ + char buf[4]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(int num) +{ + char buf[7]; + itoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned int num) +{ + char buf[6]; + utoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(long num) +{ + char buf[12]; + ltoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + +unsigned char String::concat(unsigned long num) +{ + char buf[11]; + ultoa(num, buf, 10); + return concat(buf, strlen(buf)); +} + /*********************************************/ /* Concatenate */ /*********************************************/ @@ -258,6 +301,48 @@ StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr) return a; } +StringSumHelper & operator + (const StringSumHelper &lhs, char c) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(c)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + +StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num) +{ + StringSumHelper &a = const_cast(lhs); + if (!a.concat(num)) a.invalidate(); + return a; +} + /*********************************************/ /* Comparison */ /*********************************************/ diff --git a/cores/arduino/WString.h b/cores/arduino/WString.h index 673e51b..a601aca 100644 --- a/cores/arduino/WString.h +++ b/cores/arduino/WString.h @@ -87,25 +87,42 @@ public: String & operator = (StringSumHelper &&rval); #endif - // concat + // concatenate (works w/ built-in types) + // returns true on success, false on failure (in which case, the string // is left unchanged). if the argument is null or invalid, the // concatenation is considered unsucessful. unsigned char concat(const String &str); unsigned char concat(const char *cstr); + unsigned char concat(char c); + unsigned char concat(unsigned char c); + unsigned char concat(int num); + unsigned char concat(unsigned int num); + unsigned char concat(long num); + unsigned char concat(unsigned long num); // if there's not enough memory for the concatenated value, the string // will be left unchanged (but this isn't signalled in any way) String & operator += (const String &rhs) {concat(rhs); return (*this);} String & operator += (const char *cstr) {concat(cstr); return (*this);} + String & operator += (char c) {concat(c); return (*this);} + String & operator += (unsigned char num) {concat(num); return (*this);} + String & operator += (int num) {concat(num); return (*this);} + String & operator += (unsigned int num) {concat(num); return (*this);} + String & operator += (long num) {concat(num); return (*this);} + String & operator += (unsigned long num) {concat(num); return (*this);} - // concatenate friend StringSumHelper & operator + (const StringSumHelper &lhs, const String &rhs); friend StringSumHelper & operator + (const StringSumHelper &lhs, const char *cstr); + friend StringSumHelper & operator + (const StringSumHelper &lhs, char c); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned char num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned int num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, long num); + friend StringSumHelper & operator + (const StringSumHelper &lhs, unsigned long num); - // comparison + // comparison (only works w/ Strings and "strings") operator StringIfHelperType() const { return buffer ? &String::StringIfHelper : 0; } - int compareTo(const String &s) const; unsigned char equals(const String &s) const; unsigned char equals(const char *cstr) const; @@ -176,6 +193,12 @@ class StringSumHelper : public String public: StringSumHelper(const String &s) : String(s) {} StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(unsigned char num) : String(num) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(unsigned int num) : String(num) {} + StringSumHelper(long num) : String(num) {} + StringSumHelper(unsigned long num) : String(num) {} }; #endif // __cplusplus From 2cedbeef132256ceca033f4b5073ab9aba818130 Mon Sep 17 00:00:00 2001 From: amcewen Date: Fri, 1 Apr 2011 21:10:38 +0100 Subject: [PATCH 34/54] Added Printable interface class to allow printing of classes such as IPAddress --- cores/arduino/Print.cpp | 11 +++++++++++ cores/arduino/Print.h | 3 +++ cores/arduino/Printable.h | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+) create mode 100644 cores/arduino/Printable.h diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 4ee556d..f5e77e0 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -101,6 +101,11 @@ void Print::print(double n, int digits) printFloat(n, digits); } +void Print::print(const Printable& x) +{ + x.printTo(*this); +} + void Print::println(void) { print('\r'); @@ -161,6 +166,12 @@ void Print::println(double n, int digits) println(); } +void Print::println(const Printable& x) +{ + print(x); + println(); +} + // Private Methods ///////////////////////////////////////////////////////////// void Print::printNumber(unsigned long n, uint8_t base) diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index b092ae5..d2014bf 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -24,6 +24,7 @@ #include // for size_t #include "WString.h" +#include "Printable.h" #define DEC 10 #define HEX 16 @@ -50,6 +51,7 @@ class Print void print(long, int = DEC); void print(unsigned long, int = DEC); void print(double, int = 2); + void print(const Printable&); void println(const String &s); void println(const char[]); @@ -60,6 +62,7 @@ class Print void println(long, int = DEC); void println(unsigned long, int = DEC); void println(double, int = 2); + void println(const Printable&); void println(void); }; diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h new file mode 100644 index 0000000..fc64858 --- /dev/null +++ b/cores/arduino/Printable.h @@ -0,0 +1,32 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. 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 Printable_h +#define Printable_h + +class Print; + +class Printable +{ + public: + virtual void printTo(Print& p) const =0; +}; + +#endif + From 49155d0a4604eb50d756527ef9512499d2ea6cf4 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sat, 2 Apr 2011 11:33:27 +0100 Subject: [PATCH 35/54] Added a brief explanation of how you'd use Printable --- cores/arduino/Printable.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index fc64858..e5d7732 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -22,6 +22,12 @@ class Print; +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ + class Printable { public: From edee02eaf19c4d13324959e6db881dc327342561 Mon Sep 17 00:00:00 2001 From: amcewen Date: Sun, 10 Apr 2011 11:34:40 +0100 Subject: [PATCH 36/54] Added virtual destructor to Printable, which also requires new and delete operators to be added --- cores/arduino/Printable.h | 3 +++ cores/arduino/new.cpp | 18 ++++++++++++++++++ cores/arduino/new.h | 22 ++++++++++++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 cores/arduino/new.cpp create mode 100644 cores/arduino/new.h diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index e5d7732..5ff6077 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -20,6 +20,8 @@ #ifndef Printable_h #define Printable_h +#include + class Print; /** The Printable class provides a way for new classes to allow themselves to be printed. @@ -31,6 +33,7 @@ class Print; class Printable { public: + virtual ~Printable() {}; virtual void printTo(Print& p) const =0; }; diff --git a/cores/arduino/new.cpp b/cores/arduino/new.cpp new file mode 100644 index 0000000..0f6d422 --- /dev/null +++ b/cores/arduino/new.cpp @@ -0,0 +1,18 @@ +#include + +void * operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void * ptr) +{ + free(ptr); +} + +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; + +void __cxa_pure_virtual(void) {}; + diff --git a/cores/arduino/new.h b/cores/arduino/new.h new file mode 100644 index 0000000..cd940ce --- /dev/null +++ b/cores/arduino/new.h @@ -0,0 +1,22 @@ +/* Header to define new/delete operators as they aren't provided by avr-gcc by default + Taken from http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=59453 + */ + +#ifndef NEW_H +#define NEW_H + +#include + +void * operator new(size_t size); +void operator delete(void * ptr); + +__extension__ typedef int __guard __attribute__((mode (__DI__))); + +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); + +extern "C" void __cxa_pure_virtual(void); + +#endif + From c7c7302d9df5451e6b134d8228bee6c551ca2125 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 7 May 2011 12:05:27 -0400 Subject: [PATCH 37/54] Changing Serial.flush() to write outgoing data, not drop incoming data. This brings it in line with most other uses of flush(), both in and out of Arduino. http://code.google.com/p/arduino/issues/detail?id=497 --- cores/arduino/HardwareSerial.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 1154ae7..74a0641 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -359,16 +359,8 @@ int HardwareSerial::read(void) 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; + while (_tx_buffer->head != _tx_buffer->tail) + ; } void HardwareSerial::write(uint8_t c) From 111c55581b9b5c401843f7ed6b3ce98ceae942bc Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 7 May 2011 12:47:43 -0400 Subject: [PATCH 38/54] Refactoring the UART0 / USART0 receive interrupt handler. --- cores/arduino/HardwareSerial.cpp | 51 +++++++------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 74a0641..91c79d3 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -81,61 +81,32 @@ inline void store_char(unsigned char c, ring_buffer *buffer) } } +#if !defined(USART_RX_vect) && !defined(SIG_USART0_RECV) && \ + !defined(SIG_UART0_RECV) && !defined(USART0_RX_vect) && \ + !defined(SIG_UART_RECV) + #error Don't know what the Data Received vector is called for the first UART +#else #if defined(USART_RX_vect) SIGNAL(USART_RX_vect) - { - #if defined(UDR0) - unsigned char c = UDR0; - #elif defined(UDR) - unsigned char c = UDR; // atmega8535 - #else - #error UDR not defined - #endif - store_char(c, &rx_buffer); - } -#elif defined(SIG_USART0_RECV) && defined(UDR0) +#elif defined(SIG_USART0_RECV) SIGNAL(SIG_USART0_RECV) - { - unsigned char c = UDR0; - store_char(c, &rx_buffer); - } -#elif defined(SIG_UART0_RECV) && defined(UDR0) +#elif defined(SIG_UART0_RECV) SIGNAL(SIG_UART0_RECV) - { - unsigned char c = UDR0; - store_char(c, &rx_buffer); - } -//#elif defined(SIG_USART_RECV) #elif defined(USART0_RX_vect) - // fixed by Mark Sproul this is on the 644/644p - //SIGNAL(SIG_USART_RECV) SIGNAL(USART0_RX_vect) +#elif defined(SIG_UART_RECV) + SIGNAL(SIG_UART_RECV) +#endif { #if defined(UDR0) unsigned char c = UDR0; #elif defined(UDR) - unsigned char c = UDR; // atmega8, atmega32 + unsigned char c = UDR; #else #error UDR not defined #endif store_char(c, &rx_buffer); } -#elif defined(SIG_UART_RECV) - // this is for atmega8 - SIGNAL(SIG_UART_RECV) - { - #if defined(UDR0) - unsigned char c = UDR0; // atmega645 - #elif defined(UDR) - unsigned char c = UDR; // atmega8 - #endif - store_char(c, &rx_buffer); - } -#elif defined(USBCON) - #warning No interrupt handler for usart 0 - #warning Serial(0) is on USB interface -#else - #error No interrupt handler for usart 0 #endif //#if defined(SIG_USART1_RECV) From ac5defcea611319084ca7334b347c061a95e00ac Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 7 May 2011 13:04:13 -0400 Subject: [PATCH 39/54] Adding serialEvent(), serialEvent1(), etc. Called from within the serial receive interrupt. These are implemented as an empty weak function in the core that be overridden by the user's sketch. http://code.google.com/p/arduino/issues/detail?id=263 --- cores/arduino/HardwareSerial.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 91c79d3..9f5ed50 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -86,6 +86,8 @@ inline void store_char(unsigned char c, ring_buffer *buffer) !defined(SIG_UART_RECV) #error Don't know what the Data Received vector is called for the first UART #else + void serialEvent() __attribute__((weak)); + void serialEvent() {} #if defined(USART_RX_vect) SIGNAL(USART_RX_vect) #elif defined(SIG_USART0_RECV) @@ -106,36 +108,44 @@ inline void store_char(unsigned char c, ring_buffer *buffer) #error UDR not defined #endif store_char(c, &rx_buffer); + serialEvent(); } #endif -//#if defined(SIG_USART1_RECV) #if defined(USART1_RX_vect) - //SIGNAL(SIG_USART1_RECV) + void serialEvent1() __attribute__((weak)); + void serialEvent1() {} SIGNAL(USART1_RX_vect) { unsigned char c = UDR1; store_char(c, &rx_buffer1); + serialEvent1(); } #elif defined(SIG_USART1_RECV) #error SIG_USART1_RECV #endif #if defined(USART2_RX_vect) && defined(UDR2) + void serialEvent2() __attribute__((weak)); + void serialEvent2() {} SIGNAL(USART2_RX_vect) { unsigned char c = UDR2; store_char(c, &rx_buffer2); + serialEvent2(); } #elif defined(SIG_USART2_RECV) #error SIG_USART2_RECV #endif #if defined(USART3_RX_vect) && defined(UDR3) + void serialEvent3() __attribute__((weak)); + void serialEvent3() {} SIGNAL(USART3_RX_vect) { unsigned char c = UDR3; store_char(c, &rx_buffer3); + serialEvent3(); } #elif defined(SIG_USART3_RECV) #error SIG_USART3_RECV From 5e5cce81240b39c6068380cd786ac59c2ce88c07 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 7 May 2011 18:17:32 -0400 Subject: [PATCH 40/54] Optimizing printing of numbers (writing a single buffer). Fix from Bill Greiman via Limor. --- cores/arduino/Print.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index eac145f..0a580b7 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -179,25 +179,23 @@ void Print::println(double n, int digits) // 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; +void Print::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; - if (n == 0) { - print('0'); - return; - } + *str = '\0'; - while (n > 0) { - buf[i++] = n % base; + // prevent crash if called with base == 1 + if (base < 2) base = 10; + + do { + unsigned long m = n; n /= base; - } + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); - for (; i > 0; i--) - print((char) (buf[i - 1] < 10 ? - '0' + buf[i - 1] : - 'A' + buf[i - 1] - 10)); + write(str); } void Print::printFloat(double number, uint8_t digits) From 90c487402cefadb6a2aab907ab07075cbb759e34 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 12 May 2011 16:58:56 -0400 Subject: [PATCH 41/54] Small optimization in HardwareSerial. begin(long) -> begin(unsigned long) Conflicts: hardware/arduino/cores/arduino/HardwareSerial.h --- cores/arduino/HardwareSerial.cpp | 2 +- cores/arduino/HardwareSerial.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 9f5ed50..d6d7b60 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -265,7 +265,7 @@ HardwareSerial::HardwareSerial(ring_buffer *rx_buffer, ring_buffer *tx_buffer, // Public Methods ////////////////////////////////////////////////////////////// -void HardwareSerial::begin(long baud) +void HardwareSerial::begin(unsigned long baud) { uint16_t baud_setting; bool use_u2x = true; diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index d229373..eefdcbe 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -49,7 +49,7 @@ class HardwareSerial : public Stream volatile uint8_t *ucsra, volatile uint8_t *ucsrb, volatile uint8_t *udr, uint8_t rxen, uint8_t txen, uint8_t rxcie, uint8_t udrie, uint8_t u2x); - void begin(long); + void begin(unsigned long); void end(); virtual int available(void); virtual int peek(void); From 664e9af2cd359b6e301c43cbfd21a80f390df5f4 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 14 May 2011 12:25:39 -0400 Subject: [PATCH 42/54] Fixing 300 baud communication for serial. Because UBBR is only 12 bits, we were overflowing it at 300 baud because of the use of the U2X bit. Now we turn off U2X if it would yield a UBBR value that would overflow. Note that this breaks 300 baud communication with the computer on the Uno and Mega 2560 because the 8U2 USB-serial firmware has this same bug (and previously they cancelled each other out). Since, however, it seems more likely that people will need to use 300 baud to communicate with other (legacy) hardware than with the computer, I'm making this change. Issue for 8U2 firmware bug: http://code.google.com/p/arduino/issues/detail?id=542 http://code.google.com/p/arduino/issues/detail?id=522 --- cores/arduino/HardwareSerial.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index d6d7b60..db6b149 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -278,6 +278,8 @@ void HardwareSerial::begin(unsigned long baud) use_u2x = false; } #endif + +try_again: if (use_u2x) { *_ucsra = 1 << _u2x; @@ -286,6 +288,12 @@ void HardwareSerial::begin(unsigned long baud) *_ucsra = 0; baud_setting = (F_CPU / 8 / baud - 1) / 2; } + + if ((baud_setting > 4095) && use_u2x) + { + use_u2x = false; + goto try_again; + } // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register) *_ubrrh = baud_setting >> 8; From a239d2c541094ef5445159360ae5d2d6a93dbf00 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Sat, 4 Jun 2011 09:19:17 -0400 Subject: [PATCH 43/54] Added Printable interface class to allow printing of classes such as IPAddress --- cores/arduino/Print.cpp | 11 +++++++++++ cores/arduino/Print.h | 3 +++ cores/arduino/Printable.h | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 cores/arduino/Printable.h diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 0a580b7..06ac52a 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -117,6 +117,11 @@ void Print::println(const __FlashStringHelper *ifsh) println(); } +void Print::print(const Printable& x) +{ + x.printTo(*this); +} + void Print::println(void) { print('\r'); @@ -177,6 +182,12 @@ void Print::println(double n, int digits) println(); } +void Print::println(const Printable& x) +{ + print(x); + println(); +} + // Private Methods ///////////////////////////////////////////////////////////// void Print::printNumber(unsigned long n, uint8_t base) { diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index a447753..bf10b14 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -24,6 +24,7 @@ #include // for size_t #include "WString.h" +#include "Printable.h" #define DEC 10 #define HEX 16 @@ -50,6 +51,7 @@ class Print void print(long, int = DEC); void print(unsigned long, int = DEC); void print(double, int = 2); + void print(const Printable&); void println(const __FlashStringHelper *); void println(const String &s); @@ -61,6 +63,7 @@ class Print void println(long, int = DEC); void println(unsigned long, int = DEC); void println(double, int = 2); + void println(const Printable&); void println(void); }; diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h new file mode 100644 index 0000000..d332aad --- /dev/null +++ b/cores/arduino/Printable.h @@ -0,0 +1,37 @@ +/* + Printable.h - Interface class that allows printing of complex types + Copyright (c) 2011 Adrian McEwen. 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 Printable_h +#define Printable_h + +class Print; + +/** The Printable class provides a way for new classes to allow themselves to be printed. + By deriving from Printable and implementing the printTo method, it will then be possible + for users to print out instances of this class by passing them into the usual + Print::print and Print::println methods. +*/ +class Printable +{ + public: + virtual void printTo(Print& p) const = 0; +}; + +#endif + From ca1f64682a51c9097ab699694f85aa0a47bee1d0 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 12 Aug 2011 16:59:24 -0400 Subject: [PATCH 44/54] Adding SCL, SDA, and LED #defines. --- pins/mega/pins_arduino.h | 4 ++++ pins/standard/pins_arduino.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/pins/mega/pins_arduino.h b/pins/mega/pins_arduino.h index e3785e4..acbd28f 100644 --- a/pins/mega/pins_arduino.h +++ b/pins/mega/pins_arduino.h @@ -32,6 +32,10 @@ const static uint8_t MOSI = 51; const static uint8_t MISO = 50; const static uint8_t SCK = 52; +const static uint8_t SDA = 20; +const static uint8_t SCL = 21; +const static uint8_t LED = 13; + const static uint8_t A0 = 54; const static uint8_t A1 = 55; const static uint8_t A2 = 56; diff --git a/pins/standard/pins_arduino.h b/pins/standard/pins_arduino.h index 8fabb17..b42755d 100644 --- a/pins/standard/pins_arduino.h +++ b/pins/standard/pins_arduino.h @@ -32,6 +32,10 @@ const static uint8_t MOSI = 11; const static uint8_t MISO = 12; const static uint8_t SCK = 13; +const static uint8_t SDA = 18; +const static uint8_t SCL = 19; +const static uint8_t LED = 13; + const static uint8_t A0 = 14; const static uint8_t A1 = 15; const static uint8_t A2 = 16; From cafbc48008ec9cb5cd68b29a93f59b81423322f7 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 12 Aug 2011 17:31:22 -0400 Subject: [PATCH 45/54] Adding pin-change interrupt pin mapping macros to pins_arduino.h. http://code.google.com/p/arduino/issues/detail?id=490 --- pins/mega/pins_arduino.h | 25 +++++++++++++++++++++++++ pins/standard/pins_arduino.h | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/pins/mega/pins_arduino.h b/pins/mega/pins_arduino.h index acbd28f..b25f858 100644 --- a/pins/mega/pins_arduino.h +++ b/pins/mega/pins_arduino.h @@ -53,6 +53,31 @@ const static uint8_t A13 = 67; const static uint8_t A14 = 68; const static uint8_t A15 = 69; +// A majority of the pins are NOT PCINTs, SO BE WARNED (i.e. you cannot use them as receive pins) +// Only pins available for RECEIVE (TRANSMIT can be on any pin): +// (I've deliberately left out pin mapping to the Hardware USARTs - seems senseless to me) +// Pins: 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 + +#define digitalPinToPCICR(p) ( (((p) >= 10) && ((p) <= 13)) || \ + (((p) >= 50) && ((p) <= 53)) || \ + (((p) >= 62) && ((p) <= 69)) ? (&PCICR) : ((uint8_t *)0) ) + +#define digitalPinToPCICRbit(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? 2 : \ + 0 ) ) + +#define digitalPinToPCMSK(p) ( (((p) >= 10) && ((p) <= 13)) || (((p) >= 50) && ((p) <= 53)) ? (&PCMSK0) : \ + ( (((p) >= 62) && ((p) <= 69)) ? (&PCMSK2) : \ + ((uint8_t *)0) ) ) + +#define digitalPinToPCMSKbit(p) ( (((p) >= 10) && ((p) <= 13)) ? ((p) - 6) : \ + ( ((p) == 50) ? 3 : \ + ( ((p) == 51) ? 2 : \ + ( ((p) == 52) ? 1 : \ + ( ((p) == 53) ? 0 : \ + ( (((p) >= 62) && ((p) <= 69)) ? ((p) - 62) : \ + 0 ) ) ) ) ) ) + #ifdef ARDUINO_MAIN const uint16_t PROGMEM port_to_mode_PGM[] = { diff --git a/pins/standard/pins_arduino.h b/pins/standard/pins_arduino.h index b42755d..8e25435 100644 --- a/pins/standard/pins_arduino.h +++ b/pins/standard/pins_arduino.h @@ -45,6 +45,11 @@ const static uint8_t A5 = 19; const static uint8_t A6 = 20; const static uint8_t A7 = 21; +#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) +#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) +#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) +#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) + #ifdef ARDUINO_MAIN // On the Arduino board, digital pins are also used From 39573e5cf7e5db5f0892fc6d33e0d53ede5e0d17 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 12 Aug 2011 18:27:00 -0400 Subject: [PATCH 46/54] Adding basic macros for analog + digital pin information. http://code.google.com/p/arduino/issues/detail?id=495 --- pins/mega/pins_arduino.h | 5 +++++ pins/standard/pins_arduino.h | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/pins/mega/pins_arduino.h b/pins/mega/pins_arduino.h index b25f858..237173a 100644 --- a/pins/mega/pins_arduino.h +++ b/pins/mega/pins_arduino.h @@ -27,6 +27,11 @@ #include +#define NUM_DIGITAL_PINS 70 +#define NUM_ANALOG_INPUTS 16 +#define analogInputToDigitalPin(p) ((p < 16) ? (p) + 54 : -1) +#define digitalPinHasPWM(p) (((p) >= 2 && (p) <= 13) || ((p) >= 44 && (p)<= 46)) + const static uint8_t SS = 53; const static uint8_t MOSI = 51; const static uint8_t MISO = 50; diff --git a/pins/standard/pins_arduino.h b/pins/standard/pins_arduino.h index 8e25435..3999d1f 100644 --- a/pins/standard/pins_arduino.h +++ b/pins/standard/pins_arduino.h @@ -27,6 +27,16 @@ #include +#define NUM_DIGITAL_PINS 20 +#define NUM_ANALOG_INPUTS 6 +#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1) + +#if defined(__AVR_ATmega8__) +#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11) +#else +#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11) +#endif + const static uint8_t SS = 10; const static uint8_t MOSI = 11; const static uint8_t MISO = 12; From 31ff05504fd862a3dfeace691027cc69af213c1d Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 17 Aug 2011 13:53:49 -0400 Subject: [PATCH 47/54] Integrating Stream searching & parsing (Michael Margolis) This from Michael's TextFinder library, incorporated into the Stream class: find(), findUntil(), parseInt(), parseFloat(), readChars(), readCharsUntil(), readCharsBetween(), setTimeout(). --- cores/arduino/Stream.cpp | 244 +++++++++++++++++++++++++++++++++++++++ cores/arduino/Stream.h | 64 ++++++++++ 2 files changed, 308 insertions(+) create mode 100644 cores/arduino/Stream.cpp diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp new file mode 100644 index 0000000..dea0aff --- /dev/null +++ b/cores/arduino/Stream.cpp @@ -0,0 +1,244 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + */ + +#include "Arduino.h" +#include "Stream.h" + +#define PARSE_TIMEOUT 5 // default number of seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() +{ + //Serial.println(_timeout); + this->_startMillis = millis(); + while(millis() - this->_startMillis < (this->_timeout * 1000L)) + { + if (this->available() > 0) { + return this->read(); + } + } + return -1; // -1 indicates timeout +} + +// returns the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::getNextDigit() +{ + int c; + do{ + c = timedRead(); + if( c < 0) + return c; // timeout + } + while( c != '-' && (c < '0' || c > '9') ) ; + +return c; +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout( long timeout) // sets the maximum number of seconds to wait +{ + this->_timeout = timeout; +} + + // find returns true if the target string is found +bool Stream::find(char *target) +{ + return findUntil(target, NULL); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(char *target, char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(char *target, size_t targetLen, char *terminator, size_t termLen) +{ + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if( *target == 0) + return true; // return true if target is a null string + while( (c = timedRead()) > 0){ + if( c == target[index]){ + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen){ // return true if all chars in the target match + return true; + } + } + else{ + index = 0; // reset index if any char does not match + } + if(termLen > 0 && c == terminator[termIndex]){ + if(++termIndex >= termLen) + return false; // return false if terminate string found before target string + } + else + termIndex = 0; + } + return false; +} + + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() +{ + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) +{ + boolean isNegative = false; + long value = 0; + int c; + + c = getNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore this charactor + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + c = timedRead(); + } + while( (c >= '0' && c <= '9') || c == skipChar ); + + if(isNegative) + value = -value; + return value; +} + + +// as parseInt but returns a floating point value +float Stream::parseFloat() +{ + parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar){ + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + float fValue; + char c; + float fraction = 1.0; + + c = getNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do{ + if(c == skipChar) + ; // ignore + else if(c == '-') + isNegative = true; + else if (c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + c = timedRead(); + } + while( (c >= '0' && c <= '9') || c == '.' || c == skipChar ); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, null is detected or timeout (see setTimeout) +// returns the number of characters placed in the buffer (0 means no valid data found) +int Stream::readChars( char *buffer, size_t length) +{ + return readCharsUntil( 0, buffer, length); +} + + +// as readChars with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +int Stream::readCharsUntil( char terminator, char *buffer, size_t length) +{ + int index = 0; + *buffer = 0; + while(index < length ){ + int c = timedRead(); + if( c <= 0 ){ + return 0; // timeout returns 0 ! + } + else if( c == terminator){ + buffer[index] = 0; // terminate the string + return index; // data got successfully + } + else{ + buffer[index++] = (char)c; + } + } + buffer[index] = 0; + return index; // here if buffer is full before detecting the terminator +} + + +// read characters found between pre_string and terminator into a buffer +// terminated when the terminator character is matched or the buffer is full +// returns the number of bytes placed in the buffer (0 means no valid data found) +int Stream::readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length) +{ + if( find( pre_string) ){ + return readCharsUntil(terminator, buffer, length); + } + return 0; //failed to find the prestring +} diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index 93d8275..3f76392 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -15,6 +15,8 @@ You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis */ #ifndef Stream_h @@ -23,13 +25,75 @@ #include #include "Print.h" +// compatability macros for testing +/* +#define getInt() parseInt() +#define getInt(skipChar) parseInt(skipchar) +#define getFloat() parseFloat() +#define getFloat(skipChar) parseFloat(skipChar) +#define getString( pre_string, post_string, buffer, length) +readBytesBetween( pre_string, terminator, buffer, length) +*/ + class Stream : public Print { + private: + long _timeout; // number of seconds to wait for the next char before aborting timed read + long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int getNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + public: virtual int available() = 0; virtual int read() = 0; virtual int peek() = 0; virtual void flush() = 0; + + Stream() {_timeout=5;} + +// parsing methods + + void setTimeout(long timeout); // sets maximum seconds to wait for stream data, default is 5 seconds + + bool find(char *target); // reads data from the stream until the target string is found + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(char *target, size_t length); // reads data from the stream until the target string of given length is found + // returns true if target string is found, false if timed out + + bool findUntil(char *target, char *terminator); // as find but search ends if the terminator string is found + + bool findUntil(char *target, size_t targetLen, char *terminate, size_t termLen); // as above but search ends if the terminate string is found + + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(); // float version of parseInt + + float parseFloat(char skipChar); // as above but the given skipChar is ignored + + int readChars( char *buffer, size_t length); // read chars from stream into buffer + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + int readCharsUntil( char terminator, char *buffer, size_t length); // as readChars with terminator character + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + int readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length); + // read characters found between pre_string and terminator into a buffer + // terminated when the terminator character is matched or the buffer is full + // returns the number of bytes placed in the buffer (0 means no valid data found) + + + // Arduino String functions to be added here + }; #endif From 8dd6a40334613ce1c0c575a93bcd86ee1b109be6 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Wed, 17 Aug 2011 14:16:47 -0400 Subject: [PATCH 48/54] A few API changes to new Stream parsing functions. Renamed readChars() -> readBytes(), readCharsUntil() -> readBytesUntil(). Changed timeouts to milliseconds from seconds; default from 5 to 1 seconds. Removed readCharsBetween(). --- cores/arduino/Stream.cpp | 25 +++++++------------------ cores/arduino/Stream.h | 16 +++++----------- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index dea0aff..bf8304f 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -23,7 +23,7 @@ #include "Arduino.h" #include "Stream.h" -#define PARSE_TIMEOUT 5 // default number of seconds to wait +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field // private method to read stream with timeout @@ -31,7 +31,7 @@ int Stream::timedRead() { //Serial.println(_timeout); this->_startMillis = millis(); - while(millis() - this->_startMillis < (this->_timeout * 1000L)) + while(millis() - this->_startMillis < this->_timeout) { if (this->available() > 0) { return this->read(); @@ -58,7 +58,7 @@ return c; // Public Methods ////////////////////////////////////////////////////////////// -void Stream::setTimeout( long timeout) // sets the maximum number of seconds to wait +void Stream::setTimeout( long timeout) // sets the maximum number of milliseconds to wait { this->_timeout = timeout; } @@ -200,17 +200,17 @@ float Stream::parseFloat(char skipChar){ // read characters from stream into buffer // terminates if length characters have been read, null is detected or timeout (see setTimeout) // returns the number of characters placed in the buffer (0 means no valid data found) -int Stream::readChars( char *buffer, size_t length) +int Stream::readBytes( char *buffer, size_t length) { - return readCharsUntil( 0, buffer, length); + return readBytesUntil( 0, buffer, length); } -// as readChars with terminator character +// as readBytes with terminator character // terminates if length characters have been read, timeout, or if the terminator character detected // returns the number of characters placed in the buffer (0 means no valid data found) -int Stream::readCharsUntil( char terminator, char *buffer, size_t length) +int Stream::readBytesUntil( char terminator, char *buffer, size_t length) { int index = 0; *buffer = 0; @@ -231,14 +231,3 @@ int Stream::readCharsUntil( char terminator, char *buffer, size_t length) return index; // here if buffer is full before detecting the terminator } - -// read characters found between pre_string and terminator into a buffer -// terminated when the terminator character is matched or the buffer is full -// returns the number of bytes placed in the buffer (0 means no valid data found) -int Stream::readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length) -{ - if( find( pre_string) ){ - return readCharsUntil(terminator, buffer, length); - } - return 0; //failed to find the prestring -} diff --git a/cores/arduino/Stream.h b/cores/arduino/Stream.h index 3f76392..1633f15 100644 --- a/cores/arduino/Stream.h +++ b/cores/arduino/Stream.h @@ -38,7 +38,7 @@ readBytesBetween( pre_string, terminator, buffer, length) class Stream : public Print { private: - long _timeout; // number of seconds to wait for the next char before aborting timed read + long _timeout; // number of milliseconds to wait for the next char before aborting timed read long _startMillis; // used for timeout measurement int timedRead(); // private method to read stream with timeout int getNextDigit(); // returns the next numeric digit in the stream or -1 if timeout @@ -49,11 +49,11 @@ class Stream : public Print virtual int peek() = 0; virtual void flush() = 0; - Stream() {_timeout=5;} + Stream() {_timeout=1000;} // parsing methods - void setTimeout(long timeout); // sets maximum seconds to wait for stream data, default is 5 seconds + void setTimeout(long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second bool find(char *target); // reads data from the stream until the target string is found // returns true if target string is found, false if timed out (see setTimeout) @@ -78,20 +78,14 @@ class Stream : public Print float parseFloat(char skipChar); // as above but the given skipChar is ignored - int readChars( char *buffer, size_t length); // read chars from stream into buffer + int readBytes( char *buffer, size_t length); // read chars from stream into buffer // terminates if length characters have been read or timeout (see setTimeout) // returns the number of characters placed in the buffer (0 means no valid data found) - int readCharsUntil( char terminator, char *buffer, size_t length); // as readChars with terminator character + int readBytesUntil( char terminator, char *buffer, size_t length); // as readBytes with terminator character // terminates if length characters have been read, timeout, or if the terminator character detected // returns the number of characters placed in the buffer (0 means no valid data found) - int readCharsBetween( char *pre_string, char terminator, char *buffer, size_t length); - // read characters found between pre_string and terminator into a buffer - // terminated when the terminator character is matched or the buffer is full - // returns the number of bytes placed in the buffer (0 means no valid data found) - - // Arduino String functions to be added here }; From 9bc7be0d9a52edf77cf65554bce8a43123953107 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Thu, 18 Aug 2011 15:13:47 -0400 Subject: [PATCH 49/54] Stream.readBytesUntil() now writes null terminator within length. --- cores/arduino/Stream.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/arduino/Stream.cpp b/cores/arduino/Stream.cpp index bf8304f..d267bf0 100644 --- a/cores/arduino/Stream.cpp +++ b/cores/arduino/Stream.cpp @@ -214,7 +214,7 @@ int Stream::readBytesUntil( char terminator, char *buffer, size_t length) { int index = 0; *buffer = 0; - while(index < length ){ + while(index < length-1 ){ int c = timedRead(); if( c <= 0 ){ return 0; // timeout returns 0 ! From 69d1826e456781cfa33300e6fb4edc007dcc0fd3 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 23 Aug 2011 17:07:39 -0400 Subject: [PATCH 50/54] Renaming pins/ directory to the more generic variants/ http://code.google.com/p/arduino/issues/detail?id=588 --- boards.txt | 34 +++++++++++----------- {pins => variants}/mega/pins_arduino.h | 0 {pins => variants}/standard/pins_arduino.h | 0 3 files changed, 17 insertions(+), 17 deletions(-) rename {pins => variants}/mega/pins_arduino.h (100%) rename {pins => variants}/standard/pins_arduino.h (100%) diff --git a/boards.txt b/boards.txt index 88a7143..8a2af11 100644 --- a/boards.txt +++ b/boards.txt @@ -14,7 +14,7 @@ uno.bootloader.lock_bits=0x0F uno.build.mcu=atmega328p uno.build.f_cpu=16000000L uno.build.core=arduino -uno.build.pins=standard +uno.build.variant=standard ############################################################## @@ -35,7 +35,7 @@ atmega328.bootloader.lock_bits=0x0F atmega328.build.mcu=atmega328p atmega328.build.f_cpu=16000000L atmega328.build.core=arduino -atmega328.build.pins=standard +atmega328.build.variant=standard ############################################################## @@ -56,7 +56,7 @@ diecimila.bootloader.lock_bits=0x0F diecimila.build.mcu=atmega168 diecimila.build.f_cpu=16000000L diecimila.build.core=arduino -diecimila.build.pins=standard +diecimila.build.variant=standard ############################################################## @@ -77,7 +77,7 @@ mega2560.bootloader.lock_bits=0x0F mega2560.build.mcu=atmega2560 mega2560.build.f_cpu=16000000L mega2560.build.core=arduino -mega2560.build.pins=mega +mega2560.build.variant=mega ############################################################## @@ -98,7 +98,7 @@ mega.bootloader.lock_bits=0x0F mega.build.mcu=atmega1280 mega.build.f_cpu=16000000L mega.build.core=arduino -mega.build.pins=mega +mega.build.variant=mega ############################################################## @@ -119,7 +119,7 @@ mini.bootloader.lock_bits=0x0F mini.build.mcu=atmega168 mini.build.f_cpu=16000000L mini.build.core=arduino -mini.build.pins=standard +mini.build.variant=standard ############################################################## @@ -140,7 +140,7 @@ fio.bootloader.lock_bits=0x0F fio.build.mcu=atmega328p fio.build.f_cpu=8000000L fio.build.core=arduino -fio.build.pins=standard +fio.build.variant=standard ############################################################## @@ -162,7 +162,7 @@ bt328.bootloader.lock_bits=0x0F bt328.build.mcu=atmega328p bt328.build.f_cpu=16000000L bt328.build.core=arduino -bt328.build.pins=standard +bt328.build.variant=standard ############################################################## @@ -184,7 +184,7 @@ bt.bootloader.lock_bits=0x0F bt.build.mcu=atmega168 bt.build.f_cpu=16000000L bt.build.core=arduino -bt.build.pins=standard +bt.build.variant=standard ############################################################## @@ -205,7 +205,7 @@ lilypad328.bootloader.lock_bits=0x0F lilypad328.build.mcu=atmega328p lilypad328.build.f_cpu=8000000L lilypad328.build.core=arduino -lilypad328.build.pins=standard +lilypad328.build.variant=standard ############################################################## @@ -226,7 +226,7 @@ lilypad.bootloader.lock_bits=0x0F lilypad.build.mcu=atmega168 lilypad.build.f_cpu=8000000L lilypad.build.core=arduino -lilypad.build.pins=standard +lilypad.build.variant=standard ############################################################## @@ -247,7 +247,7 @@ pro5v328.bootloader.lock_bits=0x0F pro5v328.build.mcu=atmega328p pro5v328.build.f_cpu=16000000L pro5v328.build.core=arduino -pro5v328.build.pins=standard +pro5v328.build.variant=standard ############################################################## @@ -268,7 +268,7 @@ pro5v.bootloader.lock_bits=0x0F pro5v.build.mcu=atmega168 pro5v.build.f_cpu=16000000L pro5v.build.core=arduino -pro5v.build.pins=standard +pro5v.build.variant=standard ############################################################## @@ -289,7 +289,7 @@ pro328.bootloader.lock_bits=0x0F pro328.build.mcu=atmega328p pro328.build.f_cpu=8000000L pro328.build.core=arduino -pro328.build.pins=standard +pro328.build.variant=standard ############################################################## @@ -310,7 +310,7 @@ pro.bootloader.lock_bits=0x0F pro.build.mcu=atmega168 pro.build.f_cpu=8000000L pro.build.core=arduino -pro.build.pins=standard +pro.build.variant=standard ############################################################## @@ -331,7 +331,7 @@ atmega168.bootloader.lock_bits=0x0F atmega168.build.mcu=atmega168 atmega168.build.f_cpu=16000000L atmega168.build.core=arduino -atmega168.build.pins=standard +atmega168.build.variant=standard ############################################################## @@ -351,4 +351,4 @@ atmega8.bootloader.lock_bits=0x0F atmega8.build.mcu=atmega8 atmega8.build.f_cpu=16000000L atmega8.build.core=arduino -atmega8.build.pins=standard +atmega8.build.variant=standard diff --git a/pins/mega/pins_arduino.h b/variants/mega/pins_arduino.h similarity index 100% rename from pins/mega/pins_arduino.h rename to variants/mega/pins_arduino.h diff --git a/pins/standard/pins_arduino.h b/variants/standard/pins_arduino.h similarity index 100% rename from pins/standard/pins_arduino.h rename to variants/standard/pins_arduino.h From f5a15cb62f7257bf26cdedf30ce13f8cff802f79 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 23 Aug 2011 17:29:20 -0400 Subject: [PATCH 51/54] Distinguishing those boards with eight analog inputs (Fio, BT, Nano, Mini). http://code.google.com/p/arduino/issues/detail?id=499 --- boards.txt | 54 ++++++++++++++++++++--- variants/eightanaloginputs/pins_arduino.h | 27 ++++++++++++ 2 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 variants/eightanaloginputs/pins_arduino.h diff --git a/boards.txt b/boards.txt index 8a2af11..7adac62 100644 --- a/boards.txt +++ b/boards.txt @@ -18,7 +18,7 @@ uno.build.variant=standard ############################################################## -atmega328.name=Arduino Duemilanove or Nano w/ ATmega328 +atmega328.name=Arduino Duemilanove w/ ATmega328 atmega328.upload.protocol=stk500 atmega328.upload.maximum_size=30720 @@ -39,7 +39,7 @@ atmega328.build.variant=standard ############################################################## -diecimila.name=Arduino Diecimila, Duemilanove, or Nano w/ ATmega168 +diecimila.name=Arduino Diecimila or Duemilanove w/ ATmega168 diecimila.upload.protocol=stk500 diecimila.upload.maximum_size=14336 @@ -60,6 +60,48 @@ diecimila.build.variant=standard ############################################################## +nano328.name=Arduino Nano w/ ATmega328 + +nano328.upload.protocol=stk500 +nano328.upload.maximum_size=30720 +nano328.upload.speed=57600 + +nano328.bootloader.low_fuses=0xFF +nano328.bootloader.high_fuses=0xDA +nano328.bootloader.extended_fuses=0x05 +nano328.bootloader.path=atmega +nano328.bootloader.file=ATmegaBOOT_168_atmega328.hex +nano328.bootloader.unlock_bits=0x3F +nano328.bootloader.lock_bits=0x0F + +nano328.build.mcu=atmega328p +nano328.build.f_cpu=16000000L +nano328.build.core=arduino +nano328.build.variant=eightanaloginputs + +############################################################## + +nano.name=Arduino Nano w/ ATmega168 + +nano.upload.protocol=stk500 +nano.upload.maximum_size=14336 +nano.upload.speed=19200 + +nano.bootloader.low_fuses=0xff +nano.bootloader.high_fuses=0xdd +nano.bootloader.extended_fuses=0x00 +nano.bootloader.path=atmega +nano.bootloader.file=ATmegaBOOT_168_diecimila.hex +nano.bootloader.unlock_bits=0x3F +nano.bootloader.lock_bits=0x0F + +nano.build.mcu=atmega168 +nano.build.f_cpu=16000000L +nano.build.core=arduino +nano.build.variant=eightanaloginputs + +############################################################## + mega2560.name=Arduino Mega 2560 mega2560.upload.protocol=stk500v2 @@ -119,7 +161,7 @@ mini.bootloader.lock_bits=0x0F mini.build.mcu=atmega168 mini.build.f_cpu=16000000L mini.build.core=arduino -mini.build.variant=standard +mini.build.variant=eightanaloginputs ############################################################## @@ -140,7 +182,7 @@ fio.bootloader.lock_bits=0x0F fio.build.mcu=atmega328p fio.build.f_cpu=8000000L fio.build.core=arduino -fio.build.variant=standard +fio.build.variant=eightanaloginputs ############################################################## @@ -162,7 +204,7 @@ bt328.bootloader.lock_bits=0x0F bt328.build.mcu=atmega328p bt328.build.f_cpu=16000000L bt328.build.core=arduino -bt328.build.variant=standard +bt328.build.variant=eightanaloginputs ############################################################## @@ -184,7 +226,7 @@ bt.bootloader.lock_bits=0x0F bt.build.mcu=atmega168 bt.build.f_cpu=16000000L bt.build.core=arduino -bt.build.variant=standard +bt.build.variant=eightanaloginputs ############################################################## diff --git a/variants/eightanaloginputs/pins_arduino.h b/variants/eightanaloginputs/pins_arduino.h new file mode 100644 index 0000000..52b37ef --- /dev/null +++ b/variants/eightanaloginputs/pins_arduino.h @@ -0,0 +1,27 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#include "../standard/pins_arduino.h" +#undef NUM_ANALOG_INPUTS +#define NUM_ANALOG_INPUTS 8 From f282cbaf968f7142ef5abb68a92e970c3d5eea35 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Tue, 23 Aug 2011 19:12:03 -0400 Subject: [PATCH 52/54] write(), print(), and println() now return number of bytes written. The type is long, and negative values indicate errors. Needs more testing. http://code.google.com/p/arduino/issues/detail?id=551 --- cores/arduino/HardwareSerial.cpp | 5 +- cores/arduino/HardwareSerial.h | 2 +- cores/arduino/Print.cpp | 194 +++++++++++++++++++------------ cores/arduino/Print.h | 56 ++++----- cores/arduino/Printable.h | 2 +- 5 files changed, 151 insertions(+), 108 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index db6b149..a200da5 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -352,12 +352,13 @@ void HardwareSerial::flush() ; } -void HardwareSerial::write(uint8_t c) +long HardwareSerial::write(uint8_t c) { int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; // If the output buffer is full, there's nothing for it other than to // wait for the interrupt handler to empty it a bit + // ???: return 0 here instead? while (i == _tx_buffer->tail) ; @@ -365,6 +366,8 @@ void HardwareSerial::write(uint8_t c) _tx_buffer->head = i; sbi(*_ucsrb, _udrie); + + return 1; } // Preinstantiate Objects ////////////////////////////////////////////////////// diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index eefdcbe..4af8c59 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -55,7 +55,7 @@ class HardwareSerial : public Stream virtual int peek(void); virtual int read(void); virtual void flush(void); - virtual void write(uint8_t); + virtual long write(uint8_t); using Print::write; // pull in write(str) and write(buf, size) from Print }; diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 06ac52a..58b1032 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -30,167 +30,196 @@ // Public Methods ////////////////////////////////////////////////////////////// /* default implementation: may be overridden */ -void Print::write(const char *str) +long Print::write(const char *str) { - while (*str) - write(*str++); + long n = 0; + while (*str) { + if (write(*str++) <= 0) break; + n++; + } + return n; } /* default implementation: may be overridden */ -void Print::write(const uint8_t *buffer, size_t size) +long Print::write(const uint8_t *buffer, size_t size) { - while (size--) - write(*buffer++); + long n = 0; + while (size--) { + if (write(*buffer++) <= 0) break; + n++; + } + return n; } -void Print::print(const __FlashStringHelper *ifsh) +long Print::print(const __FlashStringHelper *ifsh) { const prog_char *p = (const prog_char *)ifsh; + long n = 0; while (1) { unsigned char c = pgm_read_byte(p++); - if (c == 0) return; - write(c); + if (c == 0) break; + if (write(c) <= 0) break; + n++; } + return n; } -void Print::print(const String &s) +long Print::print(const String &s) { + long n = 0; for (int i = 0; i < s.length(); i++) { - write(s[i]); + if (write(s[i]) < 0) break; + n++; } + return n; } -void Print::print(const char str[]) +long Print::print(const char str[]) { - write(str); + return write(str); } -void Print::print(char c) +long Print::print(char c) { - write(c); + return write(c); } -void Print::print(unsigned char b, int base) +long Print::print(unsigned char b, int base) { - print((unsigned long) b, base); + return print((unsigned long) b, base); } -void Print::print(int n, int base) +long Print::print(int n, int base) { - print((long) n, base); + return print((long) n, base); } -void Print::print(unsigned int n, int base) +long Print::print(unsigned int n, int base) { - print((unsigned long) n, base); + return print((unsigned long) n, base); } -void Print::print(long n, int base) +long Print::print(long n, int base) { if (base == 0) { - write(n); + return write(n); } else if (base == 10) { if (n < 0) { - print('-'); + long t = print('-'); + if (t <= 0) return t; n = -n; + return printNumber(n, 10) + 1; } - printNumber(n, 10); + return printNumber(n, 10); } else { - printNumber(n, base); + return printNumber(n, base); } } -void Print::print(unsigned long n, int base) +long Print::print(unsigned long n, int base) { - if (base == 0) write(n); - else printNumber(n, base); + if (base == 0) return write(n); + else return printNumber(n, base); } -void Print::print(double n, int digits) +long Print::print(double n, int digits) { - printFloat(n, digits); + return printFloat(n, digits); } -void Print::println(const __FlashStringHelper *ifsh) +long Print::println(const __FlashStringHelper *ifsh) { - print(ifsh); - println(); + long n = print(ifsh); + if (n >= 0) n += println(); + return n; } -void Print::print(const Printable& x) +long Print::print(const Printable& x) { - x.printTo(*this); + return x.printTo(*this); } -void Print::println(void) +long Print::println(void) { - print('\r'); - print('\n'); + long t = print('\r'); + if (t <= 0) return t; + if (print('\n') <= 0) return 1; + return 2; } -void Print::println(const String &s) +long Print::println(const String &s) { - print(s); - println(); + long n = print(s); + if (n >= 0) n += println(); + return n; } -void Print::println(const char c[]) +long Print::println(const char c[]) { - print(c); - println(); + long n = print(c); + if (n >= 0) n += println(); + return n; } -void Print::println(char c) +long Print::println(char c) { - print(c); - println(); + long n = print(c); + if (n > 0) n += println(); + return n; } -void Print::println(unsigned char b, int base) +long Print::println(unsigned char b, int base) { - print(b, base); - println(); + long n = print(b, base); + if (n >= 0) n += println(); + return n; } -void Print::println(int n, int base) +long Print::println(int num, int base) { - print(n, base); - println(); + long n = print(num, base); + if (n >= 0) n += println(); + return n; } -void Print::println(unsigned int n, int base) +long Print::println(unsigned int num, int base) { - print(n, base); - println(); + long n = print(num, base); + if (n >= 0) n += println(); + return n; } -void Print::println(long n, int base) +long Print::println(long num, int base) { - print(n, base); - println(); + long n = print(num, base); + if (n >= 0) n += println(); + return n; } -void Print::println(unsigned long n, int base) +long Print::println(unsigned long num, int base) { - print(n, base); - println(); + long n = print(num, base); + if (n >= 0) n += println(); + return n; } -void Print::println(double n, int digits) +long Print::println(double num, int digits) { - print(n, digits); - println(); + long n = print(num, digits); + if (n >= 0) n += println(); + return n; } -void Print::println(const Printable& x) +long Print::println(const Printable& x) { - print(x); - println(); + long n = print(x); + if (n >= 0) n += println(); + return n; } // Private Methods ///////////////////////////////////////////////////////////// -void Print::printNumber(unsigned long n, uint8_t base) { +long Print::printNumber(unsigned long n, uint8_t base) { char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. char *str = &buf[sizeof(buf) - 1]; @@ -206,15 +235,17 @@ void Print::printNumber(unsigned long n, uint8_t base) { *--str = c < 10 ? c + '0' : c + 'A' - 10; } while(n); - write(str); + return write(str); } -void Print::printFloat(double number, uint8_t digits) +long Print::printFloat(double number, uint8_t digits) { + long n = 0, t; + // Handle negative numbers if (number < 0.0) { - print('-'); + if ((n = print('-')) <= 0) return n; number = -number; } @@ -228,18 +259,27 @@ void Print::printFloat(double number, uint8_t digits) // Extract the integer part of the number and print it unsigned long int_part = (unsigned long)number; double remainder = number - (double)int_part; - print(int_part); + if ((t = print(int_part)) < 0) return n; + + n += t; // Print the decimal point, but only if there are digits beyond - if (digits > 0) - print("."); + if (digits > 0) { + t = print("."); + if (t <= 0) return n; + n += t; + } // Extract digits from the remainder one at a time while (digits-- > 0) { remainder *= 10.0; int toPrint = int(remainder); - print(toPrint); + t = print(toPrint); + if (t <= 0) return n; + n += t; remainder -= toPrint; } + + return n; } diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index bf10b14..d5b02ff 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -34,37 +34,37 @@ class Print { private: - void printNumber(unsigned long, uint8_t); - void printFloat(double, uint8_t); + long printNumber(unsigned long, uint8_t); + long 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); + virtual long write(uint8_t) = 0; + virtual long write(const char *str); + virtual long write(const uint8_t *buffer, size_t size); - void print(const __FlashStringHelper *); - void print(const String &); - void print(const char[]); - void print(char); - void print(unsigned char, int = DEC); - void print(int, int = DEC); - void print(unsigned int, int = DEC); - void print(long, int = DEC); - void print(unsigned long, int = DEC); - void print(double, int = 2); - void print(const Printable&); + long print(const __FlashStringHelper *); + long print(const String &); + long print(const char[]); + long print(char); + long print(unsigned char, int = DEC); + long print(int, int = DEC); + long print(unsigned int, int = DEC); + long print(long, int = DEC); + long print(unsigned long, int = DEC); + long print(double, int = 2); + long print(const Printable&); - void println(const __FlashStringHelper *); - void println(const String &s); - void println(const char[]); - void println(char); - void println(unsigned char, int = DEC); - void println(int, int = DEC); - void println(unsigned int, int = DEC); - void println(long, int = DEC); - void println(unsigned long, int = DEC); - void println(double, int = 2); - void println(const Printable&); - void println(void); + long println(const __FlashStringHelper *); + long println(const String &s); + long println(const char[]); + long println(char); + long println(unsigned char, int = DEC); + long println(int, int = DEC); + long println(unsigned int, int = DEC); + long println(long, int = DEC); + long println(unsigned long, int = DEC); + long println(double, int = 2); + long println(const Printable&); + long println(void); }; #endif diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index d332aad..6814ee4 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -30,7 +30,7 @@ class Print; class Printable { public: - virtual void printTo(Print& p) const = 0; + virtual long printTo(Print& p) const = 0; }; #endif From 0635790dd111e91e5c488acc599cc404dc707abd Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 26 Aug 2011 14:20:41 -0400 Subject: [PATCH 53/54] Changing from long to ssize_t (int) for write(), print(), println() return. --- cores/arduino/HardwareSerial.cpp | 2 +- cores/arduino/HardwareSerial.h | 2 +- cores/arduino/Print.cpp | 90 ++++++++++++++++---------------- cores/arduino/Print.h | 58 ++++++++++---------- cores/arduino/Printable.h | 2 +- 5 files changed, 78 insertions(+), 76 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index a200da5..641c973 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -352,7 +352,7 @@ void HardwareSerial::flush() ; } -long HardwareSerial::write(uint8_t c) +ssize_t HardwareSerial::write(uint8_t c) { int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 4af8c59..960d3f5 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -55,7 +55,7 @@ class HardwareSerial : public Stream virtual int peek(void); virtual int read(void); virtual void flush(void); - virtual long write(uint8_t); + virtual ssize_t write(uint8_t); using Print::write; // pull in write(str) and write(buf, size) from Print }; diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 58b1032..192d9a3 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -30,9 +30,9 @@ // Public Methods ////////////////////////////////////////////////////////////// /* default implementation: may be overridden */ -long Print::write(const char *str) +ssize_t Print::write(const char *str) { - long n = 0; + ssize_t n = 0; while (*str) { if (write(*str++) <= 0) break; n++; @@ -41,9 +41,9 @@ long Print::write(const char *str) } /* default implementation: may be overridden */ -long Print::write(const uint8_t *buffer, size_t size) +ssize_t Print::write(const uint8_t *buffer, size_t size) { - long n = 0; + ssize_t n = 0; while (size--) { if (write(*buffer++) <= 0) break; n++; @@ -51,10 +51,10 @@ long Print::write(const uint8_t *buffer, size_t size) return n; } -long Print::print(const __FlashStringHelper *ifsh) +ssize_t Print::print(const __FlashStringHelper *ifsh) { const prog_char *p = (const prog_char *)ifsh; - long n = 0; + ssize_t n = 0; while (1) { unsigned char c = pgm_read_byte(p++); if (c == 0) break; @@ -64,9 +64,9 @@ long Print::print(const __FlashStringHelper *ifsh) return n; } -long Print::print(const String &s) +ssize_t Print::print(const String &s) { - long n = 0; + ssize_t n = 0; for (int i = 0; i < s.length(); i++) { if (write(s[i]) < 0) break; n++; @@ -74,38 +74,38 @@ long Print::print(const String &s) return n; } -long Print::print(const char str[]) +ssize_t Print::print(const char str[]) { return write(str); } -long Print::print(char c) +ssize_t Print::print(char c) { return write(c); } -long Print::print(unsigned char b, int base) +ssize_t Print::print(unsigned char b, int base) { return print((unsigned long) b, base); } -long Print::print(int n, int base) +ssize_t Print::print(int n, int base) { return print((long) n, base); } -long Print::print(unsigned int n, int base) +ssize_t Print::print(unsigned int n, int base) { return print((unsigned long) n, base); } -long Print::print(long n, int base) +ssize_t Print::print(long n, int base) { if (base == 0) { return write(n); } else if (base == 10) { if (n < 0) { - long t = print('-'); + int t = print('-'); if (t <= 0) return t; n = -n; return printNumber(n, 10) + 1; @@ -116,110 +116,110 @@ long Print::print(long n, int base) } } -long Print::print(unsigned long n, int base) +ssize_t Print::print(unsigned long n, int base) { if (base == 0) return write(n); else return printNumber(n, base); } -long Print::print(double n, int digits) +ssize_t Print::print(double n, int digits) { return printFloat(n, digits); } -long Print::println(const __FlashStringHelper *ifsh) +ssize_t Print::println(const __FlashStringHelper *ifsh) { - long n = print(ifsh); + ssize_t n = print(ifsh); if (n >= 0) n += println(); return n; } -long Print::print(const Printable& x) +ssize_t Print::print(const Printable& x) { return x.printTo(*this); } -long Print::println(void) +ssize_t Print::println(void) { - long t = print('\r'); + ssize_t t = print('\r'); if (t <= 0) return t; if (print('\n') <= 0) return 1; return 2; } -long Print::println(const String &s) +ssize_t Print::println(const String &s) { - long n = print(s); + ssize_t n = print(s); if (n >= 0) n += println(); return n; } -long Print::println(const char c[]) +ssize_t Print::println(const char c[]) { - long n = print(c); + ssize_t n = print(c); if (n >= 0) n += println(); return n; } -long Print::println(char c) +ssize_t Print::println(char c) { - long n = print(c); + ssize_t n = print(c); if (n > 0) n += println(); return n; } -long Print::println(unsigned char b, int base) +ssize_t Print::println(unsigned char b, int base) { - long n = print(b, base); + ssize_t n = print(b, base); if (n >= 0) n += println(); return n; } -long Print::println(int num, int base) +ssize_t Print::println(int num, int base) { - long n = print(num, base); + ssize_t n = print(num, base); if (n >= 0) n += println(); return n; } -long Print::println(unsigned int num, int base) +ssize_t Print::println(unsigned int num, int base) { - long n = print(num, base); + ssize_t n = print(num, base); if (n >= 0) n += println(); return n; } -long Print::println(long num, int base) +ssize_t Print::println(long num, int base) { - long n = print(num, base); + ssize_t n = print(num, base); if (n >= 0) n += println(); return n; } -long Print::println(unsigned long num, int base) +ssize_t Print::println(unsigned long num, int base) { - long n = print(num, base); + ssize_t n = print(num, base); if (n >= 0) n += println(); return n; } -long Print::println(double num, int digits) +ssize_t Print::println(double num, int digits) { - long n = print(num, digits); + ssize_t n = print(num, digits); if (n >= 0) n += println(); return n; } -long Print::println(const Printable& x) +ssize_t Print::println(const Printable& x) { - long n = print(x); + ssize_t n = print(x); if (n >= 0) n += println(); return n; } // Private Methods ///////////////////////////////////////////////////////////// -long Print::printNumber(unsigned long n, uint8_t base) { +ssize_t Print::printNumber(unsigned long n, uint8_t base) { char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. char *str = &buf[sizeof(buf) - 1]; @@ -238,9 +238,9 @@ long Print::printNumber(unsigned long n, uint8_t base) { return write(str); } -long Print::printFloat(double number, uint8_t digits) +ssize_t Print::printFloat(double number, uint8_t digits) { - long n = 0, t; + ssize_t n = 0, t; // Handle negative numbers if (number < 0.0) diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index d5b02ff..3f303f3 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -23,6 +23,8 @@ #include #include // for size_t +typedef int ssize_t; + #include "WString.h" #include "Printable.h" @@ -34,37 +36,37 @@ class Print { private: - long printNumber(unsigned long, uint8_t); - long printFloat(double, uint8_t); + ssize_t printNumber(unsigned long, uint8_t); + ssize_t printFloat(double, uint8_t); public: - virtual long write(uint8_t) = 0; - virtual long write(const char *str); - virtual long write(const uint8_t *buffer, size_t size); + virtual ssize_t write(uint8_t) = 0; + virtual ssize_t write(const char *str); + virtual ssize_t write(const uint8_t *buffer, size_t size); - long print(const __FlashStringHelper *); - long print(const String &); - long print(const char[]); - long print(char); - long print(unsigned char, int = DEC); - long print(int, int = DEC); - long print(unsigned int, int = DEC); - long print(long, int = DEC); - long print(unsigned long, int = DEC); - long print(double, int = 2); - long print(const Printable&); + ssize_t print(const __FlashStringHelper *); + ssize_t print(const String &); + ssize_t print(const char[]); + ssize_t print(char); + ssize_t print(unsigned char, int = DEC); + ssize_t print(int, int = DEC); + ssize_t print(unsigned int, int = DEC); + ssize_t print(long, int = DEC); + ssize_t print(unsigned long, int = DEC); + ssize_t print(double, int = 2); + ssize_t print(const Printable&); - long println(const __FlashStringHelper *); - long println(const String &s); - long println(const char[]); - long println(char); - long println(unsigned char, int = DEC); - long println(int, int = DEC); - long println(unsigned int, int = DEC); - long println(long, int = DEC); - long println(unsigned long, int = DEC); - long println(double, int = 2); - long println(const Printable&); - long println(void); + ssize_t println(const __FlashStringHelper *); + ssize_t println(const String &s); + ssize_t println(const char[]); + ssize_t println(char); + ssize_t println(unsigned char, int = DEC); + ssize_t println(int, int = DEC); + ssize_t println(unsigned int, int = DEC); + ssize_t println(long, int = DEC); + ssize_t println(unsigned long, int = DEC); + ssize_t println(double, int = 2); + ssize_t println(const Printable&); + ssize_t println(void); }; #endif diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index 6814ee4..9065904 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -30,7 +30,7 @@ class Print; class Printable { public: - virtual long printTo(Print& p) const = 0; + virtual ssize_t printTo(Print& p) const = 0; }; #endif From 5130a1329462aa36d5f18e31851d3d9d5086e411 Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Fri, 26 Aug 2011 16:08:14 -0400 Subject: [PATCH 54/54] Moving write errors out of return value into separate API methods. write(), print(), println() now return size_t (and don't use negative values to signal errors). Print adds writeError() for checking for write errors, clearWriteError() to reset the flag to false, and a protected setWriteError() for signalling errors. http://code.google.com/p/arduino/issues/detail?id=598 --- cores/arduino/HardwareSerial.cpp | 2 +- cores/arduino/HardwareSerial.h | 2 +- cores/arduino/Print.cpp | 150 ++++++++++++++----------------- cores/arduino/Print.h | 66 +++++++------- cores/arduino/Printable.h | 2 +- 5 files changed, 108 insertions(+), 114 deletions(-) diff --git a/cores/arduino/HardwareSerial.cpp b/cores/arduino/HardwareSerial.cpp index 641c973..d6be218 100644 --- a/cores/arduino/HardwareSerial.cpp +++ b/cores/arduino/HardwareSerial.cpp @@ -352,7 +352,7 @@ void HardwareSerial::flush() ; } -ssize_t HardwareSerial::write(uint8_t c) +size_t HardwareSerial::write(uint8_t c) { int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE; diff --git a/cores/arduino/HardwareSerial.h b/cores/arduino/HardwareSerial.h index 960d3f5..1895f08 100644 --- a/cores/arduino/HardwareSerial.h +++ b/cores/arduino/HardwareSerial.h @@ -55,7 +55,7 @@ class HardwareSerial : public Stream virtual int peek(void); virtual int read(void); virtual void flush(void); - virtual ssize_t write(uint8_t); + virtual size_t write(uint8_t); using Print::write; // pull in write(str) and write(buf, size) from Print }; diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 192d9a3..8190d4f 100755 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp @@ -30,85 +30,80 @@ // Public Methods ////////////////////////////////////////////////////////////// /* default implementation: may be overridden */ -ssize_t Print::write(const char *str) +size_t Print::write(const char *str) { - ssize_t n = 0; + size_t n = 0; while (*str) { - if (write(*str++) <= 0) break; - n++; + n += write(*str++); } return n; } /* default implementation: may be overridden */ -ssize_t Print::write(const uint8_t *buffer, size_t size) +size_t Print::write(const uint8_t *buffer, size_t size) { - ssize_t n = 0; + size_t n = 0; while (size--) { - if (write(*buffer++) <= 0) break; - n++; + n += write(*buffer++); } return n; } -ssize_t Print::print(const __FlashStringHelper *ifsh) +size_t Print::print(const __FlashStringHelper *ifsh) { const prog_char *p = (const prog_char *)ifsh; - ssize_t n = 0; + size_t n = 0; while (1) { unsigned char c = pgm_read_byte(p++); if (c == 0) break; - if (write(c) <= 0) break; - n++; + n += write(c); } return n; } -ssize_t Print::print(const String &s) +size_t Print::print(const String &s) { - ssize_t n = 0; + size_t n = 0; for (int i = 0; i < s.length(); i++) { - if (write(s[i]) < 0) break; - n++; + n += write(s[i]); } return n; } -ssize_t Print::print(const char str[]) +size_t Print::print(const char str[]) { return write(str); } -ssize_t Print::print(char c) +size_t Print::print(char c) { return write(c); } -ssize_t Print::print(unsigned char b, int base) +size_t Print::print(unsigned char b, int base) { return print((unsigned long) b, base); } -ssize_t Print::print(int n, int base) +size_t Print::print(int n, int base) { return print((long) n, base); } -ssize_t Print::print(unsigned int n, int base) +size_t Print::print(unsigned int n, int base) { return print((unsigned long) n, base); } -ssize_t Print::print(long n, int base) +size_t Print::print(long n, int base) { if (base == 0) { return write(n); } else if (base == 10) { if (n < 0) { int t = print('-'); - if (t <= 0) return t; n = -n; - return printNumber(n, 10) + 1; + return printNumber(n, 10) + t; } return printNumber(n, 10); } else { @@ -116,110 +111,109 @@ ssize_t Print::print(long n, int base) } } -ssize_t Print::print(unsigned long n, int base) +size_t Print::print(unsigned long n, int base) { if (base == 0) return write(n); else return printNumber(n, base); } -ssize_t Print::print(double n, int digits) +size_t Print::print(double n, int digits) { return printFloat(n, digits); } -ssize_t Print::println(const __FlashStringHelper *ifsh) +size_t Print::println(const __FlashStringHelper *ifsh) { - ssize_t n = print(ifsh); - if (n >= 0) n += println(); + size_t n = print(ifsh); + n += println(); return n; } -ssize_t Print::print(const Printable& x) +size_t Print::print(const Printable& x) { return x.printTo(*this); } -ssize_t Print::println(void) +size_t Print::println(void) { - ssize_t t = print('\r'); - if (t <= 0) return t; - if (print('\n') <= 0) return 1; - return 2; -} - -ssize_t Print::println(const String &s) -{ - ssize_t n = print(s); - if (n >= 0) n += println(); + size_t n = print('\r'); + n += print('\n'); return n; } -ssize_t Print::println(const char c[]) +size_t Print::println(const String &s) { - ssize_t n = print(c); - if (n >= 0) n += println(); + size_t n = print(s); + n += println(); return n; } -ssize_t Print::println(char c) +size_t Print::println(const char c[]) { - ssize_t n = print(c); - if (n > 0) n += println(); + size_t n = print(c); + n += println(); return n; } -ssize_t Print::println(unsigned char b, int base) +size_t Print::println(char c) { - ssize_t n = print(b, base); - if (n >= 0) n += println(); + size_t n = print(c); + n += println(); return n; } -ssize_t Print::println(int num, int base) +size_t Print::println(unsigned char b, int base) { - ssize_t n = print(num, base); - if (n >= 0) n += println(); + size_t n = print(b, base); + n += println(); return n; } -ssize_t Print::println(unsigned int num, int base) +size_t Print::println(int num, int base) { - ssize_t n = print(num, base); - if (n >= 0) n += println(); + size_t n = print(num, base); + n += println(); return n; } -ssize_t Print::println(long num, int base) +size_t Print::println(unsigned int num, int base) { - ssize_t n = print(num, base); - if (n >= 0) n += println(); + size_t n = print(num, base); + n += println(); return n; } -ssize_t Print::println(unsigned long num, int base) +size_t Print::println(long num, int base) { - ssize_t n = print(num, base); - if (n >= 0) n += println(); + size_t n = print(num, base); + n += println(); return n; } -ssize_t Print::println(double num, int digits) +size_t Print::println(unsigned long num, int base) { - ssize_t n = print(num, digits); - if (n >= 0) n += println(); + size_t n = print(num, base); + n += println(); return n; } -ssize_t Print::println(const Printable& x) +size_t Print::println(double num, int digits) { - ssize_t n = print(x); - if (n >= 0) n += println(); + size_t n = print(num, digits); + n += println(); + return n; +} + +size_t Print::println(const Printable& x) +{ + size_t n = print(x); + n += println(); return n; } // Private Methods ///////////////////////////////////////////////////////////// -ssize_t Print::printNumber(unsigned long n, uint8_t base) { +size_t Print::printNumber(unsigned long n, uint8_t base) { char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. char *str = &buf[sizeof(buf) - 1]; @@ -238,14 +232,14 @@ ssize_t Print::printNumber(unsigned long n, uint8_t base) { return write(str); } -ssize_t Print::printFloat(double number, uint8_t digits) +size_t Print::printFloat(double number, uint8_t digits) { - ssize_t n = 0, t; + size_t n = 0; // Handle negative numbers if (number < 0.0) { - if ((n = print('-')) <= 0) return n; + n += print('-'); number = -number; } @@ -259,15 +253,11 @@ ssize_t Print::printFloat(double number, uint8_t digits) // Extract the integer part of the number and print it unsigned long int_part = (unsigned long)number; double remainder = number - (double)int_part; - if ((t = print(int_part)) < 0) return n; - - n += t; + n += print(int_part); // Print the decimal point, but only if there are digits beyond if (digits > 0) { - t = print("."); - if (t <= 0) return n; - n += t; + n += print("."); } // Extract digits from the remainder one at a time @@ -275,9 +265,7 @@ ssize_t Print::printFloat(double number, uint8_t digits) { remainder *= 10.0; int toPrint = int(remainder); - t = print(toPrint); - if (t <= 0) return n; - n += t; + n += print(toPrint); remainder -= toPrint; } diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index 3f303f3..fce302e 100755 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h @@ -23,8 +23,6 @@ #include #include // for size_t -typedef int ssize_t; - #include "WString.h" #include "Printable.h" @@ -36,37 +34,45 @@ typedef int ssize_t; class Print { private: - ssize_t printNumber(unsigned long, uint8_t); - ssize_t printFloat(double, uint8_t); + int write_error; + size_t printNumber(unsigned long, uint8_t); + size_t printFloat(double, uint8_t); + protected: + void setWriteError(int err = 1) { write_error = err; } public: - virtual ssize_t write(uint8_t) = 0; - virtual ssize_t write(const char *str); - virtual ssize_t write(const uint8_t *buffer, size_t size); + Print() : write_error(0) {} + + int writeError() { return write_error; } + void clearWriteError() { setWriteError(0); } + + virtual size_t write(uint8_t) = 0; + virtual size_t write(const char *str); + virtual size_t write(const uint8_t *buffer, size_t size); - ssize_t print(const __FlashStringHelper *); - ssize_t print(const String &); - ssize_t print(const char[]); - ssize_t print(char); - ssize_t print(unsigned char, int = DEC); - ssize_t print(int, int = DEC); - ssize_t print(unsigned int, int = DEC); - ssize_t print(long, int = DEC); - ssize_t print(unsigned long, int = DEC); - ssize_t print(double, int = 2); - ssize_t print(const Printable&); + size_t print(const __FlashStringHelper *); + size_t print(const String &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + size_t print(const Printable&); - ssize_t println(const __FlashStringHelper *); - ssize_t println(const String &s); - ssize_t println(const char[]); - ssize_t println(char); - ssize_t println(unsigned char, int = DEC); - ssize_t println(int, int = DEC); - ssize_t println(unsigned int, int = DEC); - ssize_t println(long, int = DEC); - ssize_t println(unsigned long, int = DEC); - ssize_t println(double, int = 2); - ssize_t println(const Printable&); - ssize_t println(void); + size_t println(const __FlashStringHelper *); + size_t println(const String &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(const Printable&); + size_t println(void); }; #endif diff --git a/cores/arduino/Printable.h b/cores/arduino/Printable.h index 9065904..e22e87e 100644 --- a/cores/arduino/Printable.h +++ b/cores/arduino/Printable.h @@ -30,7 +30,7 @@ class Print; class Printable { public: - virtual ssize_t printTo(Print& p) const = 0; + virtual size_t printTo(Print& p) const = 0; }; #endif