diff --git a/.gitignore b/.gitignore index f685d48..05bb0a5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ other/maple-bootloader/cscope.out other/maple-bootloader/build other/maple-bootloader/*~ *.o -tools/src/stm32flash/src/parsers/parsers.a +tools/src/stm32flash_serial/src/parsers/parsers.a diff --git a/.gitmodules b/.gitmodules index f204a0e..8376e59 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,9 +7,12 @@ [submodule "tools/src/texane-stlink"] path = tools/src/texane-stlink url = https://github.com/texane/stlink -[submodule "tools/src/dfu-util"] - path = tools/src/dfu-util - url = https://gitorious.org/dfu-util/dfu-util.git [submodule "STM32duino-bootloader"] path = STM32duino-bootloader url = https://github.com/rogerclarkmelbourne/STM32duino-bootloader.git +[submodule "STM32F1/libraries/TFT_ILI9163C"] + path = STM32F1/libraries/TFT_ILI9163C + url = https://github.com/victorpv/TFT_ILI9163C.git +[submodule "STM32F1/libraries/Ethernet_STM"] + path = STM32F1/libraries/Ethernet_STM + url = https://github.com/Serasidis/Ethernet_STM diff --git a/STM32F1/boards.txt b/STM32F1/boards.txt index 59e476e..77ff7ba 100644 --- a/STM32F1/boards.txt +++ b/STM32F1/boards.txt @@ -6,7 +6,7 @@ menu.bootloader_version=Bootloader version menu.upload_method=Upload method ############################################################## -mapleMini.name=LeafLabs Maple Mini Rev 2 to Flash +mapleMini.name=Maple Mini mapleMini.build.board=MAPLE_MINI mapleMini.build.core=maple @@ -37,7 +37,7 @@ mapleMini.menu.bootloader_version.bootloader20.upload.maximum_size=122880 mapleMini.menu.bootloader_version.bootloader20.upload.altID=2 ############################################################## -maple.name=LeafLabs Maple Rev 3+ to Flash +maple.name=Maple (Rev 3) maple.upload.tool=maple_upload maple.upload.protocol=maple_dfu @@ -60,7 +60,7 @@ maple.build.vect=VECT_TAB_ADDR=0x8005000 ############################################################## -mapleRET6.name=LeafLabs Maple RET6 to Flash +mapleRET6.name=Maple (RET6) mapleRET6.build.board=MAPLE_RET6 mapleRET6.build.core=maple diff --git a/STM32F1/cores/maple/libmaple/timer.c b/STM32F1/cores/maple/libmaple/timer.c index 3eb3bbd..3c01474 100644 --- a/STM32F1/cores/maple/libmaple/timer.c +++ b/STM32F1/cores/maple/libmaple/timer.c @@ -1,3 +1,4 @@ + /****************************************************************************** * The MIT License * @@ -410,3 +411,102 @@ static void enable_bas_gen_irq(timer_dev *dev) { } nvic_irq_enable(irq_num); } + + +/* Note. + * + * 2015/07/06 Roger Clark + * + * The IRQ handlers were initially in timer_f1.c however this seems to cause problems + * in which the compiler / linker doesn't always link all the required handlers. + * The work around was to move the handlers into this file + */ + +/* + * IRQ handlers + * + * Defer to the timer_private dispatch API. + * + * FIXME: The names of these handlers are inaccurate since XL-density + * devices came out. Update these to match the STM32F2 names, maybe + * using some weak symbol magic to preserve backwards compatibility if + * possible. Once that's done, we can just move the IRQ handlers into + * the top-level libmaple/timer.c, and there will be no need for this + * file. + */ + +void __irq_tim1_brk(void) { + dispatch_adv_brk(TIMER1); +#if STM32_HAVE_TIMER(9) + dispatch_tim_9_12(TIMER9); +#endif +} + +void __irq_tim1_up(void) { + dispatch_adv_up(TIMER1); +#if STM32_HAVE_TIMER(10) + dispatch_tim_10_11_13_14(TIMER10); +#endif +} + +void __irq_tim1_trg_com(void) { + dispatch_adv_trg_com(TIMER1); +#if STM32_HAVE_TIMER(11) + dispatch_tim_10_11_13_14(TIMER11); +#endif +} + +void __irq_tim1_cc(void) { + dispatch_adv_cc(TIMER1); +} + +void __irq_tim2(void) { + dispatch_general(TIMER2); +} + +void __irq_tim3(void) { + dispatch_general(TIMER3); +} + +void __irq_tim4(void) { + dispatch_general(TIMER4); +} + +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) +void __irq_tim5(void) { + dispatch_general(TIMER5); +} + +void __irq_tim6(void) { + dispatch_basic(TIMER6); +} + +void __irq_tim7(void) { + dispatch_basic(TIMER7); +} + +void __irq_tim8_brk(void) { + dispatch_adv_brk(TIMER8); +#if STM32_HAVE_TIMER(12) + dispatch_tim_9_12(TIMER12); +#endif +} + +void __irq_tim8_up(void) { + dispatch_adv_up(TIMER8); +#if STM32_HAVE_TIMER(13) + dispatch_tim_10_11_13_14(TIMER13); +#endif +} + +void __irq_tim8_trg_com(void) { + dispatch_adv_trg_com(TIMER8); +#if STM32_HAVE_TIMER(14) + dispatch_tim_10_11_13_14(TIMER14); +#endif +} + +void __irq_tim8_cc(void) { + dispatch_adv_cc(TIMER8); +} +#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ \ No newline at end of file diff --git a/STM32F1/cores/maple/libmaple/timer_f1.c b/STM32F1/cores/maple/libmaple/timer_f1.c index 8b9e976..d67cf3f 100644 --- a/STM32F1/cores/maple/libmaple/timer_f1.c +++ b/STM32F1/cores/maple/libmaple/timer_f1.c @@ -30,95 +30,12 @@ * @brief STM32F1 timer. */ -#include -#include -#include "timer_private.h" - /* - * IRQ handlers - * - * Defer to the timer_private dispatch API. - * - * FIXME: The names of these handlers are inaccurate since XL-density - * devices came out. Update these to match the STM32F2 names, maybe - * using some weak symbol magic to preserve backwards compatibility if - * possible. Once that's done, we can just move the IRQ handlers into - * the top-level libmaple/timer.c, and there will be no need for this - * file. + * 2015/07/06 + * Note. The IRQ handlers which were initially in this file have been moved to timer.c + * to resolve a linker issue in where some IRQ handlers were not being linked even though + * they were being used. + * This file has been retains for historical reasons, but can be moved at some time in the future + * when full testing of the code in the new location has been completed. */ -void __irq_tim1_brk(void) { - dispatch_adv_brk(TIMER1); -#if STM32_HAVE_TIMER(9) - dispatch_tim_9_12(TIMER9); -#endif -} - -void __irq_tim1_up(void) { - dispatch_adv_up(TIMER1); -#if STM32_HAVE_TIMER(10) - dispatch_tim_10_11_13_14(TIMER10); -#endif -} - -void __irq_tim1_trg_com(void) { - dispatch_adv_trg_com(TIMER1); -#if STM32_HAVE_TIMER(11) - dispatch_tim_10_11_13_14(TIMER11); -#endif -} - -void __irq_tim1_cc(void) { - dispatch_adv_cc(TIMER1); -} - -void __irq_tim2(void) { - dispatch_general(TIMER2); -} - -void __irq_tim3(void) { - dispatch_general(TIMER3); -} - -void __irq_tim4(void) { - dispatch_general(TIMER4); -} - -#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) -void __irq_tim5(void) { - dispatch_general(TIMER5); -} - -void __irq_tim6(void) { - dispatch_basic(TIMER6); -} - -void __irq_tim7(void) { - dispatch_basic(TIMER7); -} - -void __irq_tim8_brk(void) { - dispatch_adv_brk(TIMER8); -#if STM32_HAVE_TIMER(12) - dispatch_tim_9_12(TIMER12); -#endif -} - -void __irq_tim8_up(void) { - dispatch_adv_up(TIMER8); -#if STM32_HAVE_TIMER(13) - dispatch_tim_10_11_13_14(TIMER13); -#endif -} - -void __irq_tim8_trg_com(void) { - dispatch_adv_trg_com(TIMER8); -#if STM32_HAVE_TIMER(14) - dispatch_tim_10_11_13_14(TIMER14); -#endif -} - -void __irq_tim8_cc(void) { - dispatch_adv_cc(TIMER8); -} -#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */ diff --git a/STM32F1/cores/maple/wirish.h b/STM32F1/cores/maple/wirish.h index c074528..a8264f2 100644 --- a/STM32F1/cores/maple/wirish.h +++ b/STM32F1/cores/maple/wirish.h @@ -74,11 +74,12 @@ #include -#warning these are just here to get SPI to compile they need to be changed and moved! -#define SS (1) -#define MOSI 2 -#define MISO 3 -#define SCK 4 + +#define SS BOARD_SPI1_NSS_PIN +#define MOSI BOARD_SPI1_MOSI_PIN +#define MISO BOARD_SPI1_MISO_PIN +#define SCK BOARD_SPI1_SCK_PIN + typedef unsigned int word; // typedef uint16 word;// definition from Arduino website, now appears to be incorrect for 32 bit devices diff --git a/STM32F1/libraries/Ethernet_STM b/STM32F1/libraries/Ethernet_STM new file mode 160000 index 0000000..5dd518a --- /dev/null +++ b/STM32F1/libraries/Ethernet_STM @@ -0,0 +1 @@ +Subproject commit 5dd518a193f5879744b1b3f5b112ee03c6ee14b2 diff --git a/STM32F1/libraries/SPI/src/SPI.cpp b/STM32F1/libraries/SPI/src/SPI.cpp index 3d4d0c7..33cf62f 100644 --- a/STM32F1/libraries/SPI/src/SPI.cpp +++ b/STM32F1/libraries/SPI/src/SPI.cpp @@ -91,26 +91,50 @@ static const spi_pins board_spi_pins[] __FLASH__ = { */ SPIClass::SPIClass(uint32 spi_num) { + + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + + switch (spi_num) { #if BOARD_NR_SPI >= 1 case 1: - this->spi_d = SPI1; + _currentSetting->spi_d = SPI1; break; #endif #if BOARD_NR_SPI >= 2 case 2: - this->spi_d = SPI2; + _currentSetting->spi_d = SPI2; break; #endif #if BOARD_NR_SPI >= 3 case 3: - this->spi_d = SPI3; + _currentSetting->spi_d = SPI3; break; #endif default: ASSERT(0); } + // Init things specific to each SPI device + // clock divider setup is a bit of hack, and needs to be improved at a later date. + _settings[0].spi_d = SPI1; + _settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock); + _settings[0].spiDmaDev = DMA1; + _settings[0].spiTxDmaChannel = DMA_CH3; + _settings[0].spiRxDmaChannel = DMA_CH2; + _settings[1].spi_d = SPI2; + _settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock); + _settings[1].spiDmaDev = DMA1; + _settings[1].spiTxDmaChannel = DMA_CH5; + _settings[1].spiRxDmaChannel = DMA_CH4; +#if BOARD_NR_SPI >= 3 + _settings[2].spi_d = SPI3; + _settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock); + _settings[2].spiDmaDev = DMA2; + _settings[2].spiTxDmaChannel = DMA_CH2; + _settings[2].spiRxDmaChannel = DMA_CH1; +#endif + //pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT); } @@ -120,45 +144,45 @@ SPIClass::SPIClass(uint32 spi_num) { void SPIClass::begin(void) { - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS); - spi_init(spi_d); - configure_gpios(spi_d, 1); + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS); + spi_init(_currentSetting->spi_d); + configure_gpios(_currentSetting->spi_d, 1); #ifdef SPI_DEBUG - Serial.print("spi_master_enable("); Serial.print(clockDivider); Serial.print(","); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif - spi_master_enable(spi_d, (spi_baud_rate)clockDivider, (spi_mode)dataMode, flags); + spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::beginSlave(void) { - if (dataMode >= 4) { + if (_currentSetting->dataMode >= 4) { ASSERT(0); return; } - uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE); - spi_init(spi_d); - configure_gpios(spi_d, 0); + uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE); + spi_init(_currentSetting->spi_d); + configure_gpios(_currentSetting->spi_d, 0); #ifdef SPI_DEBUG - Serial.print("spi_slave_enable("); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); + Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")"); #endif - spi_slave_enable(spi_d, (spi_mode)dataMode, flags); + spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags); } void SPIClass::end(void) { - if (!spi_is_enabled(this->spi_d)) { + if (!spi_is_enabled(_currentSetting->spi_d)) { return; } // Follows RM0008's sequence for disabling a SPI in master/slave // full duplex mode. - while (spi_is_rx_nonempty(this->spi_d)) { + while (spi_is_rx_nonempty(_currentSetting->spi_d)) { // FIXME [0.1.0] remove this once you have an interrupt based driver - volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d); + volatile uint16 rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d); } - while (!spi_is_tx_empty(this->spi_d)) + while (!spi_is_tx_empty(_currentSetting->spi_d)) ; - while (spi_is_busy(this->spi_d)) + while (spi_is_busy(_currentSetting->spi_d)) ; - spi_peripheral_disable(this->spi_d); + spi_peripheral_disable(_currentSetting->spi_d); } /* Roger Clark added 3 functions */ @@ -167,7 +191,7 @@ void SPIClass::setClockDivider(uint32_t clockDivider) #ifdef SPI_DEBUG Serial.print("Clock divider set to "); Serial.println(clockDivider); #endif - this->clockDivider = clockDivider; + _currentSetting->clockDivider = clockDivider; this->begin(); } @@ -176,7 +200,7 @@ void SPIClass::setBitOrder(BitOrder bitOrder) #ifdef SPI_DEBUG Serial.print("Bit order set to "); Serial.println(bitOrder); #endif - this->bitOrder = bitOrder; + _currentSetting->bitOrder = bitOrder; this->begin(); } @@ -186,11 +210,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder) */ void SPIClass::setDataSize(uint32 datasize) { - uint32 cr1 = this->spi_d->regs->CR1; + uint32 cr1 = _currentSetting->spi_d->regs->CR1; datasize &= SPI_CR1_DFF; cr1 &= ~(SPI_CR1_DFF); cr1 |= datasize; - this->spi_d->regs->CR1 = cr1; + _currentSetting->spi_d->regs->CR1 = cr1; } void SPIClass::setDataMode(uint8_t dataMode) @@ -225,7 +249,7 @@ If someone finds this is not the case or sees a logic error with this let me kno #ifdef SPI_DEBUG Serial.print("Data mode set to "); Serial.println(dataMode); #endif - this->dataMode = dataMode; + _currentSetting->dataMode = dataMode; this->begin(); } @@ -240,29 +264,9 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings) //digitalWrite(_SSPin,LOW); setBitOrder(settings.bitOrder); setDataMode(settings.dataMode); - setClockDivider(determine_baud_rate(spi_d, settings.clock)); + setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock)); begin(); -#if 0 -// code from SAM core - uint8_t mode = interruptMode; - if (mode > 0) { - if (mode < 16) { - if (mode & 1) PIOA->PIO_IDR = interruptMask[0]; - if (mode & 2) PIOB->PIO_IDR = interruptMask[1]; - if (mode & 4) PIOC->PIO_IDR = interruptMask[2]; - if (mode & 8) PIOD->PIO_IDR = interruptMask[3]; - } else { - interruptSave = interruptsStatus(); - noInterrupts(); - } - } - uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin); - bitOrder[ch] = settings.border; - SPI_ConfigureNPCS(spi, ch, settings.config); - //setBitOrder(pin, settings.border); - //setDataMode(pin, settings.datamode); - //setClockDivider(pin, settings.clockdiv); -#endif + } void SPIClass::endTransaction(void) @@ -301,9 +305,9 @@ uint8 SPIClass::read(void) { void SPIClass::read(uint8 *buf, uint32 len) { uint32 rxed = 0; while (rxed < len) { - while (!spi_is_rx_nonempty(this->spi_d)) + while (!spi_is_rx_nonempty(_currentSetting->spi_d)) ; - buf[rxed++] = (uint8)spi_rx_reg(this->spi_d); + buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d); } } @@ -316,9 +320,9 @@ void SPIClass::write(uint16 data) { * This almost doubles the speed of this function. */ - spi_tx_reg(this->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." } //void SPIClass::write(uint8 byte) { @@ -330,27 +334,27 @@ void SPIClass::write(uint16 data) { * This almost doubles the speed of this function. */ -// spi_tx_reg(this->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." -// while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." -// while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." +// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." +// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." +// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." //} void SPIClass::write(const uint8 *data, uint32 length) { uint32 txed = 0; while (txed < length) { - txed += spi_tx(this->spi_d, data + txed, length - txed); + txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed); } - while (spi_is_tx_empty(this->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete." } uint8 SPIClass::transfer(uint8 byte) const { uint8 b; - spi_tx_reg(this->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)." + while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..." + b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." return b; } /* Roger Clark and Victor Perez, 2015 @@ -362,52 +366,56 @@ uint8 SPIClass::transfer(uint8 byte) const { uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) { if (length == 0) return 0; uint8 b; - if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it. - dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it. +// dma1_ch3_Active=true; + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // RX - spi_rx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS, + spi_rx_dma_enable(_currentSetting->spi_d); + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA - dma_set_num_transfers(DMA1, DMA_CH2, length); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length); // TX - spi_tx_dma_enable(SPI1); + spi_tx_dma_enable(_currentSetting->spi_d); if (!transmitBuf) { static uint8_t ff = 0XFF; transmitBuf = &ff; - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly } else { - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA } - dma_set_num_transfers(DMA1, DMA_CH3, length); + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); - dma_enable(DMA1, DMA_CH2);// enable receive - dma_enable(DMA1, DMA_CH3);// enable transmit + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit // while (dma1_ch3_Active); // if (receiveBuf) { uint32_t m = millis(); - while (dma1_ch3_Active) { + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set. if ((millis() - m) > 100) { - dma1_ch3_Active = 0; +// dma1_ch3_Active = 0; b = 2; break; } } + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); // } - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - dma_disable(DMA1, DMA_CH2); - spi_rx_dma_disable(SPI1); - spi_tx_dma_disable(SPI1); + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel); + spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels + spi_tx_dma_disable(_currentSetting->spi_d); + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } return b; } @@ -420,24 +428,28 @@ uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) { if (length == 0) return 0; uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b; - dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); +// dma1_ch3_Active=true; + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS, + spi_tx_dma_enable(_currentSetting->spi_d); + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS, transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); +// while (dma1_ch3_Active); + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + spi_tx_dma_disable(_currentSetting->spi_d); + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } return b; } @@ -446,23 +458,27 @@ uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) { uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT); uint8 b; dma1_ch3_Active=true; - dma_init(DMA1); - dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); + dma_init(_currentSetting->spiDmaDev); +// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event); // TX - spi_tx_dma_enable(SPI1); - dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS, + spi_tx_dma_enable(_currentSetting->spi_d); + dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS, transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA - dma_set_num_transfers(DMA1, DMA_CH3, length); - dma_enable(DMA1, DMA_CH3);// enable transmit + dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length); + dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit - while (dma1_ch3_Active); - while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..." - b = spi_rx_reg(this->spi_d); // "... and read the last received data." - while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..." - while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." - dma_disable(DMA1, DMA_CH3); - spi_tx_dma_disable(SPI1); +// while (dma1_ch3_Active); + while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set. + dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + + while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..." + while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI." + dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel); + spi_tx_dma_disable(_currentSetting->spi_d); + if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..." + b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data." + } return b; } @@ -480,19 +496,19 @@ void SPIClass::detachInterrupt(void) { */ uint8 SPIClass::misoPin(void) { - return dev_to_spi_pins(this->spi_d)->miso; + return dev_to_spi_pins(_currentSetting->spi_d)->miso; } uint8 SPIClass::mosiPin(void) { - return dev_to_spi_pins(this->spi_d)->mosi; + return dev_to_spi_pins(_currentSetting->spi_d)->mosi; } uint8 SPIClass::sckPin(void) { - return dev_to_spi_pins(this->spi_d)->sck; + return dev_to_spi_pins(_currentSetting->spi_d)->sck; } uint8 SPIClass::nssPin(void) { - return dev_to_spi_pins(this->spi_d)->nss; + return dev_to_spi_pins(_currentSetting->spi_d)->nss; } /* diff --git a/STM32F1/libraries/SPI/src/SPI.h b/STM32F1/libraries/SPI/src/SPI.h index 490d58b..9bfe4f4 100644 --- a/STM32F1/libraries/SPI/src/SPI.h +++ b/STM32F1/libraries/SPI/src/SPI.h @@ -118,6 +118,13 @@ private: uint32_t clock; BitOrder bitOrder; uint8_t dataMode; + + spi_dev *spi_d; + uint8_t _SSPin; + uint32_t clockDivider; + dma_channel spiRxDmaChannel, spiTxDmaChannel; + dma_dev* spiDmaDev; + friend class SPIClass; }; @@ -304,7 +311,24 @@ public: * @brief Get a pointer to the underlying libmaple spi_dev for * this HardwareSPI instance. */ - spi_dev* c_dev(void) { return this->spi_d; } + spi_dev* c_dev(void) { return _currentSetting->spi_d; } + + + spi_dev *dev(){ return _currentSetting->spi_d;} + + /** + * @brief Sets the number of the SPI peripheral to be used by + * this HardwareSPI instance. + * + * @param spi_num Number of the SPI port. 1-2 in low density devices + * or 1-3 in high density devices. + */ + + void setModule(int spi_num) + { + _currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed + } + /* -- The following methods are deprecated --------------------------- */ @@ -338,12 +362,8 @@ public: */ uint8 recv(void); - spi_dev *dev(){ return spi_d;} - - - private: - +/* static inline void DMA1_CH3_Event() { dma1_ch3_Active = 0; // dma_disable(DMA1, DMA_CH3); @@ -351,11 +371,17 @@ private: // To Do. Need to wait for } +*/ + SPISettings _settings[BOARD_NR_SPI]; + SPISettings *_currentSetting; + + /* spi_dev *spi_d; uint8_t _SSPin; uint32_t clockDivider; uint8_t dataMode; BitOrder bitOrder; + */ }; diff --git a/STM32F1/libraries/Serasidis_VS1003B_STM/src/VS1003_STM.cpp b/STM32F1/libraries/Serasidis_VS1003B_STM/src/VS1003_STM.cpp index 2f80b19..07540d5 100644 --- a/STM32F1/libraries/Serasidis_VS1003B_STM/src/VS1003_STM.cpp +++ b/STM32F1/libraries/Serasidis_VS1003B_STM/src/VS1003_STM.cpp @@ -10,11 +10,16 @@ email: avrsite@yahoo.gr 29 May 2015 - Added a fix for booting the VS1053B boards into mp3 decoding instead of booting into MID (modeSwitch function). + 01 July 2015 - Added a Flac decoder patch. */ //#include #include +#if defined(USEFLAC) +#include "flac.h" +#endif + #define vs1003_chunk_size 32 /****************************************************************************/ @@ -237,6 +242,9 @@ void VS1003::begin(void) write_register(SCI_MODE, (1< #include /** diff --git a/STM32F1/libraries/Serasidis_VS1003B_STM/src/flac.h b/STM32F1/libraries/Serasidis_VS1003B_STM/src/flac.h new file mode 100644 index 0000000..106483f --- /dev/null +++ b/STM32F1/libraries/Serasidis_VS1003B_STM/src/flac.h @@ -0,0 +1,1078 @@ +#define FLAC_PATCHLEN 8161 + //Taken from FLAC decoder patch 2015-05-25 v2.30 + const unsigned short flac_patch[FLAC_PATCHLEN] = + { + 0x0007,0x0001, /*copy 1*/ + 0x8050, + 0x0006,0x0002, /*copy 2*/ + 0x2a00,0xc000, + 0x0006, 0x801e, 0x0000, /*Rle(30)*/ + 0x0006,0x0540, /*copy 1344*/ + 0xf400,0x4095,0x0000,0x02c2,0x6124,0x0024,0x0000,0x0024, + 0x2800,0x1ac5,0x4192,0x4542,0x0000,0x0041,0x2000,0x0015, + 0x0030,0x0317,0x2000,0x0000,0x3f00,0x4024,0x2000,0x0000, + 0x0000,0x0000,0x3e12,0x3800,0x3e00,0xb804,0x0030,0x0015, + 0x0007,0x8257,0x3700,0x984c,0xf224,0x1444,0xf224,0x0024, + 0x0008,0x0002,0x2910,0x0181,0x0000,0x1bc8,0xb428,0x1402, + 0x0000,0x8004,0x2910,0x0195,0x0000,0x1bc8,0xb428,0x0024, + 0x0006,0x0095,0x2800,0x2945,0x3e13,0x780e,0x3e11,0x7803, + 0x3e13,0xf806,0x3e11,0xf801,0x3510,0xb808,0x003f,0xe004, + 0xfec4,0x3800,0x48be,0x17c3,0xfe46,0x41c2,0x48be,0x4497, + 0x4090,0x1c46,0xf06c,0x0024,0x2400,0x2580,0x6090,0x41c3, + 0x6628,0x1c47,0x0000,0x0024,0x2800,0x2449,0xf07e,0x0024, + 0xf400,0x4182,0x673a,0x1c46,0x0000,0x0024,0x2800,0x2589, + 0xf06c,0x0024,0xf400,0x41c3,0x0000,0x0024,0x4224,0x3442, + 0x2903,0xbe80,0x4336,0x37c3,0x0000,0x1805,0x2903,0xbe80, + 0x4508,0x40c2,0x450a,0x9808,0x0000,0x0207,0xa478,0x1bc0, + 0xc45a,0x1807,0x0030,0x03d5,0x3d01,0x5bc1,0x36f3,0xd806, + 0x3601,0x5803,0x36f3,0x0024,0x36f3,0x580e,0x0007,0x8257, + 0x0000,0x6004,0x3730,0x8024,0xb244,0x1c04,0xd428,0x3c02, + 0x0006,0xc717,0x2800,0x2d05,0x4284,0x0024,0x3613,0x3c02, + 0x0006,0xc357,0x2901,0x6780,0x3e11,0x5c05,0x4284,0x1bc5, + 0x0000,0x0024,0x2800,0x2fc5,0x0000,0x0024,0x3613,0x0024, + 0x3e10,0x3813,0x3e14,0x8024,0x3e04,0x8024,0x2900,0x4c00, + 0x0006,0x02d3,0x36e3,0x0024,0x3009,0x1bd3,0x0007,0x8257, + 0x3700,0x8024,0xf224,0x0024,0x0000,0x0024,0x2800,0x31d1, + 0x3600,0x9844,0x2900,0x3780,0x0000,0x3248,0x2911,0xf140, + 0x0000,0x0024,0x0030,0x0057,0x3700,0x0024,0xf200,0x4595, + 0x0fff,0xfe02,0xa024,0x164c,0x8000,0x17cc,0x3f00,0x0024, + 0x3500,0x0024,0x0021,0x6d82,0xd024,0x44c0,0x0006,0xa402, + 0x2800,0x3695,0xd024,0x0024,0x0000,0x0000,0x2800,0x3695, + 0x000b,0x6d57,0x3009,0x3c00,0x36f0,0x8024,0x36f2,0x1800, + 0x2000,0x0000,0x0000,0x0024,0x3e14,0x7810,0x3e13,0xb80d, + 0x3e13,0xf80a,0x3e10,0xb803,0x3e11,0x3805,0x3e11,0xb807, + 0x3e14,0xf801,0x0001,0x000a,0x0006,0xc4d5,0xbf8e,0x9442, + 0x3e01,0x9403,0x0006,0xa017,0x0023,0xffd1,0x0000,0x0053, + 0x3281,0xf806,0x4091,0x2d64,0x2400,0x3d00,0x4efa,0x9c10, + 0xf1eb,0x6061,0xfe55,0x2f66,0x5653,0x2d64,0x48b2,0xa201, + 0x4efa,0xa201,0x36f3,0x3c10,0x36f4,0xd801,0x36f1,0x9807, + 0x36f1,0x1805,0x36f0,0x9803,0x36f3,0xd80a,0x36f3,0x980d, + 0x2000,0x0000,0x36f4,0x5810,0x3e12,0xb817,0x3e14,0xf812, + 0x3e01,0xb811,0x0007,0x9717,0x0020,0xffd2,0x0030,0x11d1, + 0x3111,0x8024,0x3704,0xc024,0x3b81,0x8024,0x3101,0x8024, + 0x3b81,0x8024,0x3f04,0xc024,0x2808,0x4800,0x36f1,0x9811, + 0x36f3,0x0024,0x3009,0x3848,0x3e14,0x3811,0x3e00,0x0024, + 0x0000,0x4000,0x0001,0x0010,0x2915,0x94c0,0x0001,0xcc11, + 0x36f0,0x0024,0x2927,0x9e40,0x3604,0x1811,0x3613,0x0024, + 0x3e14,0x3811,0x3e00,0x0024,0x0000,0x4000,0x0001,0x0010, + 0x2915,0x94c0,0x0001,0xcc11,0x36f0,0x0024,0x36f4,0x1811, + 0x3009,0x1808,0x2000,0x0000,0x0000,0x190d,0x3600,0x3840, + 0x3e13,0x780e,0x3e13,0xf808,0x3e00,0x0024,0x0000,0x430e, + 0x0027,0x9e0f,0x2922,0xb680,0x0000,0x190d,0x36f3,0x0024, + 0x36f3,0xd808,0x36f3,0x580e,0x2000,0x0000,0x3009,0x1800, + 0x3613,0x0024,0x3e22,0xb815,0x3e05,0xb814,0x3615,0x0024, + 0x0000,0x800a,0x3e13,0x7801,0x3e10,0xb803,0x3e11,0x3805, + 0x3e11,0xb807,0x3e14,0x3811,0x3e14,0xb813,0x3e03,0xf80e, + 0xb488,0x44d5,0x3543,0x134c,0x34e5,0xc024,0x3524,0x8024, + 0x35a4,0xc024,0x3710,0x8a0c,0x3540,0x4a0c,0x3d44,0x8024, + 0x3a10,0x8024,0x3590,0x0024,0x4010,0x15c1,0x6010,0x3400, + 0x3710,0x8024,0x2800,0x57c4,0x3af0,0x8024,0x3df0,0x0024, + 0x3591,0x4024,0x3530,0x4024,0x4192,0x4050,0x6100,0x1482, + 0x4020,0x1753,0xbf8e,0x1582,0x4294,0x4011,0xbd86,0x408e, + 0x2400,0x55ce,0xfe6d,0x2819,0x520e,0x0a00,0x5207,0x2819, + 0x4fbe,0x0024,0xad56,0x904c,0xaf5e,0x1010,0xf7d4,0x0024, + 0xf7fc,0x2042,0x6498,0x2046,0x3cf4,0x0024,0x3400,0x170c, + 0x4090,0x1492,0x35a4,0xc024,0x2800,0x5055,0x3c00,0x0024, + 0x4480,0x914c,0x36f3,0xd80e,0x36f4,0x9813,0x36f4,0x1811, + 0x36f1,0x9807,0x36f1,0x1805,0x36f0,0x9803,0x36f3,0x5801, + 0x3405,0x9014,0x36e3,0x0024,0x2000,0x0000,0x36f2,0x9815, + 0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814,0x3625,0x0024, + 0x0000,0x800a,0x3e10,0x3801,0x3e10,0xb803,0x3e11,0x3805, + 0x3e11,0xb807,0x3e14,0x3811,0x0006,0xa090,0x2912,0x0d00, + 0x3e14,0xc024,0x4088,0x8000,0x4080,0x0024,0x0007,0x90d1, + 0x2800,0x61c5,0x0000,0x0024,0x0007,0x9051,0x3100,0x4024, + 0x4100,0x0024,0x3900,0x0024,0x0007,0x90d1,0x0004,0x0000, + 0x31f0,0x4024,0x6014,0x0400,0x0000,0x0024,0x2800,0x6611, + 0x4080,0x0024,0x0000,0x0000,0x2800,0x6585,0x0000,0x0024, + 0x0007,0x9053,0x3300,0x0024,0x4080,0x0024,0x0000,0x0000, + 0x2800,0x6618,0x0000,0x0024,0x0007,0x9051,0x3900,0x0024, + 0x3200,0x504c,0x6410,0x0024,0x3cf0,0x0000,0x4080,0x0024, + 0x0006,0xc691,0x2800,0x7ec5,0x3009,0x0400,0x0007,0x9051, + 0x0000,0x1001,0x3100,0x0024,0x6012,0x0024,0x0006,0xc6d0, + 0x2800,0x7309,0x003f,0xe000,0x0006,0xc693,0x3900,0x0c00, + 0x3009,0x0001,0x6014,0x0024,0x0007,0x1ad0,0x2800,0x7315, + 0x3009,0x0000,0x4080,0x0024,0x0000,0x0301,0x2800,0x6d05, + 0x4090,0x0024,0x0000,0x0024,0x2800,0x6e15,0x0000,0x0024, + 0x3009,0x0000,0xc012,0x0024,0x2800,0x7300,0x3009,0x2001, + 0x3009,0x0000,0x6012,0x0024,0x0000,0x0341,0x2800,0x7015, + 0x0000,0x0024,0x6190,0x0024,0x2800,0x7300,0x3009,0x2000, + 0x6012,0x0024,0x0000,0x0381,0x2800,0x71d5,0x0000,0x0024, + 0x6190,0x0024,0x2800,0x7300,0x3009,0x2000,0x6012,0x0024, + 0x0000,0x00c0,0x2800,0x7315,0x0000,0x0024,0x3009,0x2000, + 0x0006,0xa090,0x3009,0x0000,0x4080,0x0024,0x0000,0x0081, + 0x2800,0x77d5,0x0007,0x8c13,0x3300,0x104c,0xb010,0x0024, + 0x0002,0x8001,0x2800,0x7a45,0x34f0,0x0024,0x2800,0x77c0, + 0x0000,0x0024,0x0006,0xc351,0x3009,0x0000,0x6090,0x0024, + 0x3009,0x2000,0x2900,0x0b80,0x3009,0x0405,0x0006,0xc690, + 0x0006,0xc6d1,0x3009,0x0000,0x3009,0x0401,0x6014,0x0024, + 0x0006,0xa093,0x2800,0x7651,0xb880,0x0024,0x2800,0x8780, + 0x3009,0x2c00,0x4040,0x0024,0x6012,0x0024,0x0006,0xc6d0, + 0x2800,0x8798,0x0000,0x0024,0x0006,0xc693,0x3009,0x0c00, + 0x3009,0x0001,0x6014,0x0024,0x0006,0xc350,0x2800,0x8781, + 0x0000,0x0024,0x6090,0x0024,0x3009,0x2c00,0x3009,0x0005, + 0x2900,0x0b80,0x0000,0x8788,0x3009,0x0400,0x4080,0x0024, + 0x0003,0x8000,0x2800,0x8785,0x0000,0x0024,0x6400,0x0024, + 0x0000,0x0081,0x2800,0x8789,0x0000,0x0024,0x0007,0x8c13, + 0x3300,0x0024,0xb010,0x0024,0x0006,0xc650,0x2800,0x8795, + 0x0000,0x0024,0x0001,0x0002,0x3413,0x0000,0x3009,0x0401, + 0x4010,0x8406,0x0000,0x0281,0xa010,0x13c1,0x4122,0x0024, + 0x0000,0x03c2,0x6122,0x8002,0x462c,0x0024,0x469c,0x0024, + 0xfee2,0x0024,0x48be,0x0024,0x6066,0x8400,0x0006,0xc350, + 0x2800,0x8781,0x0000,0x0024,0x4090,0x0024,0x3009,0x2400, + 0x2900,0x0b80,0x3009,0x0005,0x0007,0x1b50,0x2912,0x0d00, + 0x3613,0x0024,0x3a00,0x0380,0x4080,0x0024,0x0000,0x00c1, + 0x2800,0x9045,0x3009,0x0000,0xb010,0x008c,0x4192,0x0024, + 0x6012,0x0024,0x0006,0xf051,0x2800,0x8e58,0x3009,0x0400, + 0x0007,0x1fd1,0x30e3,0x0400,0x4080,0x0024,0x0000,0x0301, + 0x2800,0x9045,0x3009,0x0000,0xb010,0x0024,0x0000,0x0101, + 0x6012,0x0024,0x0006,0xf051,0x2800,0x9055,0x0000,0x0024, + 0x3023,0x0400,0xf200,0x184c,0xb880,0xa400,0x3009,0x2000, + 0x3009,0x0441,0x3e10,0x4402,0x2909,0xa9c0,0x3e10,0x8024, + 0x36e3,0x0024,0x36f4,0xc024,0x36f4,0x1811,0x36f1,0x9807, + 0x36f1,0x1805,0x36f0,0x9803,0x36f0,0x1801,0x3405,0x9014, + 0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3615,0x0024,0x0000,0x800a,0x3e10,0xb803,0x0012,0x5103, + 0x3e11,0x3805,0x3e11,0xb807,0x3e14,0x380d,0x0030,0x0250, + 0x3e13,0xf80e,0xbe8b,0x83e0,0x290c,0x4840,0x3613,0x0024, + 0x290c,0x4840,0x4086,0x984c,0x0000,0x00ce,0x2400,0x9a4e, + 0x3009,0x1bc0,0x0000,0x01c3,0xae3a,0x184c,0x0000,0x0043, + 0x3009,0x3842,0x290c,0x4840,0x3009,0x3840,0x4084,0x9bc0, + 0xfe26,0x9bc2,0xceba,0x0024,0x4e8e,0x0024,0x4e9a,0x0024, + 0x4f8e,0x0024,0x0000,0x0102,0x2800,0x9f85,0x0030,0x0010, + 0x0000,0x0206,0x3613,0x0024,0x290c,0x4840,0x3009,0x3840, + 0x3000,0xdbc0,0xb366,0x0024,0x0000,0x0024,0x2800,0x9f95, + 0x4e8e,0x0024,0x4e9a,0x0024,0x4f8e,0x0024,0x0030,0x0010, + 0x2800,0x9c55,0x0000,0x0206,0x36f3,0xd80e,0x36f4,0x180d, + 0x36f1,0x9807,0x36f1,0x1805,0x36f0,0x9803,0x3405,0x9014, + 0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3635,0x0024,0x0000,0x800a,0x3e10,0x7802,0x3e14,0x0024, + 0x2903,0x5400,0x0000,0x0201,0x0000,0x0601,0x3413,0x184c, + 0x2903,0x5b40,0x3cf0,0x0024,0x3413,0x184c,0x3400,0x3040, + 0x3009,0x33c1,0x0000,0x1fc1,0xb010,0x0024,0x6014,0x9040, + 0x0006,0x8010,0x2800,0xa8d5,0x0000,0x0024,0x34e3,0x1bcc, + 0x6890,0x0024,0x2800,0xaa80,0xb880,0x2000,0x3e10,0x1381, + 0x2903,0x9d80,0x3e00,0x4024,0x003f,0xfe41,0x36e3,0x104c, + 0x34f0,0x0024,0xa010,0x0024,0x36f4,0x0024,0x36f0,0x5802, + 0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000, + 0x36f2,0x9817,0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815, + 0x3e05,0xb814,0x3615,0x0024,0x0000,0x800a,0x3e10,0xb804, + 0x3e01,0x534c,0xbe8a,0x10c0,0x4080,0x0024,0x0000,0x0024, + 0x2800,0xb3c5,0x0000,0x0024,0x2903,0x5b40,0x4082,0x184c, + 0x4c8a,0x134c,0x0000,0x0001,0x6890,0x10c2,0x4294,0x0024, + 0xac22,0x0024,0xbec2,0x0024,0x0000,0x0024,0x2800,0xb3c5, + 0x0000,0x0024,0x6890,0x134c,0xb882,0x10c2,0xac22,0x0024, + 0x4c92,0x0024,0xdc92,0x0024,0xceca,0x0024,0x4e82,0x1bc5, + 0x36f0,0x9804,0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815, + 0x2000,0x0000,0x36f2,0x9817,0x3613,0x0024,0x3e12,0xb817, + 0x3e12,0x3815,0x3e05,0xb814,0x3615,0x0024,0x0000,0x800a, + 0x3e10,0x3801,0x3e10,0xb804,0x3e11,0xb807,0x3e14,0x3811, + 0x3e04,0x934c,0x3430,0x0024,0x4080,0x0024,0x0000,0x0206, + 0x2800,0xbc05,0x0006,0x8151,0x3101,0x130c,0xff0c,0x1102, + 0x6408,0x0024,0x4204,0x0024,0xb882,0x4092,0x1005,0xfe02, + 0x48be,0x0024,0x4264,0x0024,0x2903,0xaa00,0xf400,0x4090, + 0x36f4,0x8024,0x36f4,0x1811,0x36f1,0x9807,0x36f0,0x9804, + 0x36f0,0x1801,0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815, + 0x2000,0x0000,0x36f2,0x9817,0x2a08,0x1b8e,0x2803,0x7140, + 0x0000,0xbe97,0x0006,0xd397,0x2000,0x0000,0x3f00,0x0024, + 0x0007,0x0001, /*copy 1*/ + 0x8300, + 0x0006,0x1844, /*copy 6212*/ + 0x0030,0x0055,0xb080,0x1402,0x0fdf,0xffc1,0x0007,0x9257, + 0xb212,0x3c00,0x3d00,0x4024,0x0030,0x0297,0x3f00,0x0024, + 0x0007,0x9017,0x3f00,0x0024,0x0007,0x81d7,0x3f10,0x0024, + 0xc090,0x3c00,0x0006,0x0297,0xb080,0x3c00,0x0000,0x0401, + 0x000a,0x1055,0x0006,0x0017,0x3f10,0x3401,0x000a,0x2795, + 0x3f00,0x3401,0x0001,0x6757,0xf400,0x55c0,0x0000,0x0817, + 0xb080,0x57c0,0x0006,0x01d7,0x3f00,0x0024,0x0000,0x190d, + 0x000f,0xf94f,0x0000,0xca0e,0x280f,0xe100,0x0006,0x2016, + 0x0000,0x0080,0x0005,0x4f92,0x2909,0xf840,0x3613,0x2800, + 0x0006,0x0197,0x0006,0xa115,0xb080,0x0024,0x3f00,0x3400, + 0x0007,0x8a57,0x3700,0x0024,0x4080,0x0024,0x0000,0x0040, + 0x2800,0xcbd5,0x0006,0xa2d7,0x3009,0x3c00,0x0006,0xa157, + 0x3009,0x1c00,0x0006,0x01d7,0x0000,0x190d,0x000a,0x708f, + 0x0000,0xd4ce,0x290b,0x1a80,0x3f00,0x184c,0x0030,0x0017, + 0x4080,0x1c01,0x0000,0x0200,0x2800,0xc815,0xb102,0x0024, + 0x0000,0xca08,0x2800,0xc815,0x0000,0xd0ce,0x0011,0x210f, + 0x0000,0x190d,0x280f,0xcb00,0x3613,0x0024,0x0006,0xa115, + 0x0006,0x01d7,0x37f0,0x1401,0x6100,0x1c01,0x4012,0x0024, + 0x0000,0x8000,0x6010,0x0024,0x34f3,0x0400,0x2800,0xd398, + 0x0000,0x0024,0x0000,0x8001,0x6010,0x3c01,0x0000,0x000d, + 0x2811,0x8259,0x0000,0x0024,0x2a11,0x2100,0x0030,0x0257, + 0x3700,0x0024,0x4080,0x0024,0x0000,0x0024,0x2800,0xd6d5, + 0x0006,0x0197,0x0006,0xa115,0x3f00,0x3400,0x003f,0xc000, + 0xb600,0x41c1,0x0012,0x5103,0x000c,0xc002,0xdcd6,0x0024, + 0x0019,0xd4c2,0x2800,0x9305,0x0001,0x0e48,0x0013,0xd9c3, + 0x6fd6,0x0024,0x0000,0x190d,0x2800,0xdc95,0x0014,0x1b01, + 0x0020,0x480f,0x0000,0xdb4e,0x0000,0x190d,0x2820,0x41c0, + 0x0001,0x0e48,0x0039,0x324f,0x0001,0x3b4e,0x2820,0x4a18, + 0xb882,0x0024,0x2a20,0x48c0,0x003f,0xfd00,0xb700,0x0024, + 0x003f,0xf901,0x6010,0x0024,0x0014,0x1b01,0x280a,0xc505, + 0x0000,0x190d,0x0015,0x59c0,0x6fc2,0x0024,0x0019,0x9301, + 0x2800,0xe695,0x0018,0x50c0,0x290c,0x4840,0x3613,0x0024, + 0x290c,0x4840,0x4086,0x184c,0x0000,0x18c2,0x6234,0x0024, + 0x0000,0x1d02,0x2800,0xe295,0x6234,0x0024,0x0030,0x0317, + 0x2800,0xe800,0x3f00,0x0024,0x0000,0x1d82,0x2800,0xe515, + 0x6234,0x0024,0x2912,0x0d00,0x4084,0x184c,0xf200,0x0024, + 0x6200,0x0024,0x0006,0x0017,0x2800,0xe200,0xb080,0x3c40, + 0x0000,0x0202,0x2800,0xe815,0xa024,0x0024,0xc020,0x0024, + 0x2800,0xe200,0x0030,0x02d7,0x6fc2,0x0024,0x0000,0x0024, + 0x2800,0xe815,0x0000,0x0024,0x2802,0xffc0,0x000a,0xcac8, + 0x000a,0x8c8f,0x0000,0xe94e,0x000c,0x0981,0x280a,0x71c0, + 0x002c,0x9d40,0x000a,0x708f,0x0000,0xd4ce,0x280a,0xc0d5, + 0x0012,0x5182,0x6fd6,0x0024,0x003f,0xfd81,0x280a,0x8e45, + 0xb710,0x0024,0xb710,0x0024,0x003f,0xfc01,0x6012,0x0024, + 0x0000,0x0101,0x2801,0x0515,0xffd2,0x0024,0x48b2,0x0024, + 0x4190,0x0024,0x0000,0x190d,0x2801,0x0515,0x0030,0x0250, + 0xb880,0x104c,0x3cf0,0x0024,0x0010,0x5500,0xb880,0x23c0, + 0xb882,0x2000,0x0007,0x8590,0x2914,0xbec0,0x0000,0x0440, + 0x0007,0x8b50,0xb880,0x0024,0x2920,0x0100,0x3800,0x0024, + 0x2920,0x0000,0x0006,0x8a91,0x0000,0x0800,0xb880,0xa440, + 0x003f,0xfd81,0xb710,0xa7c0,0x003f,0xfc01,0x6012,0x0024, + 0x0000,0x0101,0x2801,0x0e55,0x0000,0x0024,0xffe2,0x0024, + 0x48b2,0x0024,0x4190,0x0024,0x0000,0x0024,0x2801,0x0e55, + 0x0000,0x0024,0x2912,0x2d80,0x0000,0x0780,0x4080,0x0024, + 0x0006,0x8a90,0x2801,0x0e55,0x0000,0x01c2,0xb886,0x8040, + 0x3613,0x03c1,0xbcd2,0x0024,0x0030,0x0011,0x2800,0xfad5, + 0x003f,0xff42,0xb886,0x8040,0x3009,0x03c1,0x0000,0x0020, + 0xac22,0x0024,0x0000,0x0102,0x6cd2,0x0024,0x3e10,0x0024, + 0x2909,0x8c80,0x3e00,0x4024,0x36f3,0x0024,0x3e11,0x8024, + 0x3e01,0xc024,0x2901,0x3200,0x0000,0x0201,0xf400,0x4512, + 0x2900,0x0c80,0x3213,0x1b8c,0x3100,0x0024,0xb010,0x0024, + 0x0000,0x0024,0x2801,0x0e55,0x0000,0x0024,0x291a,0x8a40, + 0x0000,0x0100,0x2920,0x0200,0x3633,0x0024,0x2920,0x0280, + 0x0000,0x0401,0x408e,0x0024,0x2920,0x0280,0x0000,0x0401, + 0x003f,0xfd81,0xb710,0x4006,0x003f,0xfc01,0x6012,0x0024, + 0x0000,0x0101,0x2801,0x0e55,0x0000,0x0024,0xffe2,0x0024, + 0x48b2,0x0024,0x4190,0x0024,0x0000,0x0024,0x2801,0x0e55, + 0x0000,0x0024,0x2912,0x2d80,0x0000,0x0780,0x4080,0x0024, + 0x0000,0x01c2,0x2800,0xf6c5,0x0006,0x8a90,0x2a01,0x0e40, + 0x2920,0x0100,0x0000,0x0401,0x0000,0x0180,0x2920,0x0200, + 0x3613,0x0024,0x2920,0x0280,0x3613,0x0024,0x0000,0x0401, + 0x2920,0x0280,0x4084,0x984c,0x0019,0x9d01,0x6212,0x0024, + 0x001e,0x5c01,0x2801,0x0995,0x6012,0x0024,0x0000,0x0024, + 0x2801,0x0b85,0x0000,0x0024,0x001b,0x5bc1,0x6212,0x0024, + 0x001b,0xdd81,0x2801,0x0f55,0x6012,0x0024,0x0000,0x0024, + 0x2801,0x0f55,0x0000,0x0024,0x0000,0x004d,0x000a,0xbf4f, + 0x280a,0xb880,0x0001,0x0c8e,0x0020,0xfb4f,0x0000,0x190d, + 0x0001,0x138e,0x2920,0x0480,0x3009,0x2bc1,0x291a,0x8a40, + 0x36e3,0x0024,0x0000,0x190d,0x000a,0x708f,0x280a,0xcac0, + 0x0000,0xd4ce,0x0030,0x0017,0x3700,0x4024,0x0000,0x0200, + 0xb102,0x0024,0x0000,0x00c0,0x2801,0x1285,0x0005,0x4f92, + 0x2909,0xf840,0x3613,0x2800,0x0006,0x0197,0x0006,0xa115, + 0xb080,0x0024,0x3f00,0x3400,0x0000,0x190d,0x000a,0x708f, + 0x280a,0xc0c0,0x0000,0xd4ce,0x0000,0x004d,0x0020,0xfe0f, + 0x2820,0xfb40,0x0001,0x148e,0x2801,0x1655,0x3009,0x1000, + 0x6012,0x93cc,0x0000,0x0024,0x2801,0x3105,0x0000,0x0024, + 0x3413,0x0024,0x34b0,0x0024,0x4080,0x0024,0x0000,0x0200, + 0x2801,0x1955,0xb882,0x0024,0x3453,0x0024,0x3009,0x13c0, + 0x4080,0x0024,0x0000,0x0200,0x2801,0x3105,0x0000,0x0024, + 0xb882,0x130c,0x0000,0x004d,0x0021,0x058f,0x2821,0x0340, + 0x0001,0x1a4e,0x2801,0x2a95,0x6012,0x0024,0x0000,0x0024, + 0x2801,0x2a95,0x0000,0x0024,0x34c3,0x184c,0x3e13,0xb80f, + 0xf400,0x4500,0x0026,0x9dcf,0x0001,0x1e4e,0x0000,0xfa0d, + 0x2926,0x8e80,0x3e10,0x110c,0x36f3,0x0024,0x2801,0x2a80, + 0x36f3,0x980f,0x001c,0xdd00,0x001c,0xd901,0x6ec2,0x0024, + 0x001c,0xdd00,0x2801,0x2155,0x0018,0xdbc1,0x3413,0x184c, + 0xf400,0x4500,0x2926,0xc640,0x3e00,0x13cc,0x2801,0x2840, + 0x36f3,0x0024,0x6ec2,0x0024,0x003f,0xc000,0x2801,0x23d5, + 0x002a,0x4001,0x3413,0x184c,0xf400,0x4500,0x2926,0xafc0, + 0x3e00,0x13cc,0x2801,0x2840,0x36f3,0x0024,0xb400,0x0024, + 0xd100,0x0024,0x0000,0x0024,0x2801,0x2845,0x0000,0x0024, + 0x3613,0x0024,0x3e11,0x4024,0x2926,0x8540,0x3e01,0x0024, + 0x4080,0x1b8c,0x0000,0x0024,0x2801,0x2845,0x0000,0x0024, + 0x3413,0x184c,0xf400,0x4500,0x2926,0x8e80,0x3e10,0x13cc, + 0x36f3,0x0024,0x3110,0x8024,0x31f0,0xc024,0x0000,0x4000, + 0x0000,0x0021,0x6d06,0x0024,0x3110,0x8024,0x2826,0xa8c4, + 0x31f0,0xc024,0x2a26,0xad00,0x34c3,0x184c,0x3410,0x8024, + 0x3430,0xc024,0x0000,0x4000,0x0000,0x0021,0x6d06,0x0024, + 0x0000,0x0024,0x2801,0x3114,0x4d06,0x0024,0x0000,0x0200, + 0x2922,0x1885,0x0001,0x2f88,0x0000,0x0200,0x3e10,0x8024, + 0x2921,0xca80,0x3e00,0xc024,0x291a,0x8a40,0x0000,0x0024, + 0x2922,0x1880,0x36f3,0x0024,0x0000,0x004d,0x0021,0x0ecf, + 0x2821,0x0bc0,0x0001,0x308e,0x2801,0x1380,0x3c30,0x4024, + 0x0000,0x190d,0x0000,0x430e,0x2821,0x0f80,0x0027,0x9e0f, + 0x0020,0xcd4f,0x2820,0xc780,0x0001,0x32ce,0x0006,0xf017, + 0x0000,0x0015,0xb070,0xbc15,0x0000,0x430e,0x0027,0x9e0f, + 0x2820,0xcd80,0x0000,0x190d,0x3613,0x0024,0x3e10,0xb803, + 0x3e14,0x3811,0x3e11,0x3805,0x3e00,0x3801,0x0007,0xc390, + 0x0006,0xa011,0x3010,0x0444,0x3050,0x4405,0x6458,0x0302, + 0xff94,0x4081,0x0003,0xffc5,0x48b6,0x0024,0xff82,0x0024, + 0x42b2,0x0042,0xb458,0x0003,0x4cd6,0x9801,0xf248,0x1bc0, + 0xb58a,0x0024,0x6de6,0x1804,0x0006,0x0010,0x3810,0x9bc5, + 0x3800,0xc024,0x36f4,0x1811,0x36f0,0x9803,0x283e,0x2d80, + 0x0fff,0xffc3,0x2801,0x4900,0x0000,0x0024,0x3413,0x0024, + 0x2801,0x3d05,0xf400,0x4517,0x2801,0x4100,0x6894,0x13cc, + 0x37b0,0x184c,0x6090,0x1d51,0x0000,0x0910,0x3f00,0x060c, + 0x3100,0x4024,0x6016,0xb812,0x000c,0x8012,0x2801,0x3f91, + 0xb884,0x0024,0x6894,0x3002,0x0000,0x028d,0x003a,0x5e0f, + 0x0001,0x510e,0x2939,0xb0c0,0x3e10,0x93cc,0x4084,0x9bd2, + 0x4282,0x0024,0x0000,0x0040,0x2801,0x4305,0x4292,0x130c, + 0x3443,0x0024,0x2801,0x4445,0x000c,0x8390,0x2a01,0x47c0, + 0x3444,0x0024,0x3073,0x0024,0xc090,0x014c,0x2801,0x47c0, + 0x3800,0x0024,0x000c,0x4113,0xb880,0x2380,0x3304,0x4024, + 0x3800,0x05cc,0xcc92,0x05cc,0x3910,0x0024,0x3910,0x4024, + 0x000c,0x8110,0x3910,0x0024,0x39f0,0x4024,0x3810,0x0024, + 0x38d0,0x4024,0x3810,0x0024,0x38f0,0x4024,0x34c3,0x0024, + 0x3444,0x0024,0x3073,0x0024,0x3063,0x0024,0x3000,0x0024, + 0x4080,0x0024,0x0000,0x0024,0x2839,0x53d5,0x4284,0x0024, + 0x3613,0x0024,0x2801,0x4b05,0x6898,0xb804,0x0000,0x0084, + 0x293b,0x1cc0,0x3613,0x0024,0x000c,0x8117,0x3711,0x0024, + 0x37d1,0x4024,0x4e8a,0x0024,0x0000,0x0015,0x2801,0x4dc5, + 0xce9a,0x0024,0x3f11,0x0024,0x3f01,0x4024,0x000c,0x8197, + 0x408a,0x9bc4,0x3f15,0x4024,0x2801,0x5005,0x4284,0x3c15, + 0x6590,0x0024,0x0000,0x0024,0x2839,0x53d5,0x4284,0x0024, + 0x0000,0x0024,0x2801,0x3bd8,0x458a,0x0024,0x2a39,0x53c0, + 0x003e,0x2d4f,0x283a,0x5ed5,0x0001,0x348e,0x000c,0x4653, + 0x0000,0x0246,0xffac,0x0c01,0x48be,0x0024,0x4162,0x4546, + 0x6642,0x4055,0x3501,0x8024,0x0000,0x0087,0x667c,0x4057, + 0x000c,0x41d5,0x283a,0x62d5,0x3501,0x8024,0x667c,0x1c47, + 0x3701,0x8024,0x283a,0x62d5,0xc67c,0x0024,0x0000,0x0024, + 0x283a,0x62c5,0x0000,0x0024,0x2a3a,0x5ec0,0x3009,0x3851, + 0x3e14,0xf812,0x3e12,0xb817,0x3e11,0x8024,0x0006,0x0293, + 0x3301,0x8024,0x468c,0x3804,0x0006,0xa057,0x2801,0x5d04, + 0x0006,0x0011,0x469c,0x0024,0x3be1,0x8024,0x2801,0x5d15, + 0x0006,0xc392,0x3311,0x0024,0x33f1,0x2844,0x3009,0x2bc4, + 0x0030,0x04d2,0x3311,0x0024,0x3a11,0x0024,0x3201,0x8024, + 0x003f,0xfc04,0xb64c,0x0fc4,0xc648,0x0024,0x3a01,0x0024, + 0x3111,0x1fd3,0x6498,0x07c6,0x868c,0x2444,0x0023,0xffd2, + 0x3901,0x8e06,0x0030,0x0551,0x3911,0x8e06,0x3961,0x9c44, + 0xf400,0x44c6,0xd46c,0x1bc4,0x36f1,0xbc13,0x2801,0x6695, + 0x36f2,0x9817,0x002b,0xffd2,0x3383,0x188c,0x3e01,0x8c06, + 0x0006,0xa097,0x3009,0x1c12,0x3213,0x0024,0x468c,0xbc12, + 0x002b,0xffd2,0xf400,0x4197,0x2801,0x6384,0x3713,0x0024, + 0x2801,0x63c5,0x37e3,0x0024,0x3009,0x2c17,0x3383,0x0024, + 0x3009,0x0c06,0x468c,0x4197,0x0006,0xa052,0x2801,0x65c4, + 0x3713,0x2813,0x2801,0x6605,0x37e3,0x0024,0x3009,0x2c17, + 0x36f1,0x8024,0x36f2,0x9817,0x36f4,0xd812,0x2100,0x0000, + 0x3904,0x5bd1,0x2a01,0x56ce,0x3e11,0x7804,0x0030,0x0257, + 0x3701,0x0024,0x0013,0x4d05,0xd45b,0xe0e1,0x0007,0xc795, + 0x2801,0x6e15,0x0fff,0xff45,0x3511,0x184c,0x4488,0xb808, + 0x0006,0x8a97,0x2801,0x6dc5,0x3009,0x1c40,0x3511,0x1fc1, + 0x0000,0x0020,0xac52,0x1405,0x6ce2,0x0024,0x0000,0x0024, + 0x2801,0x6dc1,0x68c2,0x0024,0x291a,0x8a40,0x3e10,0x0024, + 0x2921,0xca80,0x3e00,0x4024,0x36f3,0x0024,0x3009,0x1bc8, + 0x36f0,0x1801,0x3601,0x5804,0x3e13,0x780f,0x3e13,0xb808, + 0x0008,0x9b0f,0x0001,0x70ce,0x2908,0x9300,0x0000,0x004d, + 0x36f3,0x9808,0x2000,0x0000,0x36f3,0x580f,0x0007,0x81d7, + 0x3711,0x8024,0x3711,0xc024,0x3700,0x0024,0x0000,0x2001, + 0xb012,0x0024,0x0034,0x0000,0x2801,0x7385,0x0000,0x01c1, + 0x0014,0xc000,0x0000,0x01c1,0x4fce,0x0024,0xffea,0x0024, + 0x48b6,0x0024,0x4384,0x4097,0xb886,0x45c6,0xfede,0x0024, + 0x4db6,0x0024,0x466c,0x0024,0x0006,0xc610,0x8dd6,0x8007, + 0x0000,0x00c6,0xff6e,0x0024,0x48b2,0x0024,0x0034,0x2406, + 0xffee,0x0024,0x2914,0xaa80,0x40b2,0x0024,0xf1c6,0x0024, + 0xf1d6,0x0024,0x0000,0x0201,0x8d86,0x0024,0x61de,0x0024, + 0x0006,0xc612,0x2801,0x7a01,0x0006,0xc713,0x4c86,0x0024, + 0x2912,0x1180,0x0006,0xc351,0x0006,0x0210,0x2912,0x0d00, + 0x3810,0x984c,0xf200,0x2043,0x2808,0xa000,0x3800,0x0024, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3645,0x0024,0x0000,0x800a,0x3e10,0x3801,0x3e10,0xb803, + 0x3e11,0x3805,0x3e11,0xb807,0x3e14,0x104c,0x2903,0x5400, + 0x0000,0x0081,0x4080,0x3040,0x0000,0x0101,0x2801,0x8145, + 0x0000,0x0024,0x4090,0x0024,0x0006,0x8050,0x2801,0x9555, + 0x0000,0x0024,0x2903,0x5400,0x3613,0x0024,0xb880,0x3000, + 0x2801,0x9300,0x3009,0x3380,0x2903,0x5400,0x4122,0x10cc, + 0x3cf0,0x0024,0x3001,0x0024,0x3400,0x0024,0x6800,0x0024, + 0xa408,0x9040,0x4080,0x0024,0x0000,0x07c1,0x2801,0x86d5, + 0x6894,0x1380,0x6894,0x130c,0x3460,0x0024,0x6408,0x4481, + 0x4102,0x1380,0xf400,0x4052,0x0000,0x07c1,0x34f0,0xc024, + 0x6234,0x0024,0x6824,0x0024,0xa122,0x0024,0x6014,0x0024, + 0x0000,0x0141,0x2801,0x8dd5,0x0000,0x0024,0x2903,0x5400, + 0x3613,0x0024,0x2801,0x8c40,0xb88a,0x4002,0x2900,0xac40, + 0x3e00,0x8024,0x4c8e,0xa801,0x0000,0x0201,0x3a10,0x1bcc, + 0x3000,0x0024,0xb010,0x0024,0x0000,0x0024,0x2801,0x91d5, + 0x659a,0x0024,0x6540,0x184c,0x0030,0x0010,0x2801,0x89c8, + 0x0000,0x0024,0x2801,0x91c0,0x36f3,0x0024,0x2801,0x9080, + 0xb88a,0x0024,0x2903,0x1c40,0x34d0,0x4024,0x4c8f,0xa0a1, + 0x0000,0x0201,0x3000,0x084c,0xb010,0x0024,0x0000,0x0024, + 0x2801,0x91d5,0x659a,0x0024,0x6540,0x10cc,0x0030,0x0010, + 0x2801,0x8e48,0x0000,0x0024,0x34d3,0x0024,0x3423,0x0024, + 0xf400,0x4510,0x3009,0x1380,0x6090,0x0024,0x3009,0x2000, + 0x6892,0x108c,0x34f0,0x9000,0xa122,0x984c,0x6016,0x13c1, + 0x0000,0x0102,0x2801,0x8288,0x0006,0x8150,0x2801,0x95c0, + 0x3009,0x1bcc,0x6890,0x938c,0x3800,0x0024,0x36f4,0x0024, + 0x36f1,0x9807,0x36f1,0x1805,0x36f0,0x9803,0x36f0,0x1801, + 0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000, + 0x36f2,0x9817,0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815, + 0x3e05,0xb814,0x3675,0x0024,0x3643,0x0024,0x0000,0x800a, + 0x3e10,0x3801,0x0000,0x0181,0x3e10,0xb803,0x3e11,0x3806, + 0x3e11,0xf810,0x3e14,0x7812,0x3e13,0xf80e,0x2903,0x2540, + 0x3e03,0x4024,0x2903,0x5400,0x4088,0x184c,0x3413,0x184c, + 0x2903,0x5400,0x6892,0x3040,0x4080,0x3040,0x0000,0x0000, + 0x2801,0xa345,0x0000,0x0024,0x6890,0x0024,0x2903,0x2540, + 0x3cd0,0x0024,0x4080,0x0024,0x0000,0x0024,0x2801,0xa395, + 0x0000,0x0024,0x3433,0x0024,0xf400,0x4510,0x34d0,0x0024, + 0x6090,0x0024,0x2903,0x2540,0x3800,0x0024,0x4080,0x10cc, + 0xf400,0x4510,0x2801,0xa105,0x34d0,0x0024,0x2801,0xa380, + 0x0000,0x0024,0x3cd0,0x0024,0x3433,0x0024,0x34a0,0x0024, + 0xf400,0x4510,0x3430,0x4024,0x6100,0x0024,0x0000,0x0341, + 0x3840,0x0024,0x3000,0x0024,0x6012,0x0024,0x0006,0x0581, + 0x2801,0xc101,0x4012,0x0024,0xf400,0x4057,0x3702,0x0024, + 0x2000,0x0000,0x0000,0x0024,0x34d3,0x184c,0x3430,0x8024, + 0x2900,0xac40,0x3e00,0x8024,0x36f3,0x11cc,0xb888,0x104c, + 0x3c10,0x0024,0x3c90,0x4024,0x2801,0xacc0,0x34e3,0x0024, + 0x3411,0x8024,0x3491,0xc024,0x4f82,0x128c,0x3400,0x4024, + 0x4142,0x0024,0xf400,0x4050,0x3800,0x0024,0x3440,0x4024, + 0x4142,0x0024,0x6498,0x4050,0x3009,0x2007,0x0006,0x8150, + 0x3000,0x11cc,0x6402,0x104c,0x0000,0x0024,0x2801,0xaa08, + 0x0000,0x0024,0x3493,0x0024,0x2801,0xdcc0,0x34f3,0x0024, + 0x2801,0xb440,0xb888,0x0024,0x3430,0x8024,0x2900,0xac40, + 0x3e00,0x8024,0x4c8e,0x130c,0x3400,0x5bcc,0x4142,0x0024, + 0xf400,0x4050,0x3800,0x0024,0x3440,0x4024,0x4142,0x0024, + 0xf400,0x4050,0x0000,0x0201,0x3009,0x2007,0x0030,0x0010, + 0x3000,0x0024,0xb010,0x0024,0x0000,0x0024,0x2801,0xdcd5, + 0x6498,0x0024,0x0006,0x8150,0x3000,0x134c,0x6402,0x984c, + 0x0000,0x0024,0x2801,0xaf88,0x0000,0x0024,0x2801,0xdcc0, + 0x3433,0x1bcc,0x0000,0x0201,0xb888,0x104c,0x3430,0x184c, + 0x6010,0x0024,0x6402,0x3000,0x0000,0x0201,0x2801,0xbcd8, + 0x0030,0x0010,0x4090,0x124c,0x2401,0xbbc0,0x0000,0x0024, + 0x3430,0x8024,0x2900,0xac40,0x3e00,0x8024,0x4c8e,0x130c, + 0x3400,0x4024,0x4142,0x0024,0xf400,0x4050,0x3800,0x0024, + 0x3410,0x4024,0x4142,0x0024,0x6498,0x4050,0x3009,0x2007, + 0x0030,0x0010,0x0000,0x0201,0x3473,0x0024,0x3490,0x0024, + 0x3e00,0x13cc,0x2901,0x7c00,0x3444,0x8024,0x3000,0x1bcc, + 0xb010,0x0024,0x0000,0x0024,0x2801,0xdcd5,0x0000,0x0024, + 0x34c3,0x184c,0x3470,0x0024,0x3e10,0x104c,0x34c0,0x4024, + 0x2900,0xb580,0x3e00,0x4024,0x2801,0xdcc0,0x36e3,0x0024, + 0x0000,0x0801,0x3413,0x0024,0x34f0,0x0024,0x6012,0x0024, + 0x0000,0x07c1,0x2801,0xdc08,0x0000,0x0024,0x6010,0x114c, + 0xb888,0x32c0,0x6402,0x0024,0x0000,0x0101,0x2801,0xc898, + 0x0000,0x0024,0x4090,0x134c,0x2401,0xc7c0,0x3009,0x184c, + 0x3430,0x8024,0x2900,0xac40,0x3e00,0x8024,0x4c8e,0x130c, + 0x3400,0x4024,0x4142,0x0024,0xf400,0x4050,0x3800,0x0024, + 0x3410,0x4024,0x4142,0x0024,0x6498,0x4050,0x3009,0x2007, + 0x0000,0x0101,0x3433,0x1bcc,0x2903,0x5400,0x3613,0x0024, + 0x0000,0x0141,0x6090,0x118c,0x2903,0x5400,0x3ca0,0x184c, + 0x3473,0x184c,0xb888,0x3380,0x3400,0x0024,0x6402,0x0024, + 0x0000,0x0201,0x2801,0xcf58,0x0000,0x0024,0x4090,0x104c, + 0x2401,0xce80,0x0000,0x0024,0x34a0,0x8024,0x2900,0xac40, + 0x3e00,0x8024,0x0006,0x8002,0x4244,0x118c,0x4244,0x0024, + 0x6498,0x4095,0x3009,0x3440,0x3009,0x37c1,0x0000,0x0201, + 0x34f3,0x0024,0x0030,0x0010,0x3490,0x0024,0x3e00,0x138c, + 0x2901,0x7c00,0x3444,0x8024,0x3000,0x1bcc,0xb010,0x0024, + 0x0000,0x0024,0x2801,0xdcd5,0x4112,0x0024,0x3463,0x0024, + 0x34a0,0x0024,0x6012,0x0024,0x0006,0x8111,0x2801,0xd899, + 0x0000,0x0024,0x3100,0x11cc,0x3490,0x4024,0x4010,0x0024, + 0x0000,0x0a01,0x6012,0x0024,0x0006,0x8151,0x2801,0xd898, + 0x0000,0x0024,0x3613,0x114c,0x3101,0x3804,0x3490,0x8024, + 0x6428,0x138c,0x3470,0x8024,0x3423,0x0024,0x3420,0xc024, + 0x4234,0x1241,0x4380,0x4092,0x2903,0xaa00,0x0006,0x8010, + 0x2801,0xdcc0,0x3009,0x1bcc,0x0006,0x8151,0x3613,0x114c, + 0x3101,0x3804,0x3490,0x8024,0x6428,0x138c,0x3470,0x8024, + 0x3423,0x0024,0x3420,0xc024,0x4234,0x1241,0x4380,0x4092, + 0x2903,0xb3c0,0x0006,0x8010,0x2801,0xdcc0,0x3009,0x1bcc, + 0x0006,0x8050,0x6890,0x0024,0x3800,0x0024,0x3433,0x0024, + 0x34d0,0x0024,0x4080,0x0024,0x0006,0x8150,0x2801,0xe245, + 0x0000,0x0024,0x3000,0x11cc,0xb888,0x10cc,0x6402,0x3240, + 0x3493,0x0024,0x3444,0x8024,0x2801,0xe258,0x4090,0x0024, + 0x2401,0xe200,0x0000,0x0024,0x6499,0x2620,0xb78e,0x4001, + 0x0000,0x0000,0x3433,0x0024,0xcfce,0x1340,0xaf0e,0x0024, + 0x3a11,0xa807,0x36f3,0x4024,0x36f3,0xd80e,0x36f4,0x5812, + 0x36f1,0xd810,0x36f1,0x1806,0x36f0,0x9803,0x36f0,0x1801, + 0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000, + 0x36f2,0x9817,0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815, + 0x3e05,0xb814,0x3615,0x0024,0x0000,0x800a,0x3e10,0x7802, + 0x3e10,0xf804,0x0000,0x3fc3,0x3e11,0x7806,0x3e11,0xf810, + 0xbc82,0x12cc,0x3404,0x0024,0x3023,0x0024,0x3810,0x0024, + 0x38f0,0x4024,0x3454,0x0024,0x3810,0x0024,0x38f0,0x4024, + 0x2903,0x5400,0x0000,0x0201,0x0006,0x9301,0x4088,0x134c, + 0x3400,0x8024,0xd204,0x0024,0xb234,0x0024,0x4122,0x0024, + 0xf400,0x4055,0x3500,0x0024,0x3c30,0x0024,0x0000,0x2000, + 0xb400,0x0024,0x0000,0x3001,0x2801,0xefd5,0x0000,0x3800, + 0x0000,0x0041,0xfe42,0x12cc,0x48b2,0x1090,0x3810,0x0024, + 0x38f0,0x4024,0x2802,0x10c0,0x3430,0x0024,0xb400,0x0024, + 0x6012,0x0024,0x0000,0x3801,0x2801,0xf315,0x0000,0x3c00, + 0x0000,0x07c0,0x0000,0x0041,0xb400,0x12cc,0xfe02,0x1150, + 0x48b2,0x0024,0x689a,0x2040,0x2802,0x0f80,0x38f0,0x4024, + 0xb400,0x0024,0x6012,0x0024,0x0000,0x3c01,0x2801,0xf695, + 0x0000,0x3e00,0x0000,0x03c0,0x0000,0x0085,0x4592,0x12cc, + 0xb400,0x1150,0xfe02,0x0024,0x48b2,0x0024,0x3810,0x0024, + 0x2802,0x0f80,0x38f0,0x4024,0xb400,0x0024,0x6012,0x0024, + 0x0000,0x3e01,0x2801,0xfa15,0x0000,0x3f00,0x0000,0x01c0, + 0xf20a,0x12cc,0xb400,0x1150,0xf252,0x0024,0xfe02,0x0024, + 0x48b2,0x0024,0x3810,0x0024,0x2802,0x0f80,0x38f0,0x4024, + 0xb400,0x130c,0x6012,0x0024,0x0000,0x3f01,0x2801,0xfd95, + 0x4390,0x0024,0x0000,0x0041,0x0000,0x0105,0x4590,0x13cc, + 0xb400,0x1150,0xfe02,0x0024,0x48b2,0x0024,0x3810,0x0024, + 0x2802,0x0f80,0x38f0,0x4024,0xb400,0x0024,0x6012,0x1100, + 0x0000,0x01c1,0x2802,0x0115,0x0000,0x0024,0x0000,0x0041, + 0x0000,0x0145,0x6890,0x12cc,0xb400,0x1150,0xfe02,0x0024, + 0x48b2,0x0024,0x3810,0x0024,0x2802,0x0f80,0x38f0,0x4024, + 0x6012,0x0024,0x0000,0x3f81,0x2802,0x0395,0xb430,0x0024, + 0x6012,0x0024,0x0000,0x0024,0x2802,0x0395,0x0000,0x0024, + 0x2802,0x0f80,0x0000,0x0185,0x2802,0x10c0,0xc890,0x0024, + 0x0000,0x3fc3,0x0000,0x0201,0x34d3,0x0024,0x2903,0x5400, + 0x3433,0x184c,0x0006,0x9301,0x4088,0x134c,0x3400,0x8024, + 0xd204,0x0024,0xb234,0x0024,0x4122,0x0024,0xf400,0x4055, + 0x0000,0x2001,0x3500,0x0024,0x3c30,0x0024,0x0000,0x3000, + 0xb400,0x0024,0x6012,0x0024,0x0000,0x0182,0x2802,0x09c5, + 0x0000,0x0024,0x2802,0x10c0,0xc890,0x0024,0x459a,0x12cc, + 0x3404,0x0024,0x3023,0x0024,0x3010,0x0024,0x30d0,0x4024, + 0xac22,0x0046,0x003f,0xf982,0x3011,0xc024,0x0000,0x0023, + 0xaf2e,0x0024,0x0000,0x0182,0xccf2,0x0024,0x0000,0x0fc6, + 0x0000,0x0047,0xb46c,0x2040,0xfe6e,0x23c1,0x3454,0x0024, + 0x3010,0x0024,0x30f0,0x4024,0xac22,0x0024,0xccb2,0x0024, + 0x3810,0x0024,0x38f0,0x4024,0x458a,0x134c,0x0000,0x0201, + 0x2802,0x04d5,0x0000,0x3fc3,0x3430,0x0024,0x36f1,0xd810, + 0x36f1,0x5806,0x36f0,0xd804,0x36f0,0x5802,0x3405,0x9014, + 0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3675,0x0024,0x3633,0x0024,0x0000,0x800a,0x3e10,0x3801, + 0x3e10,0xb803,0x3e11,0x3805,0x3e11,0xb807,0x3e14,0x3811, + 0x3e14,0xb813,0x3e13,0xf80e,0x3e03,0x4024,0x2903,0x9100, + 0x0000,0x0381,0x000f,0xff81,0x6012,0x184c,0x0000,0x0201, + 0x2802,0x1945,0x0000,0x0024,0x2903,0x5400,0x0002,0xfc88, + 0x3613,0x0024,0x0000,0x0401,0x0006,0x8a10,0x2900,0xbf40, + 0xb880,0x1bcc,0xb880,0x11cc,0x3413,0x184c,0x3c90,0x0024, + 0x2903,0x5400,0x34f3,0x0024,0x3473,0x184c,0x3c00,0x0000, + 0x4080,0x0024,0x0006,0x9301,0x2802,0x1ec5,0x003f,0xfe04, + 0x3490,0x8024,0xa244,0x0024,0x2903,0x7400,0xb880,0x0024, + 0x2900,0xbf40,0x003f,0xfe04,0x3473,0x184c,0x0006,0x8091, + 0x3413,0x0024,0x34f0,0x8024,0x3400,0xc024,0xa346,0x0024, + 0xd234,0x0024,0x0000,0x3fc3,0xb234,0x0024,0x4122,0x1042, + 0xf400,0x4055,0x0006,0x9301,0x3500,0x0024,0xd024,0x3000, + 0xb234,0x0024,0x4122,0x0024,0x6892,0x4055,0x3500,0x0024, + 0x3cf0,0x0024,0x34a0,0x0024,0xf100,0x0024,0xb010,0x0024, + 0x3c60,0x0024,0x34b0,0x0024,0xb010,0x0024,0x0000,0x0201, + 0x2903,0x5400,0x3ce0,0x0024,0x0006,0x9301,0x3473,0x184c, + 0x3c10,0x0024,0x34f0,0x8024,0x3410,0xc024,0xd234,0x0024, + 0x0000,0x3fc3,0xb234,0x0024,0x4122,0x0024,0xf400,0x4055, + 0x003f,0xff01,0x3500,0x0024,0x3cf0,0x0024,0x34c0,0x0024, + 0xa010,0x0024,0x0000,0x03c1,0x3c40,0x0024,0x34d0,0x0024, + 0xb010,0x0024,0x0000,0x0201,0x2903,0x5400,0x3cc0,0x0024, + 0x0006,0x9301,0x3473,0x0024,0x3c10,0x0024,0x34f0,0x8024, + 0x3410,0xc024,0xd234,0x0024,0x0000,0x3fc3,0xb234,0x0024, + 0x4122,0x0024,0xf400,0x4055,0x003f,0xff01,0x3500,0x0024, + 0x3cf0,0x0024,0x3400,0x0024,0xa010,0x0024,0x0000,0x01c1, + 0x3900,0x0024,0x34e0,0x0024,0xf100,0x0024,0xb010,0x0024, + 0x6892,0x3080,0x34f0,0x0024,0xb010,0x0024,0x3cb0,0x0024, + 0x3450,0x0024,0x34a0,0x4024,0xc010,0x0024,0x0000,0x0181, + 0x2802,0x3345,0x3100,0x0024,0x6890,0x07cc,0x2802,0xfc80, + 0x3900,0x0024,0x6012,0x0024,0x0000,0x0201,0x2802,0x34d8, + 0x0000,0x0024,0x2802,0x37c0,0x6090,0x044c,0x6012,0x0024, + 0x0000,0x0281,0x2802,0x3708,0x6012,0x0024,0x0000,0x0080, + 0x2802,0x3719,0x0000,0x0024,0x2802,0x37c0,0x3113,0x0024, + 0x6890,0x07cc,0x2802,0xfc80,0x3900,0x0024,0x0000,0x0201, + 0x3900,0x114c,0x34b0,0x0024,0x6012,0x0024,0x0006,0x08c1, + 0x2802,0x4201,0x4012,0x0024,0xf400,0x4057,0x3702,0x0024, + 0x2000,0x0000,0x0000,0x0024,0x2802,0x4200,0x0000,0x0024, + 0x0000,0x0200,0x0006,0x8110,0x2802,0x4200,0x3800,0x0024, + 0x0000,0x0300,0x0006,0x8110,0x2802,0x4200,0x3800,0x0024, + 0x0006,0x8050,0x6890,0x0024,0x2802,0xfc80,0x3800,0x0024, + 0x0000,0x0400,0x0006,0x8110,0x2802,0x4200,0x3800,0x0024, + 0x0000,0x0500,0x0006,0x8110,0x2802,0x4200,0x3800,0x0024, + 0x0000,0x0600,0x0006,0x8110,0x2802,0x4200,0x3800,0x0024, + 0x0006,0x8050,0x6890,0x0024,0x2802,0xfc80,0x3800,0x0024, + 0x3423,0x184c,0x3460,0x0024,0x4080,0x0024,0x0006,0x8200, + 0x2802,0x4745,0x3e10,0x0024,0x0000,0x01c0,0x3e10,0x0024, + 0x3490,0x0024,0x2901,0xe540,0x3e00,0x13cc,0x36d3,0x11cc, + 0x3413,0x0024,0x4080,0x3240,0x34f3,0x0024,0x2802,0x4b18, + 0x0000,0x0024,0x0006,0x8010,0x6890,0x0024,0x2802,0xfc80, + 0x3800,0x0024,0x0000,0x0180,0x3e10,0x0024,0x3490,0x0024, + 0x2901,0xe540,0x3e00,0x13cc,0x36d3,0x11cc,0x3413,0x0024, + 0x4080,0x3240,0x34f3,0x0024,0x2802,0x4b18,0x0000,0x0024, + 0x0006,0x8010,0x6890,0x0024,0x2802,0xfc80,0x3800,0x0024, + 0x0000,0x0201,0x3433,0x0024,0x34d0,0x0024,0x6012,0x0024, + 0x0006,0x0ac1,0x2802,0x5d01,0x4012,0x0024,0xf400,0x4057, + 0x3702,0x0024,0x2000,0x0000,0x0000,0x0024,0x0006,0x8050, + 0x6890,0x0024,0x2802,0xfc80,0x3800,0x0024,0x0000,0x3000, + 0x2802,0x5ec0,0x0006,0x8150,0x0000,0x9000,0x0006,0x8150, + 0x3433,0x0024,0x34d0,0x4024,0x4192,0x0024,0x4192,0x0024, + 0x2802,0x5ec0,0xa010,0x0024,0x0000,0x0201,0x0006,0x8150, + 0x2903,0x5400,0x3613,0x0024,0x0006,0x9301,0x3473,0x0024, + 0x3c10,0x0024,0x34f0,0x8024,0x3410,0xc024,0xd234,0x0024, + 0x0000,0x3fc3,0xb234,0x0024,0x4122,0x0024,0xf400,0x4055, + 0x3500,0x0024,0x3cf0,0x0024,0x3490,0x0024,0x2802,0x5ec0, + 0x6090,0x0024,0x003f,0xfe04,0x0000,0x0401,0x0006,0x8150, + 0x2903,0x5400,0x3613,0x0024,0x0006,0x9301,0x3473,0x0024, + 0x3c10,0x0024,0x34f0,0x8024,0x3400,0xc024,0xa346,0x0024, + 0xd234,0x0024,0x0000,0x3fc3,0xb234,0x0024,0x4122,0x1042, + 0xf400,0x4055,0x0006,0x9301,0x3500,0x0024,0xd024,0x3000, + 0xb234,0x0024,0x4122,0x0024,0xf400,0x4055,0x3500,0x0024, + 0x3cf0,0x0024,0x3490,0x0024,0x2802,0x5ec0,0x6090,0x0024, + 0x0000,0x4000,0x0000,0x0202,0x0006,0x8150,0x3433,0x0024, + 0x34d0,0x4024,0x6122,0x0024,0xa010,0x0024,0x0004,0x8001, + 0x3800,0x110c,0x0006,0x8150,0x3000,0x0024,0x6012,0x1300, + 0x0000,0x0401,0x2802,0x6189,0x0000,0x0024,0x6890,0x82cc, + 0x2802,0xfc80,0x3800,0x0024,0x6012,0x0024,0x0006,0x0cc1, + 0x2802,0x8901,0x4012,0x0024,0xf400,0x4057,0x3702,0x0024, + 0x2000,0x0000,0x0000,0x0024,0x2802,0x8900,0x0000,0x0024, + 0x0016,0x2200,0x0006,0x8190,0x6892,0x2040,0x2802,0x8900, + 0x38f0,0x4024,0x002c,0x4400,0x0000,0x0081,0x0006,0x8190, + 0x3810,0x0024,0x2802,0x8900,0x38f0,0x4024,0x003b,0x8000, + 0x0000,0x0081,0x0006,0x8190,0x3810,0x0024,0x2802,0x8900, + 0x38f0,0x4024,0x0007,0xd000,0x0006,0x8190,0xb882,0x2040, + 0x2802,0x8900,0x38f0,0x4024,0x000f,0xa000,0x0006,0x8190, + 0xb882,0x2040,0x2802,0x8900,0x38f0,0x4024,0x0015,0x8880, + 0x0006,0x8190,0xb882,0x2040,0x2802,0x8900,0x38f0,0x4024, + 0x0017,0x7000,0x0006,0x8190,0xb882,0x2040,0x2802,0x8900, + 0x38f0,0x4024,0x001f,0x4000,0x0006,0x8190,0xb882,0x2040, + 0x2802,0x8900,0x38f0,0x4024,0x002b,0x1100,0x0006,0x8190, + 0xb882,0x2040,0x2802,0x8900,0x38f0,0x4024,0x002e,0xe000, + 0x0006,0x8190,0xb882,0x2040,0x2802,0x8900,0x38f0,0x4024, + 0x001d,0xc000,0x0006,0x8190,0x6892,0x2040,0x2802,0x8900, + 0x38f0,0x4024,0x0006,0x8190,0x0000,0x0201,0x0000,0xfa04, + 0x2903,0x5400,0x3613,0x0024,0x0006,0x9301,0xb88a,0x11cc, + 0x3c10,0x0024,0x34f0,0x8024,0x3410,0xc024,0xd234,0x0024, + 0x0000,0x3fc3,0xb234,0x0024,0x4122,0x0024,0xf400,0x4055, + 0x3500,0x0024,0x3cf0,0x0024,0x3490,0x0024,0xfe50,0x4005, + 0x48b2,0x0024,0xfeca,0x0024,0x40b2,0x0024,0x3810,0x0024, + 0x2802,0x8900,0x38f0,0x4024,0x003f,0xfe04,0x0000,0x0401, + 0x0006,0x8190,0x2903,0x5400,0x3613,0x0024,0x0006,0x9301, + 0x3473,0x0024,0x3c10,0x0024,0x34f0,0x8024,0x3400,0xc024, + 0xa346,0x0024,0xd234,0x0024,0x0000,0x3fc3,0xb234,0x0024, + 0x4122,0x1042,0xf400,0x4055,0x0006,0x9301,0x3500,0x0024, + 0xd024,0x3000,0xb234,0x0024,0x4122,0x0024,0xf400,0x4055, + 0x0000,0x0041,0x3500,0x0024,0x3cf0,0x0024,0x3490,0x0024, + 0xfe02,0x0024,0x48b2,0x0024,0x3810,0x0024,0x2802,0x8900, + 0x38f0,0x4024,0x003f,0xfe04,0x0000,0x0401,0x0006,0x8190, + 0x2903,0x5400,0x3613,0x0024,0x0006,0x9301,0x3473,0x0024, + 0x3c10,0x0024,0x34f0,0x8024,0x3400,0xc024,0xa346,0x0024, + 0xd234,0x0024,0x0000,0x3fc3,0xb234,0x0024,0x4122,0x1042, + 0xf400,0x4055,0x0006,0x9301,0x3500,0x0024,0xd024,0x3000, + 0xb234,0x0024,0x4122,0x0024,0xf400,0x4055,0x3500,0x0024, + 0x3cf0,0x0024,0x0000,0x0280,0x3490,0x4024,0xfe02,0x0024, + 0x48b2,0x0024,0x3810,0x0024,0x2802,0x8900,0x38f0,0x4024, + 0x0006,0x8010,0x6890,0x0024,0x2802,0xfc80,0x3800,0x0024, + 0x0000,0x0201,0x2903,0x5400,0x3613,0x11cc,0x3c10,0x0024, + 0x3490,0x4024,0x6014,0x13cc,0x0000,0x0081,0x2802,0x8c45, + 0x0006,0x80d0,0x0006,0x8010,0x6890,0x0024,0x2802,0xfc80, + 0x3800,0x0024,0x3010,0x0024,0x6012,0x0024,0x0000,0x0241, + 0x2802,0xabc9,0x0006,0x8112,0x0008,0x0001,0x3009,0x184c, + 0x3e10,0x4024,0x3000,0x8024,0x2901,0x9840,0x3e00,0x8024, + 0x36f3,0x004c,0x3000,0x3844,0x0008,0x0010,0xb884,0x3840, + 0x0000,0x0400,0x3e00,0x8024,0x3201,0x0024,0x2903,0x3400, + 0x6408,0x4091,0x0001,0x0000,0x000b,0x8011,0x0004,0x0010, + 0x36e3,0x0024,0x2915,0x8300,0x3009,0x1bc4,0x000b,0x8000, + 0x3613,0x0024,0x3e10,0x0024,0x3200,0xc024,0x2901,0x9840, + 0x3e00,0xc024,0x36f3,0x084c,0x32f0,0xf844,0x3e10,0xc024, + 0x3e00,0x8024,0x2b01,0x0091,0x0000,0x0400,0xf204,0x0804, + 0x2903,0x3400,0x6408,0x0024,0x000b,0x8011,0x0008,0x0010, + 0x0000,0x0084,0x36d3,0x0024,0x2915,0x8300,0x0003,0x8000, + 0x0005,0x0010,0x0001,0x0000,0x2915,0x8300,0x000f,0x0011, + 0x1006,0x0ac0,0x32f3,0x11cc,0x3200,0xd08c,0xff34,0x0024, + 0x48b6,0x0024,0x4020,0x0024,0x3c90,0x0024,0x2802,0xa800, + 0x34e3,0x0024,0x0006,0x8112,0x3613,0x0024,0x3e10,0x0024, + 0x3000,0x4024,0x2901,0x9840,0x3e00,0x4024,0x36f3,0x004c, + 0x3000,0x7844,0xb884,0x3841,0x2b01,0x0091,0x0000,0x0400, + 0x3e00,0x8024,0x3201,0x0024,0x2903,0x3400,0x6408,0x0024, + 0x0003,0x8000,0x000b,0x8011,0x0008,0x0010,0x36e3,0x11cc, + 0x3423,0x0024,0x3494,0xc024,0x2903,0x5f80,0x3301,0x138c, + 0x0001,0x0000,0x000f,0x0011,0x0004,0x0010,0x2903,0x64c0, + 0x3301,0x0024,0xf400,0x4510,0x000b,0x8011,0x3073,0x0024, + 0x3023,0x0024,0x3000,0x0024,0x6090,0x0024,0x3800,0x0024, + 0x0003,0x8000,0x3004,0xc024,0x0008,0x0010,0x2903,0x64c0, + 0x3301,0x0024,0x0001,0x0000,0x000f,0x0011,0x0005,0x0010, + 0x2903,0x64c0,0x3301,0x0024,0xf400,0x4510,0x3073,0x1bc4, + 0x6498,0x008c,0x3000,0x0024,0x6090,0x0024,0x3800,0x0024, + 0x0006,0x80d0,0x3000,0x0024,0x6402,0x0024,0x0006,0x8110, + 0x2802,0x9b48,0x000b,0x8000,0x000b,0x8010,0x0001,0x0000, + 0x2903,0xc580,0x0004,0x0011,0x0005,0x0011,0x000b,0x8010, + 0x0001,0x0000,0x291f,0xc6c0,0x0002,0xbd08,0x30e1,0x184c, + 0x3000,0x0024,0x6012,0x0024,0x0008,0x0001,0x2802,0xad95, + 0x0000,0x0024,0x6498,0x0024,0x3e10,0x4024,0x0000,0x0081, + 0x2901,0x9840,0x3e01,0x0024,0x36e3,0x004c,0x3000,0x0024, + 0x6012,0x0024,0x000b,0x8011,0x2802,0xb9d5,0x0006,0x8112, + 0x0000,0x0201,0x0004,0x0010,0x2915,0x8300,0x0001,0x0000, + 0x000b,0x8011,0x0005,0x0010,0x291f,0xc6c0,0x0001,0x0000, + 0x0006,0x8110,0x30e1,0x0024,0x3000,0x0024,0x6012,0x0024, + 0x0000,0x0281,0x2802,0xb4c5,0x6012,0x0024,0x000b,0x8001, + 0x2802,0xb555,0x3613,0x0024,0x36f3,0x0024,0x000b,0x8001, + 0x6498,0x184c,0x0006,0x8112,0x0003,0x8000,0x3e10,0x4024, + 0x2901,0x9840,0x3e01,0x0024,0x36f3,0x0024,0x3009,0x3844, + 0x3e10,0x0024,0x0000,0x0400,0x3000,0x8024,0x0008,0x0010, + 0x3e00,0x8024,0x3201,0x0024,0x2903,0x3400,0x6408,0x4051, + 0x36e3,0x0024,0x2802,0xbd00,0x3009,0x1bc4,0x0000,0x0400, + 0x0000,0x0011,0x3613,0x008c,0x30d0,0x7844,0x3e10,0x4024, + 0x3000,0x8024,0x0008,0x0010,0x3e00,0x8024,0x3201,0x0024, + 0x2903,0x3400,0x6408,0x0024,0x36e3,0x0024,0x3009,0x1bc4, + 0x0006,0x8a10,0x0000,0x01c1,0x3009,0x0000,0xb010,0x0024, + 0x0000,0x0024,0x2802,0xc105,0x6192,0x0024,0x2903,0x5400, + 0x6102,0x184c,0x4088,0x0024,0x0000,0x0024,0x2802,0xc105, + 0x0000,0x0024,0x0006,0x8051,0x6890,0x0024,0x3900,0x0024, + 0x3009,0x0000,0x4080,0x0024,0x0000,0x0024,0x2903,0x7345, + 0x0002,0xc5c8,0x0006,0x9f92,0x0000,0x4003,0x3009,0x0811, + 0x3100,0x8024,0xffa6,0x0024,0x48b6,0x0024,0x2903,0x7340, + 0x4384,0x0024,0x2903,0x7400,0x3613,0x0024,0x2900,0xbf40, + 0x0000,0x0024,0x2903,0x7340,0x0000,0x0024,0x0000,0x0401, + 0x3473,0x184c,0x2903,0x5400,0x3c10,0x0024,0x3c90,0x0024, + 0x290b,0x1400,0x34f3,0x0024,0x4080,0x0024,0x0000,0x0024, + 0x2802,0xf915,0x0000,0x0024,0x3473,0x0024,0x3410,0x0024, + 0x34a0,0x4024,0x6014,0x1380,0x0000,0x0024,0x2802,0xcdc5, + 0x4080,0x0024,0x0006,0x8011,0x6890,0x0024,0xb882,0x2400, + 0x0004,0x8000,0x2914,0xbec0,0x0008,0x0010,0x0000,0x0400, + 0x3143,0x108c,0x6890,0x27c0,0x3920,0x0024,0x0004,0x8000, + 0x3900,0x0024,0x34e0,0x0024,0x4080,0x0024,0x0006,0x8150, + 0x2802,0xd1c5,0x0000,0x3200,0x0000,0x0142,0x0006,0x8210, + 0x3613,0x0024,0x3e00,0x7800,0x3011,0x8024,0x30d1,0xc024, + 0xfef4,0x4087,0x48b6,0x0040,0xfeee,0x03c1,0x2914,0xa580, + 0x42b6,0x0024,0x2802,0xd5c0,0x0007,0x89d0,0x0000,0x0142, + 0x3613,0x0024,0x3e00,0x7800,0x3031,0x8024,0x3010,0x0024, + 0x30d0,0x4024,0xfe9c,0x4181,0x48be,0x0024,0xfe82,0x0040, + 0x46be,0x03c1,0xfef4,0x4087,0x48b6,0x0024,0xfeee,0x0024, + 0x2914,0xa580,0x42b6,0x0024,0x0007,0x89d0,0x0006,0x8191, + 0x4c8a,0x9800,0xfed0,0x4005,0x48b2,0x0024,0xfeca,0x0024, + 0x40b2,0x0024,0x3810,0x0024,0x38f0,0x4024,0x3111,0x8024, + 0x468a,0x0707,0x2908,0xbe80,0x3101,0x0024,0x3123,0x11cc, + 0x3100,0x108c,0x3009,0x3000,0x0004,0x8000,0x3009,0x1241, + 0x6014,0x138c,0x000b,0x8011,0x2802,0xdc01,0x0000,0x0024, + 0x3473,0x0024,0x3423,0x0024,0x3009,0x3240,0x34e3,0x0024, + 0x2802,0xf740,0x0008,0x0012,0x0000,0x0081,0x2802,0xdd89, + 0x0006,0x80d0,0xf400,0x4004,0x3000,0x0024,0x6012,0x0024, + 0x0000,0x0005,0x2802,0xe309,0x0000,0x0024,0x6540,0x0024, + 0x0000,0x0024,0x2802,0xf358,0x4490,0x0024,0x2402,0xe240, + 0x0000,0x0024,0x0006,0x8301,0x4554,0x0800,0x4122,0x0024, + 0x659a,0x4055,0x0006,0x8341,0x3d00,0x0840,0x4122,0x0024, + 0xf400,0x4055,0x3d00,0x0024,0x2802,0xf340,0x0000,0x0024, + 0x4090,0x0024,0xf400,0x4480,0x2802,0xe855,0x000b,0x8001, + 0x6540,0x0024,0x0000,0x0024,0x2802,0xf358,0x4490,0x0024, + 0x2402,0xe780,0x0000,0x0024,0x0006,0x8301,0x4554,0x0800, + 0x4122,0x0024,0x659a,0x4055,0x0006,0x8341,0x4122,0x3400, + 0xf400,0x4055,0x3210,0x0024,0x3d00,0x0024,0x2802,0xf340, + 0x0000,0x0024,0x6014,0x0024,0x0001,0x0000,0x2802,0xef95, + 0x0003,0x8001,0x0008,0x0012,0x0008,0x0010,0x0006,0x8153, + 0x3613,0x0024,0x3009,0x3811,0x2903,0xc580,0x0004,0x0011, + 0x0008,0x0010,0x0001,0x0000,0x291f,0xc6c0,0x0005,0x0011, + 0x000f,0x0011,0x0008,0x0010,0x33d0,0x184c,0x6010,0xb844, + 0x3e10,0x0024,0x0000,0x0400,0x3320,0x4024,0x3e00,0x4024, + 0x3301,0x0024,0x2903,0x3400,0x6408,0x0024,0x36e3,0x0024, + 0x3009,0x1bc4,0x3009,0x1bd1,0x6540,0x0024,0x0000,0x0024, + 0x2802,0xf358,0x4490,0x0024,0x2402,0xf300,0x0000,0x0024, + 0x0006,0x8301,0x4554,0x0840,0x4122,0x0024,0x659a,0x4055, + 0x0006,0x8341,0x4122,0x3400,0xf400,0x4055,0x3110,0x0024, + 0x3d00,0x0024,0xf400,0x4510,0x0030,0x0013,0x3073,0x184c, + 0x3e11,0x008c,0x3009,0x0001,0x6140,0x0024,0x0000,0x0201, + 0x3009,0x2000,0x0006,0x8300,0x290c,0x7300,0x3e10,0x0024, + 0x3300,0x1b8c,0xb010,0x0024,0x0000,0x0024,0x2802,0xf915, + 0x0000,0x0024,0x3473,0x0024,0x3423,0x0024,0x3009,0x1240, + 0x4080,0x138c,0x0000,0x0804,0x2802,0xdc95,0x6402,0x0024, + 0x0006,0xd312,0x0006,0xd310,0x0006,0x8191,0x3010,0x984c, + 0x30f0,0xc024,0x0000,0x0021,0xf2d6,0x07c6,0x290a,0xf5c0, + 0x4682,0x0400,0x6894,0x0840,0xb886,0x0bc1,0xbcd6,0x0024, + 0x3a10,0x8024,0x3af0,0xc024,0x36f3,0x4024,0x36f3,0xd80e, + 0x36f4,0x9813,0x36f4,0x1811,0x36f1,0x9807,0x36f1,0x1805, + 0x36f0,0x9803,0x36f0,0x1801,0x3405,0x9014,0x36f3,0x0024, + 0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817,0x3613,0x0024, + 0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814,0x3615,0x0024, + 0x0000,0x800a,0x3e10,0x3801,0x0020,0x0001,0x3e14,0x3811, + 0x0030,0x0050,0x0030,0x0251,0x3e04,0xb813,0x3000,0x0024, + 0xc012,0x0024,0x0019,0x9300,0x3800,0x4024,0x2903,0x7100, + 0x3900,0x0024,0x2903,0x8500,0x0000,0x0300,0xb882,0x0024, + 0x2914,0xbec0,0x0006,0x8010,0x0000,0x1540,0x0007,0x8190, + 0x2900,0xa200,0x3800,0x0024,0x4080,0x0024,0x0000,0x0024, + 0x2803,0x0cd5,0x0000,0x0024,0x0006,0x8012,0x3200,0x0024, + 0x4080,0x0024,0x0030,0x0010,0x2803,0x0cd5,0x0000,0x0201, + 0x3000,0x0024,0xb010,0x0024,0x0000,0x0024,0x2803,0x0cd5, + 0x0000,0x0024,0x2900,0xa200,0x0000,0x0024,0x4080,0x0024, + 0x0006,0x8010,0x2803,0x0cd5,0x3000,0x0024,0x4080,0x0024, + 0x0000,0x0201,0x2803,0x0905,0x0030,0x0010,0x0030,0x0050, + 0xf292,0x0000,0xb012,0x0024,0x3800,0x4024,0x0030,0x0010, + 0x0000,0x0201,0x3000,0x0024,0xb010,0x0024,0x0000,0x0024, + 0x2900,0xbed5,0x0003,0x1688,0x0006,0x8011,0x3100,0x0024, + 0x4080,0x0024,0x0000,0x0024,0x2803,0x14c5,0x0000,0x0024, + 0x0007,0x8a52,0x3200,0x0024,0x4080,0x0024,0x0000,0x0024, + 0x2803,0x14c9,0x0000,0x0024,0xf292,0x0800,0x6012,0x0024, + 0x0000,0x0000,0x2803,0x1485,0x0000,0x0024,0x3200,0x0024, + 0x4090,0x0024,0xb880,0x2800,0x3900,0x0024,0x3100,0x0024, + 0x4080,0x0024,0x0000,0x0024,0x2902,0x1305,0x0003,0x0dc8, + 0x2900,0xbec0,0x0000,0x0024,0x0000,0x0010,0x0006,0x9f51, + 0x0006,0x9f92,0x0030,0x0493,0x0000,0x0201,0x6890,0xa410, + 0x3b00,0x2810,0x0006,0x8a10,0x3009,0x0000,0x6012,0x0024, + 0x0006,0x9fd0,0x2803,0x1a08,0xb880,0x0024,0x6890,0x0024, + 0x3009,0x2000,0x36f4,0x9813,0x36f4,0x1811,0x36f0,0x1801, + 0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000, + 0x36f2,0x9817,0x3613,0x0024,0x3e10,0xb810,0x3e11,0x3805, + 0x3e02,0x0024,0x0030,0x0010,0xce9a,0x0002,0x0000,0x0200, + 0x2903,0x2540,0xb024,0x0024,0xc020,0x0024,0x0000,0x0200, + 0x2803,0x1e05,0x6e9a,0x0002,0x4182,0x0024,0x0000,0x0400, + 0x2803,0x23c5,0xae1a,0x0024,0x6104,0x984c,0x0000,0x0024, + 0x2903,0x5409,0x0003,0x2388,0x6103,0xe4e5,0x2903,0x5400, + 0x408a,0x188c,0x2903,0x5400,0x408a,0x4141,0x4583,0x6465, + 0x2803,0x23c0,0xceca,0x1bcc,0xc408,0x0024,0xf2e2,0x1bc8, + 0x36f1,0x1805,0x2000,0x0011,0x36f0,0x9810,0x2000,0x0000, + 0xdc92,0x0024,0x0006,0x8a17,0x3613,0x1c00,0x6093,0xe1e3, + 0x0000,0x03c3,0x0006,0x9f95,0xb132,0x9415,0x3500,0xfc01, + 0x2803,0x3355,0xa306,0x0024,0x0006,0xd397,0x003f,0xc001, + 0x3500,0x184c,0xb011,0xe4e5,0xb182,0x1c04,0xd400,0x184c, + 0x0000,0x0205,0xac52,0x3802,0x0006,0xd3c2,0x4212,0x0024, + 0xf400,0x4057,0xb182,0x1c04,0xd400,0x0024,0xac52,0x1404, + 0xd142,0x0024,0x0000,0x3fc4,0xb142,0x0024,0x4122,0x1bc2, + 0xf400,0x4057,0x3700,0x4024,0xd101,0x6465,0x0006,0xd397, + 0x3f00,0x3814,0x0025,0xffd4,0x0006,0xd317,0x3710,0x160c, + 0x0006,0x9f94,0x37f0,0x73d5,0x6c92,0x3808,0x3f10,0x0024, + 0x3ff0,0x4024,0x3009,0x1040,0x3009,0x13c1,0x6010,0x0024, + 0x0000,0x0024,0x2903,0x8dc5,0x0003,0x2f48,0x2803,0x3194, + 0x0006,0x0001,0x4010,0x0024,0x0005,0xf601,0x6010,0x0024, + 0x0000,0x0040,0x2803,0x3314,0x0030,0x0497,0x3f00,0x0024, + 0x36f2,0x1814,0x4330,0x9803,0x2000,0x0000,0x8880,0x1bc1, + 0x3613,0x0024,0x3e22,0xb806,0x3e05,0xb814,0x3615,0x0024, + 0x0000,0x800a,0x3e10,0x3801,0x3e10,0xb803,0x3e11,0x7807, + 0x6848,0x930c,0x3411,0x780d,0x459a,0x10c0,0x0000,0x0201, + 0x6012,0x384e,0x0000,0x0241,0x2803,0x3a95,0x6012,0x380f, + 0x2403,0x39c5,0x0000,0x0024,0x3000,0x0001,0x3101,0x8407, + 0x6cfe,0x0024,0xac42,0x0024,0xaf4e,0x2040,0x3911,0x8024, + 0x2803,0x4640,0x0000,0x0024,0x0000,0x0281,0x2803,0x3dd5, + 0x6012,0x4455,0x2403,0x3d05,0x0000,0x0024,0x3000,0x0001, + 0x3101,0x8407,0x4cf2,0x0024,0xac42,0x0024,0xaf4e,0x2040, + 0x3911,0x8024,0x2803,0x4640,0x0000,0x0024,0x0000,0x0024, + 0x2803,0x4215,0x4080,0x0024,0x3110,0x0401,0xf20f,0x0203, + 0x2403,0x4145,0x8dd6,0x0024,0x4dce,0x0024,0xf1fe,0x0024, + 0xaf4e,0x0024,0x6dc6,0x2046,0xf1df,0x0203,0xaf4f,0x1011, + 0xf20e,0x07cc,0x8dd6,0x2486,0x2803,0x4640,0x0000,0x0024, + 0x0000,0x0024,0x2803,0x4495,0x0000,0x0024,0x0fff,0xffd1, + 0x2403,0x43c5,0x3010,0x0001,0xac4f,0x0801,0x3821,0x8024, + 0x2803,0x4640,0x0000,0x0024,0x0fff,0xffd1,0x2403,0x4605, + 0x3010,0x0001,0x3501,0x9407,0xac47,0x0801,0xaf4e,0x2082, + 0x3d11,0x8024,0x36f3,0xc024,0x36f3,0x980d,0x36f1,0x5807, + 0x36f0,0x9803,0x36f0,0x1801,0x3405,0x9014,0x36e3,0x0024, + 0x2000,0x0000,0x36f2,0x9806,0x0006,0x9f97,0x3e00,0x5c15, + 0x0006,0xd397,0x003f,0xc001,0x3500,0x3840,0xb011,0xe4e5, + 0xb182,0x1c04,0xd400,0x184c,0x0000,0x0205,0xac52,0x3802, + 0x0006,0xd3c2,0x4212,0x0024,0xb182,0x4057,0x3701,0x0024, + 0xd400,0x0024,0xac52,0x1404,0xd142,0x0024,0x0000,0x3fc4, + 0xb142,0x0024,0x4122,0x1bc2,0xf400,0x4057,0x3700,0x4024, + 0xd101,0x6465,0x0006,0xd397,0x3f00,0x3814,0x0025,0xffd4, + 0x0006,0xd317,0x3710,0x160c,0x0006,0x9f94,0x37f0,0x73d5, + 0x6c92,0x0024,0x3f10,0x1040,0x3ff0,0x53c1,0x6010,0x0024, + 0x0000,0x0024,0x2803,0x5214,0x0006,0x0001,0x4010,0x0024, + 0x0005,0xf601,0x6010,0x9bd4,0x0000,0x0040,0x2803,0x5394, + 0x0030,0x0497,0x3f00,0x0024,0x2000,0x0000,0x36f0,0x5800, + 0x3e10,0xb812,0x3e11,0xb810,0x3e12,0x0024,0x0006,0x9f92, + 0x0025,0xffd0,0x3e04,0x4bd1,0x3181,0xf847,0xb68c,0x4440, + 0x3009,0x0802,0x6024,0x3806,0x0006,0x8a10,0x2903,0x8dc5, + 0x0003,0x5608,0x0000,0x0800,0x6101,0x1602,0xaf2e,0x0024, + 0x4214,0x1be3,0xaf0e,0x1811,0x0fff,0xfc00,0xb200,0x9bc7, + 0x0000,0x03c0,0x2803,0x5a45,0xb204,0xa002,0x2903,0x4880, + 0x3613,0x2002,0x4680,0x1bc8,0x36f1,0x9810,0x2000,0x0000, + 0x36f0,0x9812,0x0000,0x0400,0x6102,0x0024,0x3e11,0x3805, + 0x2803,0x5e49,0x3e02,0x0024,0x2903,0x5400,0x408a,0x188c, + 0x2903,0x5400,0x408a,0x4141,0x4582,0x1bc8,0x2000,0x0000, + 0x36f1,0x1805,0x2903,0x5400,0x4102,0x184c,0xb182,0x1bc8, + 0x2000,0x0000,0x36f1,0x1805,0x3613,0x0024,0x3e12,0xb815, + 0x3e11,0xb807,0x3e13,0xf80e,0x3e03,0x4024,0x680c,0x0024, + 0x0000,0x0024,0x2803,0x6398,0x409c,0x0024,0x2403,0x6346, + 0x0000,0x000a,0x3111,0xc024,0xfe4e,0x0007,0x47be,0x0024, + 0xf6fe,0x0024,0x3811,0xc024,0x36f3,0x4024,0x36f3,0xd80e, + 0x36f1,0x9807,0x2000,0x0000,0x36f2,0x9815,0x3613,0x0024, + 0x3e12,0xb815,0x3e11,0xb807,0x3e13,0xf80e,0x3e03,0x4024, + 0x680c,0x0024,0x0000,0x0024,0x2803,0x68d8,0x409c,0x0024, + 0x2403,0x6886,0x0000,0x000a,0x3111,0xc024,0xfe4e,0x8007, + 0x47be,0x0024,0xf6fe,0x0024,0x3009,0x2047,0x36f3,0x4024, + 0x36f3,0xd80e,0x36f1,0x9807,0x2000,0x0000,0x36f2,0x9815, + 0x2a03,0x6a4e,0x3e12,0xb817,0x3e10,0x3802,0x0000,0x800a, + 0x0006,0x9f97,0x3009,0x1fc2,0x3e04,0x5c00,0x6020,0xb810, + 0x0030,0x0451,0x2803,0x6d14,0x0006,0x0002,0x4020,0x0024, + 0x0005,0xfb02,0x6024,0x0024,0x0025,0xffd0,0x2803,0x6f51, + 0x3100,0x1c11,0xb284,0x0024,0x0030,0x0490,0x3800,0x8024, + 0x0025,0xffd0,0x3980,0x1810,0x36f4,0x7c11,0x36f0,0x1802, + 0x0030,0x0717,0x3602,0x8024,0x2100,0x0000,0x3f05,0xdbd7, + 0x0003,0x6a17,0x3613,0x0024,0x3e00,0x3801,0xf400,0x55c0, + 0x0000,0x0897,0xf400,0x57c0,0x0000,0x0024,0x2000,0x0000, + 0x36f0,0x1801,0x0006,0xd397,0x2000,0x0000,0x3700,0x0024, + 0xb183,0xe1e3,0x0000,0x0203,0xac32,0x40d5,0xd122,0x0024, + 0x0000,0x3fc3,0xb132,0x0024,0x0006,0xd3c3,0x4316,0x0024, + 0xf400,0x40d5,0x3500,0x5803,0x2000,0x0000,0xd010,0x1bc1, + 0x3613,0x0024,0x3e22,0xb815,0x3e05,0xb814,0x3615,0x0024, + 0x0000,0x800a,0x3e10,0x3801,0x3e10,0xb803,0xb884,0xb805, + 0xb888,0x3844,0x3e11,0xb80d,0x3e03,0xf80e,0x0000,0x03ce, + 0xf400,0x4083,0x2403,0x7f8e,0xf400,0x4105,0x0000,0x0206, + 0xa562,0x0024,0x455a,0x0024,0x0020,0x0006,0xd312,0x0024, + 0xb16c,0x0024,0x0020,0x0006,0x2803,0x7e05,0xd342,0x0024, + 0x0000,0x01c6,0xd342,0x0024,0xd56a,0x0024,0x0020,0x0006, + 0x4448,0x0024,0xb16c,0x0024,0x0020,0x0146,0x2803,0x7f85, + 0x0000,0x0024,0xd468,0x0024,0x4336,0x0024,0x0000,0x4000, + 0x0006,0xd3c1,0x0006,0x9306,0x4122,0x0024,0x462c,0x4055, + 0x4092,0x3404,0xb512,0x4195,0x6294,0x3401,0x6200,0x0024, + 0x0000,0x03ce,0x2803,0x7a11,0xb888,0x0024,0x36f3,0xd80e, + 0x36f1,0x980d,0x36f1,0x1805,0x36f0,0x9803,0x36f0,0x1801, + 0x3405,0x9014,0x36e3,0x0024,0x2000,0x0000,0x36f2,0x9815, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3615,0x0024,0x0000,0x800a,0x3e10,0x3801,0xb880,0xb810, + 0x0006,0x9fd0,0x3e10,0x8001,0x4182,0x3811,0x0006,0xd311, + 0x2803,0x88c5,0x0006,0x8a10,0x0000,0x0200,0xbc82,0xa000, + 0x3910,0x0024,0x2903,0x7700,0x39f0,0x4024,0x0006,0x9f90, + 0x0006,0x9f51,0x3009,0x0000,0x3009,0x0401,0x6014,0x0024, + 0x0000,0x0024,0x2903,0x8dc5,0x0003,0x89c8,0x36f4,0x4024, + 0x36f0,0x9810,0x36f0,0x1801,0x3405,0x9014,0x36f3,0x0024, + 0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817,0x3613,0x0024, + 0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814,0x290a,0xd900, + 0x3605,0x0024,0x2910,0x0180,0x3613,0x0024,0x3405,0x9014, + 0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817, + 0x3613,0x0024,0x3e12,0xb817,0x3e12,0x3815,0x3e05,0xb814, + 0x3615,0x0024,0x0000,0x800a,0x3e10,0xb803,0x0006,0x0002, + 0x3e11,0x3805,0x3e11,0xb807,0x3e14,0x3811,0x0006,0x9f90, + 0x3e04,0xb813,0x3009,0x0012,0x3213,0x0024,0xf400,0x4480, + 0x6026,0x0024,0x0000,0x0024,0x2803,0x9655,0x0000,0x0024, + 0x0000,0x0012,0xf400,0x4480,0x0006,0x9f50,0x3009,0x0002, + 0x6026,0x0024,0x0000,0x0024,0x2903,0x8dc5,0x0003,0x9648, + 0x0006,0x9f93,0x3201,0x0c11,0xb58a,0x0406,0x0006,0x8a11, + 0x468e,0x8400,0xb68c,0x9813,0xcfee,0x1bd2,0x0000,0x0804, + 0xaf0e,0x9811,0x4f86,0x1bd0,0x0000,0x0021,0x6418,0x9807, + 0x6848,0x1bc6,0xad46,0x9805,0xf400,0x4080,0x36f1,0x0024, + 0x36f0,0x9803,0x3405,0x9014,0x36f3,0x0024,0x36f2,0x1815, + 0x2000,0x0000,0x36f2,0x9817,0x3613,0x0024,0x3e12,0xb817, + 0x3e12,0x3815,0x3e05,0xb814,0x3615,0x0024,0x0000,0x800a, + 0x3e10,0x3801,0x3e10,0xb803,0x3e11,0x3805,0x2803,0xa480, + 0x3e04,0x3811,0x0000,0x0401,0x2903,0x5400,0x3613,0x0024, + 0x0000,0x0080,0xb882,0x130c,0xf400,0x4510,0x3010,0x910c, + 0x30f0,0xc024,0x6dc2,0x0024,0x3810,0x0024,0x38f0,0x4024, + 0x0000,0x0201,0x3100,0x0024,0xb010,0x0024,0x0000,0x0024, + 0x2803,0xa7d5,0x0000,0x0024,0x6894,0x130c,0xb886,0x1040, + 0x3430,0x4024,0x6dca,0x0024,0x0030,0x0011,0x2803,0xa051, + 0x0000,0x0024,0xbcd2,0x0024,0x0000,0x0201,0x2803,0xa7c5, + 0x0000,0x0024,0x2903,0x5400,0x3613,0x0024,0x36f4,0x1811, + 0x36f1,0x1805,0x36f0,0x9803,0x36f0,0x1801,0x3405,0x9014, + 0x36f3,0x0024,0x36f2,0x1815,0x2000,0x0000,0x36f2,0x9817, + 0x3613,0x0024,0x3e12,0xb815,0x0000,0x800a,0x3e14,0x7813, + 0x3e10,0xb803,0x3e11,0x3805,0x3e11,0xb807,0x3e13,0xf80e, + 0x6812,0x0024,0x3e03,0x7810,0x0fff,0xffd3,0x0000,0x0091, + 0xbd86,0x9850,0x3e10,0x3804,0x3e00,0x7812,0xbe8a,0x8bcc, + 0x409e,0x8086,0x2403,0xaf07,0xfe49,0x2821,0x526a,0x8801, + 0x5c87,0x280e,0x4eba,0x9812,0x4286,0x40e1,0xb284,0x1bc1, + 0x4de6,0x0024,0xad17,0x2627,0x4fde,0x9804,0x4498,0x1bc0, + 0x0000,0x0024,0x2803,0xad15,0x3a11,0xa807,0x36f3,0x4024, + 0x36f3,0xd80e,0x36f1,0x9807,0x36f1,0x1805,0x36f0,0x9803, + 0x36f4,0x5813,0x2000,0x0000,0x36f2,0x9815,0x3613,0x0024, + 0x3e12,0xb815,0x0000,0x800a,0x3e10,0xb803,0x3e11,0x3805, + 0x3e11,0xb807,0x3e13,0xf80e,0x6812,0x0024,0x3e03,0x7810, + 0x3009,0x1850,0x3e10,0x3804,0x3e10,0x7812,0x32f3,0x0024, + 0xbd86,0x0024,0x4091,0xe2e3,0x3009,0x0046,0x2403,0xba80, + 0x3009,0x0047,0x32f0,0x0801,0xfe1f,0x6465,0x5e8a,0x0024, + 0x44ba,0x0024,0xfee2,0x0024,0x5d8a,0x1800,0x4482,0x4160, + 0x48ba,0x8046,0x4dc6,0x1822,0x4de6,0x8047,0x36f3,0x0024, + 0x36f0,0x5812,0xad17,0x2627,0x4fde,0x9804,0x4498,0x1bc0, + 0x0000,0x0024,0x2803,0xb615,0x3a11,0xa807,0x36f3,0x4024, + 0x36f3,0xd80e,0x36f1,0x9807,0x36f1,0x1805,0x36f0,0x9803, + 0x2000,0x0000,0x36f2,0x9815,0xb386,0x40d7,0x4284,0x184c, + 0x0000,0x05c0,0x2803,0xc015,0xf5d8,0x3804,0x0000,0x0984, + 0x6400,0xb84a,0x3e13,0xf80d,0xa204,0x380e,0x0000,0x800a, + 0x0000,0x00ce,0x2403,0xc34e,0xffa4,0x0024,0x48b6,0x0024, + 0x0000,0x0024,0x2803,0xc344,0x4000,0x40c2,0x4224,0x0024, + 0x6090,0x0024,0xffa4,0x0024,0x0fff,0xfe83,0xfe86,0x1bce, + 0x36f3,0xd80d,0x48b6,0x0024,0x0fff,0xff03,0xa230,0x45c3, + 0x2000,0x0000,0x36f1,0x180a,0x4080,0x184c,0x3e13,0x780f, + 0x2803,0xc785,0x4090,0xb80e,0x2403,0xc700,0x3e04,0x0440, + 0x3810,0x0440,0x3604,0x0024,0x3009,0x1bce,0x3603,0x5bcf, + 0x2000,0x0000,0x0000,0x0024, + 0x0007,0x0001, /*copy 1*/ + 0x802e, + 0x0006,0x0002, /*copy 2*/ + 0x2801,0x6780, + 0x0007,0x0001, /*copy 1*/ + 0x8030, + 0x0006,0x0002, /*copy 2*/ + 0x2800,0x1b40, + 0x0007,0x0001, /*copy 1*/ + 0x8028, + 0x0006,0x0002, /*copy 2*/ + 0x2a00,0x3f8e, + 0x0007,0x0001, /*copy 1*/ + 0x8032, + 0x0006,0x0002, /*copy 2*/ + 0x2800,0x5c00, + 0x0007,0x0001, /*copy 1*/ + 0x3580, + 0x0006, 0x8038, 0x0000, /*Rle(56)*/ + 0x0007,0x0001, /*copy 1*/ + 0xfab3, + 0x0006,0x01a4, /*copy 420*/ + 0x0001,0x0001,0x0001,0x0001,0x0000,0xffff,0xfffe,0xfffb, + 0xfff9,0xfff5,0xfff2,0xffed,0xffe8,0xffe3,0xffde,0xffd8, + 0xffd3,0xffce,0xffca,0xffc7,0xffc4,0xffc4,0xffc5,0xffc7, + 0xffcc,0xffd3,0xffdc,0xffe6,0xfff3,0x0001,0x0010,0x001f, + 0x002f,0x003f,0x004e,0x005b,0x0066,0x006f,0x0074,0x0075, + 0x0072,0x006b,0x005f,0x004f,0x003c,0x0024,0x0009,0xffed, + 0xffcf,0xffb0,0xff93,0xff77,0xff5f,0xff4c,0xff3d,0xff35, + 0xff34,0xff3b,0xff4a,0xff60,0xff7e,0xffa2,0xffcd,0xfffc, + 0x002e,0x0061,0x0094,0x00c4,0x00f0,0x0114,0x0131,0x0144, + 0x014b,0x0146,0x0134,0x0116,0x00eb,0x00b5,0x0075,0x002c, + 0xffde,0xff8e,0xff3d,0xfeef,0xfea8,0xfe6a,0xfe39,0xfe16, + 0xfe05,0xfe06,0xfe1b,0xfe43,0xfe7f,0xfecd,0xff2a,0xff95, + 0x0009,0x0082,0x00fd,0x0173,0x01e1,0x0242,0x0292,0x02cc, + 0x02ec,0x02f2,0x02da,0x02a5,0x0253,0x01e7,0x0162,0x00c9, + 0x0021,0xff70,0xfebc,0xfe0c,0xfd68,0xfcd5,0xfc5b,0xfc00, + 0xfbc9,0xfbb8,0xfbd2,0xfc16,0xfc85,0xfd1b,0xfdd6,0xfeae, + 0xff9e,0x009c,0x01a0,0x02a1,0x0392,0x046c,0x0523,0x05b0, + 0x060a,0x062c,0x0613,0x05bb,0x0526,0x0456,0x0351,0x021f, + 0x00c9,0xff5a,0xfde1,0xfc6a,0xfb05,0xf9c0,0xf8aa,0xf7d0, + 0xf73d,0xf6fa,0xf70f,0xf77e,0xf848,0xf96b,0xfadf,0xfc9a, + 0xfe8f,0x00ad,0x02e3,0x051a,0x073f,0x0939,0x0af4,0x0c5a, + 0x0d59,0x0de1,0x0de5,0x0d5c,0x0c44,0x0a9e,0x0870,0x05c7, + 0x02b4,0xff4e,0xfbaf,0xf7f8,0xf449,0xf0c7,0xed98,0xeae0, + 0xe8c4,0xe765,0xe6e3,0xe756,0xe8d2,0xeb67,0xef19,0xf3e9, + 0xf9cd,0x00b5,0x088a,0x112b,0x1a72,0x2435,0x2e42,0x3866, + 0x426b,0x4c1b,0x553e,0x5da2,0x6516,0x6b6f,0x7087,0x7441, + 0x7686,0x774a,0x7686,0x7441,0x7087,0x6b6f,0x6516,0x5da2, + 0x553e,0x4c1b,0x426b,0x3866,0x2e42,0x2435,0x1a72,0x112b, + 0x088a,0x00b5,0xf9cd,0xf3e9,0xef19,0xeb67,0xe8d2,0xe756, + 0xe6e3,0xe765,0xe8c4,0xeae0,0xed98,0xf0c7,0xf449,0xf7f8, + 0xfbaf,0xff4e,0x02b4,0x05c7,0x0870,0x0a9e,0x0c44,0x0d5c, + 0x0de5,0x0de1,0x0d59,0x0c5a,0x0af4,0x0939,0x073f,0x051a, + 0x02e3,0x00ad,0xfe8f,0xfc9a,0xfadf,0xf96b,0xf848,0xf77e, + 0xf70f,0xf6fa,0xf73d,0xf7d0,0xf8aa,0xf9c0,0xfb05,0xfc6a, + 0xfde1,0xff5a,0x00c9,0x021f,0x0351,0x0456,0x0526,0x05bb, + 0x0613,0x062c,0x060a,0x05b0,0x0523,0x046c,0x0392,0x02a1, + 0x01a0,0x009c,0xff9e,0xfeae,0xfdd6,0xfd1b,0xfc85,0xfc16, + 0xfbd2,0xfbb8,0xfbc9,0xfc00,0xfc5b,0xfcd5,0xfd68,0xfe0c, + 0xfebc,0xff70,0x0021,0x00c9,0x0162,0x01e7,0x0253,0x02a5, + 0x02da,0x02f2,0x02ec,0x02cc,0x0292,0x0242,0x01e1,0x0173, + 0x00fd,0x0082,0x0009,0xff95,0xff2a,0xfecd,0xfe7f,0xfe43, + 0xfe1b,0xfe06,0xfe05,0xfe16,0xfe39,0xfe6a,0xfea8,0xfeef, + 0xff3d,0xff8e,0xffde,0x002c,0x0075,0x00b5,0x00eb,0x0116, + 0x0134,0x0146,0x014b,0x0144,0x0131,0x0114,0x00f0,0x00c4, + 0x0094,0x0061,0x002e,0xfffc,0xffcd,0xffa2,0xff7e,0xff60, + 0xff4a,0xff3b,0xff34,0xff35,0xff3d,0xff4c,0xff5f,0xff77, + 0xff93,0xffb0,0xffcf,0xffed,0x0009,0x0024,0x003c,0x004f, + 0x005f,0x006b,0x0072,0x0075,0x0074,0x006f,0x0066,0x005b, + 0x004e,0x003f,0x002f,0x001f,0x0010,0x0001,0xfff3,0xffe6, + 0xffdc,0xffd3,0xffcc,0xffc7,0xffc5,0xffc4,0xffc4,0xffc7, + 0xffca,0xffce,0xffd3,0xffd8,0xffde,0xffe3,0xffe8,0xffed, + 0xfff2,0xfff5,0xfff9,0xfffb,0xfffe,0xffff,0x0000,0x0001, + 0x0001,0x0001,0x0001,0x0000, + 0x0007,0x0001, /*copy 1*/ + 0x180b, + 0x0006,0x000d, /*copy 13*/ + 0x000f,0x0010,0x001c,0xfab3,0x3580,0x804b,0xa04b,0x0001, + 0x0000,0x3580,0x01a4,0x069e,0x06bc, + 0x0006, 0x8006, 0x0704, /*Rle(6)*/ + 0x0006,0x0027, /*copy 39*/ + 0x06d9,0x06d9,0x06d9,0x06d9,0x06d9,0x0908,0x08ec,0x08f0, + 0x08f4,0x08f8,0x08fc,0x0900,0x0904,0x0937,0x093b,0x093e, + 0x093e,0x093e,0x093e,0x0946,0x0959,0x0a24,0x0990,0x0995, + 0x099b,0x09a1,0x09a6,0x09ab,0x09b0,0x09b5,0x09ba,0x09bf, + 0x09c4,0x09c9,0x09e2,0x0a01,0x0a20,0x5a82,0x5a82, + 0x0006, 0x8006, 0x0000, /*Rle(6)*/ + 0x0006,0x0018, /*copy 24*/ + 0x6fb8,0xc180,0xc180,0x6fb8,0x0000,0x0000,0x0000,0x0000, + 0x5a82,0x5a82,0x6fb8,0xc180,0xc180,0x6fb8,0x0000,0x0000, + 0x5a82,0x5a82,0x5a82,0x5a82,0x6fb8,0xc180,0xc180,0x6fb8, + 0x0007,0x0001, /*copy 1*/ + 0x5800, + 0x0006,0x0001, /*copy 1*/ + 0x0001, + 0x0006, 0x8007, 0x0000, /*Rle(7)*/ + 0x0006,0x0018, /*copy 24*/ + 0x0002,0x0000,0xffff,0xffff,0x0000,0x0000,0x0000,0x0000, + 0x0003,0x0000,0xfffd,0xffff,0x0001,0x0000,0x0000,0x0000, + 0x0004,0x0000,0xfffa,0xffff,0x0004,0x0000,0xffff,0xffff, + 0x000a,0x0001, /*copy 1*/ + 0x0300, + }; + + + + + + + + + + + + + + + + diff --git a/STM32F1/libraries/TFT_ILI9163C b/STM32F1/libraries/TFT_ILI9163C new file mode 160000 index 0000000..bbc39bb --- /dev/null +++ b/STM32F1/libraries/TFT_ILI9163C @@ -0,0 +1 @@ +Subproject commit bbc39bbb79edf95996da5733dadf293a0d5984ea diff --git a/STM32F1/platform.txt b/STM32F1/platform.txt index f9979c9..e9c518c 100644 --- a/STM32F1/platform.txt +++ b/STM32F1/platform.txt @@ -3,7 +3,7 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification -name=STM32 Boards (stm32duino) +name=STM32 Boards (STM32duino.com) version=0.1.2 compiler.warning_flags=-w -DDEBUG_LEVEL=DEBUG_NONE diff --git a/STM32F1/variants/generic_stm32f103c/board.cpp b/STM32F1/variants/generic_stm32f103c/board.cpp index d19d965..95ea65b 100644 --- a/STM32F1/variants/generic_stm32f103c/board.cpp +++ b/STM32F1/variants/generic_stm32f103c/board.cpp @@ -56,13 +56,13 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOA, TIMER2, ADC1, 0, 1, 0}, /* PA0 */ - {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* PA1 */ + {GPIOA, TIMER2, ADC1, 1, 2, 1}, /* PA1 */ {GPIOA, TIMER2, ADC1, 2, 3, 2}, /* PA2 */ {GPIOA, TIMER2, ADC1, 3, 4, 3}, /* PA3 */ - {GPIOA, NULL, ADC1, 4, 0, 4}, /* PA4 */ - {GPIOA, NULL, ADC1, 5, 0, 5}, /* PA5 */ - {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* PA6 */ - {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* PA7 */ + {GPIOA, NULL, ADC1, 4, 0, 4}, /* PA4 */ + {GPIOA, NULL, ADC1, 5, 0, 5}, /* PA5 */ + {GPIOA, TIMER3, ADC1, 6, 1, 6}, /* PA6 */ + {GPIOA, TIMER3, ADC1, 7, 2, 7}, /* PA7 */ {GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* PA8 */ {GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* PA9 */ {GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* PA10 */ @@ -81,7 +81,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = { {GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* PB6 */ {GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* PB7 */ {GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* PB8 */ - {GPIOB, NULL, NULL, 9, 0, ADCx}, /* PB9 */ + {GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* PB9 */ {GPIOB, NULL, NULL, 10, 0, ADCx}, /* PB10 */ {GPIOB, NULL, NULL, 11, 0, ADCx}, /* PB11 */ {GPIOB, NULL, NULL, 12, 0, ADCx}, /* PB12 */ diff --git a/STM32F4/cores/maple/Client.h b/STM32F4/cores/maple/Client.h new file mode 100644 index 0000000..b8e5d93 --- /dev/null +++ b/STM32F4/cores/maple/Client.h @@ -0,0 +1,45 @@ +/* + Client.h - Base class that provides Client + 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 client_h +#define client_h +#include "Print.h" +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) =0; + virtual int connect(const char *host, uint16_t port) =0; + virtual size_t write(uint8_t) =0; + virtual size_t write(const uint8_t *buf, size_t size) =0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/STM32F4/cores/maple/IPAddress.cpp b/STM32F4/cores/maple/IPAddress.cpp new file mode 100644 index 0000000..a8ed095 --- /dev/null +++ b/STM32F4/cores/maple/IPAddress.cpp @@ -0,0 +1,89 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + 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 +*/ + +#include +#include +#include + +IPAddress::IPAddress() +{ + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) +{ + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +IPAddress& IPAddress::operator=(const uint8_t *address) +{ + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) +{ + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const +{ + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +size_t IPAddress::printTo(Print& p) const +{ + size_t n = 0; + for (int i =0; i < 3; i++) + { + n += p.print(_address.bytes[i], DEC); + n += p.print('.'); + } + n += p.print(_address.bytes[3], DEC); + return n; +} + +char *IPAddress::toCharArray() +{ + static char szRet[20]; + String str = String(_address.bytes[0]); + str += "."; + str += String(_address.bytes[1]); + str += "."; + str += String(_address.bytes[2]); + str += "."; + str += String(_address.bytes[3]); + str.toCharArray(szRet, 20); + return szRet; +} + diff --git a/STM32F4/cores/maple/IPAddress.h b/STM32F4/cores/maple/IPAddress.h new file mode 100644 index 0000000..eb8a7c0 --- /dev/null +++ b/STM32F4/cores/maple/IPAddress.h @@ -0,0 +1,76 @@ +/* + IPAddress.h - Base class that provides IPAddress + 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 IPAddress_h +#define IPAddress_h + +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +class IPAddress : public Printable { +private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { return _address.bytes; }; + +public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const { return _address.dword; }; + bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; }; + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { return _address.bytes[index]; }; + uint8_t& operator[](int index) { return _address.bytes[index]; }; + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + virtual size_t printTo(Print& p) const; + char * toCharArray(); + + friend class EthernetClass; + friend class UDP; + friend class Client; + friend class Server; + friend class DhcpClass; + friend class DNSClient; +}; + +const IPAddress INADDR_NONE(0,0,0,0); + + +#endif diff --git a/STM32F4/cores/maple/Printable.h b/STM32F4/cores/maple/Printable.h new file mode 100644 index 0000000..2a1b2e9 --- /dev/null +++ b/STM32F4/cores/maple/Printable.h @@ -0,0 +1,40 @@ +/* + 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 + +#include + +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 size_t printTo(Print& p) const = 0; +}; + +#endif + diff --git a/STM32F4/cores/maple/Server.h b/STM32F4/cores/maple/Server.h new file mode 100644 index 0000000..69e3e39 --- /dev/null +++ b/STM32F4/cores/maple/Server.h @@ -0,0 +1,30 @@ +/* + Server.h - Base class that provides Server + 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 server_h +#define server_h + +#include "Print.h" + +class Server : public Print { +public: + virtual void begin() =0; +}; + +#endif diff --git a/STM32F4/cores/maple/Udp.h b/STM32F4/cores/maple/Udp.h new file mode 100644 index 0000000..dc5644b --- /dev/null +++ b/STM32F4/cores/maple/Udp.h @@ -0,0 +1,88 @@ +/* + * Udp.cpp: Library to send/receive UDP packets. + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence. + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef udp_h +#define udp_h + +#include +#include + +class UDP : public Stream { + +public: + virtual uint8_t begin(uint16_t) =0; // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + virtual void stop() =0; // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + virtual int beginPacket(IPAddress ip, uint16_t port) =0; + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + virtual int beginPacket(const char *host, uint16_t port) =0; + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + virtual int endPacket() =0; + // Write a single byte into the packet + virtual size_t write(uint8_t) =0; + // Write size bytes from buffer into the packet + virtual size_t write(const uint8_t *buffer, size_t size) =0; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + virtual int parsePacket() =0; + // Number of bytes remaining in the current packet + virtual int available() =0; + // Read a single byte from the current packet + virtual int read() =0; + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + virtual int read(unsigned char* buffer, size_t len) =0; + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + virtual int read(char* buffer, size_t len) =0; + // Return the next byte from the current packet without moving on to the next byte + virtual int peek() =0; + virtual void flush() =0; // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + virtual IPAddress remoteIP() =0; + // Return the port of the host who sent the current incoming packet + virtual uint16_t remotePort() =0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/STM32F4/cores/maple/avr/dtostrf.c b/STM32F4/cores/maple/avr/dtostrf.c new file mode 100644 index 0000000..7f90154 --- /dev/null +++ b/STM32F4/cores/maple/avr/dtostrf.c @@ -0,0 +1,29 @@ +/* + dtostrf - Emulation for dtostrf function from avr-libc + Copyright (c) 2013 Arduino. All rights reserved. + Written by Cristian Maglie + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +char *dtostrf (double val, signed char width, unsigned char prec, char *sout) { + char fmt[20]; + sprintf(fmt, "%%%d.%df", width, prec); + sprintf(sout, fmt, val); + return sout; +} + diff --git a/STM32F4/cores/maple/avr/dtostrf.h b/STM32F4/cores/maple/avr/dtostrf.h new file mode 100644 index 0000000..0bf9f57 --- /dev/null +++ b/STM32F4/cores/maple/avr/dtostrf.h @@ -0,0 +1,29 @@ +/* + dtostrf - Emulation for dtostrf function from avr-libc + Copyright (c) 2013 Arduino. All rights reserved. + Written by Cristian Maglie + + 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 +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +char *dtostrf (double val, signed char width, unsigned char prec, char *sout); + +#ifdef __cplusplus +} +#endif diff --git a/STM32F4/cores/maple/avr/pgmspace.h b/STM32F4/cores/maple/avr/pgmspace.h new file mode 100644 index 0000000..9b344c9 --- /dev/null +++ b/STM32F4/cores/maple/avr/pgmspace.h @@ -0,0 +1,44 @@ +#ifndef __PGMSPACE_H_ +#define __PGMSPACE_H_ 1 + +#include + +#define PROGMEM +#define PGM_P const char * +#define PSTR(str) (str) + +#define _SFR_BYTE(n) (n) + +typedef void prog_void; +typedef char prog_char; +typedef unsigned char prog_uchar; +typedef int8_t prog_int8_t; +typedef uint8_t prog_uint8_t; +typedef int16_t prog_int16_t; +typedef uint16_t prog_uint16_t; +typedef int32_t prog_int32_t; +typedef uint32_t prog_uint32_t; + +#define memcpy_P(dest, src, num) memcpy((dest), (src), (num)) +#define strcpy_P(dest, src) strcpy((dest), (src)) +#define strcat_P(dest, src) strcat((dest), (src)) +#define strcmp_P(a, b) strcmp((a), (b)) +#define strstr_P(a, b) strstr((a), (b)) +#define strlen_P(a) strlen((a)) +#define sprintf_P(s, f, ...) sprintf((s), (f), __VA_ARGS__) + +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#define pgm_read_float(addr) (*(const float *)(addr)) + +#define pgm_read_byte_near(addr) pgm_read_byte(addr) +#define pgm_read_word_near(addr) pgm_read_word(addr) +#define pgm_read_dword_near(addr) pgm_read_dword(addr) +#define pgm_read_float_near(addr) pgm_read_float(addr) +#define pgm_read_byte_far(addr) pgm_read_byte(addr) +#define pgm_read_word_far(addr) pgm_read_word(addr) +#define pgm_read_dword_far(addr) pgm_read_dword(addr) +#define pgm_read_float_far(addr) pgm_read_float(addr) + +#endif diff --git a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp index a156770..f6fdcbb 100644 --- a/STM32F4/cores/maple/libmaple/HardwareSerial.cpp +++ b/STM32F4/cores/maple/libmaple/HardwareSerial.cpp @@ -94,8 +94,14 @@ void HardwareSerial::begin(uint32 baud) { const stm32_pin_info *rxi = &PIN_MAP[rx_pin]; #ifdef STM32F2 // int af = 7<<8; - gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 7); - gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 7); + if (usart_device == UART4 || usart_device == UART5) { + gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 8); + gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 8); + } + else { + gpio_set_af_mode(txi->gpio_device, txi->gpio_bit, 7); + gpio_set_af_mode(rxi->gpio_device, rxi->gpio_bit, 7); + } gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_AF_OUTPUT_PP | GPIO_PUPD_INPUT_PU | 0x700)); gpio_set_mode(rxi->gpio_device, rxi->gpio_bit, (gpio_pin_mode)(GPIO_MODE_AF | GPIO_PUPD_INPUT_PU | 0x700)); //gpio_set_mode(txi->gpio_device, txi->gpio_bit, (gpio_pin_mode)(GPIO_PUPD_INPUT_PU)); diff --git a/STM32F4/cores/maple/libmaple/gpioF2.c b/STM32F4/cores/maple/libmaple/gpioF2.c index 47f3754..b04c7e9 100644 --- a/STM32F4/cores/maple/libmaple/gpioF2.c +++ b/STM32F4/cores/maple/libmaple/gpioF2.c @@ -126,6 +126,18 @@ void gpio_init_all(void) { gpio_init(GPIOF); gpio_init(GPIOG); #endif + +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + // PA8 Output the Master Clock MCO1 + gpio_set_af_mode(GPIOA, 8, 0); + gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); + // PB4 as alternate MISO Input + gpio_set_af_mode(GPIOB, 4, 5); + // PA5 as alternate SCK Output + gpio_set_af_mode(GPIOA, 5, 5); + // PA7 as alternate MOSI Output + gpio_set_af_mode(GPIOA, 7, 5); +#endif } /** diff --git a/STM32F4/cores/maple/libmaple/libmaple_types.h b/STM32F4/cores/maple/libmaple/libmaple_types.h index 17bcfb1..332ded1 100644 --- a/STM32F4/cores/maple/libmaple/libmaple_types.h +++ b/STM32F4/cores/maple/libmaple/libmaple_types.h @@ -48,6 +48,8 @@ typedef void (*voidFuncPtr)(void); #define __io volatile #define __attr_flash __attribute__((section (".USER_FLASH"))) +#define __always_inline inline __attribute__((always_inline)) + #ifndef NULL #define NULL 0 #endif diff --git a/STM32F4/cores/maple/libmaple/rccF2.c b/STM32F4/cores/maple/libmaple/rccF2.c index 40816c4..5b3b8ec 100644 --- a/STM32F4/cores/maple/libmaple/rccF2.c +++ b/STM32F4/cores/maple/libmaple/rccF2.c @@ -34,6 +34,7 @@ #include "libmaple.h" #include "flash.h" +#include "gpio.h" #include "rcc.h" #include "bitband.h" @@ -167,6 +168,18 @@ typedef struct typedef uint32 uint32_t; +void InitMCO1() +{ + rcc_reg_map *RCC = RCC_BASE; + // Turn MCO1 Master Clock Output mode + RCC->CFGR &= RCC_CFGR_MCO1_RESET_MASK; + RCC->CFGR |= RCC_CFGR_MCO1Source_HSE | RCC_CFGR_MCO1Div_1; + // PA8 Output the Master Clock MCO1 + gpio_set_af_mode(GPIOA, 8, 0); + gpio_set_mode(GPIOA, 8, GPIO_MODE_AF | GPIO_OTYPE_PP | GPIO_OSPEED_100MHZ); +} + + void SetupClock72MHz() { uint32_t SystemCoreClock = 72000000; @@ -377,6 +390,10 @@ void SetupClock168MHz() uint32 StartUpCounter = 0, HSEStatus = 0; rcc_reg_map *RCC = RCC_BASE; +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + InitMCO1(); +#endif + /* Enable HSE */ RCC->CR |= ((uint32_t)RCC_CR_HSEON); @@ -447,20 +464,19 @@ void SetupClock168MHz() } - void rcc_clk_init(rcc_sysclk_src sysclk_src, rcc_pllsrc pll_src, rcc_pll_multiplier pll_mul) { //SetupClock72MHz(); #if STM32_TICKS_PER_US == 168 - SetupClock168MHz(); + SetupClock168MHz(); #endif #if STM32_TICKS_PER_US == 120 - SetupClock120MHz(); + SetupClock120MHz(); #endif #if STM32_TICKS_PER_US == 72 - SetupClock72MHz(); + SetupClock72MHz(); #endif } diff --git a/STM32F4/cores/maple/libmaple/rccF2.h b/STM32F4/cores/maple/libmaple/rccF2.h index 9982e55..597870b 100644 --- a/STM32F4/cores/maple/libmaple/rccF2.h +++ b/STM32F4/cores/maple/libmaple/rccF2.h @@ -125,6 +125,17 @@ typedef struct #define RCC_CFGR_SW_PLL 0x2 #define RCC_CFGR_SW_HSE 0x1 +#define RCC_CFGR_MCO1Source_HSI ((uint32_t)0x00000000) +#define RCC_CFGR_MCO1Source_LSE ((uint32_t)0x00200000) +#define RCC_CFGR_MCO1Source_HSE ((uint32_t)0x00400000) +#define RCC_CFGR_MCO1Source_PLLCLK ((uint32_t)0x00600000) +#define RCC_CFGR_MCO1Div_1 ((uint32_t)0x00000000) +#define RCC_CFGR_MCO1Div_2 ((uint32_t)0x04000000) +#define RCC_CFGR_MCO1Div_3 ((uint32_t)0x05000000) +#define RCC_CFGR_MCO1Div_4 ((uint32_t)0x06000000) +#define RCC_CFGR_MCO1Div_5 ((uint32_t)0x07000000) +#define RCC_CFGR_MCO1_RESET_MASK ((uint32_t)0xF89FFFFF) + /* Clock interrupt register */ #define RCC_CIR_CSSC_BIT 23 diff --git a/STM32F4/libraries/arduino_uip/Dhcp.cpp b/STM32F4/libraries/arduino_uip/Dhcp.cpp new file mode 100644 index 0000000..c15fe83 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/Dhcp.cpp @@ -0,0 +1,478 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#include +#include +#include "Dhcp.h" +#include "Arduino.h" +#include "utility/util.h" + +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout) +{ + _dhcpLeaseTime=0; + _dhcpT1=0; + _dhcpT2=0; + _lastCheck=0; + _timeout = timeout; + _responseTimeout = responseTimeout; + + // zero out _dhcpMacAddr + memset(_dhcpMacAddr, 0, 6); + reset_DHCP_lease(); + + memcpy((void*)_dhcpMacAddr, (void*)mac, 6); + _dhcp_state = STATE_DHCP_START; + return request_DHCP_lease(); +} + +void DhcpClass::reset_DHCP_lease(){ + // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp + memset(_dhcpLocalIp, 0, 20); +} + +//return:0 on error, 1 if request is sent and response is received +int DhcpClass::request_DHCP_lease(){ + + uint8_t messageType = 0; + + + + // Pick an initial transaction ID + _dhcpTransactionId = random(1UL, 2000UL); + _dhcpInitialTransactionId = _dhcpTransactionId; + + _dhcpUdpSocket.stop(); + if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0) + { + // Couldn't get a socket + return 0; + } + + presend_DHCP(); + + int result = 0; + + unsigned long startTime = millis(); + + while(_dhcp_state != STATE_DHCP_LEASED) + { + if(_dhcp_state == STATE_DHCP_START) + { + _dhcpTransactionId++; + + send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_DISCOVER; + } + else if(_dhcp_state == STATE_DHCP_REREQUEST){ + _dhcpTransactionId++; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + else if(_dhcp_state == STATE_DHCP_DISCOVER) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_OFFER) + { + // We'll use the transaction ID that the offer came with, + // rather than the one we were up to + _dhcpTransactionId = respId; + send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000)); + _dhcp_state = STATE_DHCP_REQUEST; + } + } + else if(_dhcp_state == STATE_DHCP_REQUEST) + { + uint32_t respId; + messageType = parseDHCPResponse(_responseTimeout, respId); + if(messageType == DHCP_ACK) + { + _dhcp_state = STATE_DHCP_LEASED; + result = 1; + //use default lease time if we didn't get it + if(_dhcpLeaseTime == 0){ + _dhcpLeaseTime = DEFAULT_LEASE; + } + //calculate T1 & T2 if we didn't get it + if(_dhcpT1 == 0){ + //T1 should be 50% of _dhcpLeaseTime + _dhcpT1 = _dhcpLeaseTime >> 1; + } + if(_dhcpT2 == 0){ + //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime + _dhcpT2 = _dhcpT1 << 1; + } + _renewInSec = _dhcpT1; + _rebindInSec = _dhcpT2; + } + else if(messageType == DHCP_NAK) + _dhcp_state = STATE_DHCP_START; + } + + if(messageType == 255) + { + messageType = 0; + _dhcp_state = STATE_DHCP_START; + } + + if(result != 1 && ((millis() - startTime) > _timeout)) + break; + } + + // We're done with the socket now + _dhcpUdpSocket.stop(); + _dhcpTransactionId++; + + return result; +} + +void DhcpClass::presend_DHCP() +{ +} + +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed) +{ + uint8_t buffer[32]; + memset(buffer, 0, 32); + IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address + + if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT)) + { + // FIXME Need to return errors + return; + } + + buffer[0] = DHCP_BOOTREQUEST; // op + buffer[1] = DHCP_HTYPE10MB; // htype + buffer[2] = DHCP_HLENETHERNET; // hlen + buffer[3] = DHCP_HOPS; // hops + + // xid + unsigned long xid = htonl(_dhcpTransactionId); + memcpy(buffer + 4, &(xid), 4); + + // 8, 9 - seconds elapsed + buffer[8] = ((secondsElapsed & 0xff00) >> 8); + buffer[9] = (secondsElapsed & 0x00ff); + + // flags + unsigned short flags = htons(DHCP_FLAGSBROADCAST); + memcpy(buffer + 10, &(flags), 2); + + // ciaddr: already zeroed + // yiaddr: already zeroed + // siaddr: already zeroed + // giaddr: already zeroed + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 28); + + memset(buffer, 0, 32); // clear local buffer + + memcpy(buffer, _dhcpMacAddr, 6); // chaddr + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 16); + + memset(buffer, 0, 32); // clear local buffer + + // leave zeroed out for sname && file + // put in W5100 transmit buffer x 6 (192 bytes) + + for(int i = 0; i < 6; i++) { + _dhcpUdpSocket.write(buffer, 32); + } + + // OPT - Magic Cookie + buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF); + buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF); + buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF); + buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF); + + // OPT - message type + buffer[4] = dhcpMessageType; + buffer[5] = 0x01; + buffer[6] = messageType; //DHCP_REQUEST; + + // OPT - client identifier + buffer[7] = dhcpClientIdentifier; + buffer[8] = 0x07; + buffer[9] = 0x01; + memcpy(buffer + 10, _dhcpMacAddr, 6); + + // OPT - host name + buffer[16] = hostName; + buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address + strcpy((char*)&(buffer[18]), HOST_NAME); + + printByte((char*)&(buffer[24]), _dhcpMacAddr[3]); + printByte((char*)&(buffer[26]), _dhcpMacAddr[4]); + printByte((char*)&(buffer[28]), _dhcpMacAddr[5]); + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 30); + + if(messageType == DHCP_REQUEST) + { + buffer[0] = dhcpRequestedIPaddr; + buffer[1] = 0x04; + buffer[2] = _dhcpLocalIp[0]; + buffer[3] = _dhcpLocalIp[1]; + buffer[4] = _dhcpLocalIp[2]; + buffer[5] = _dhcpLocalIp[3]; + + buffer[6] = dhcpServerIdentifier; + buffer[7] = 0x04; + buffer[8] = _dhcpDhcpServerIp[0]; + buffer[9] = _dhcpDhcpServerIp[1]; + buffer[10] = _dhcpDhcpServerIp[2]; + buffer[11] = _dhcpDhcpServerIp[3]; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 12); + } + + buffer[0] = dhcpParamRequest; + buffer[1] = 0x06; + buffer[2] = subnetMask; + buffer[3] = routersOnSubnet; + buffer[4] = dns; + buffer[5] = domainName; + buffer[6] = dhcpT1value; + buffer[7] = dhcpT2value; + buffer[8] = endOption; + + //put data in W5100 transmit buffer + _dhcpUdpSocket.write(buffer, 9); + + _dhcpUdpSocket.endPacket(); +} + +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId) +{ + uint8_t type = 0; + uint8_t opt_len = 0; + + unsigned long startTime = millis(); + + while(_dhcpUdpSocket.parsePacket() <= 0) + { + if((millis() - startTime) > responseTimeout) + { + return 255; + } + delay(50); + } + // start reading in the packet + RIP_MSG_FIXED fixedMsg; + _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED)); + + if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT) + { + transactionId = ntohl(fixedMsg.xid); + if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId)) + { + // Need to read the rest of the packet here regardless + _dhcpUdpSocket.flush(); + return 0; + } + + memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4); + + // Skip to the option part + // Doing this a byte at a time so we don't have to put a big buffer + // on the stack (as we don't have lots of memory lying around) + for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++) + { + _dhcpUdpSocket.read(); // we don't care about the returned byte + } + + while (_dhcpUdpSocket.available() > 0) + { + switch (_dhcpUdpSocket.read()) + { + case endOption : + break; + + case padOption : + break; + + case dhcpMessageType : + opt_len = _dhcpUdpSocket.read(); + type = _dhcpUdpSocket.read(); + break; + + case subnetMask : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpSubnetMask, 4); + break; + + case routersOnSubnet : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpGatewayIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dns : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read(_dhcpDnsServerIp, 4); + for (int i = 0; i < opt_len-4; i++) + { + _dhcpUdpSocket.read(); + } + break; + + case dhcpServerIdentifier : + opt_len = _dhcpUdpSocket.read(); + if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || + IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() ) + { + _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp)); + } + else + { + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + } + break; + + case dhcpT1value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1)); + _dhcpT1 = ntohl(_dhcpT1); + break; + + case dhcpT2value : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2)); + _dhcpT2 = ntohl(_dhcpT2); + break; + + case dhcpIPaddrLeaseTime : + opt_len = _dhcpUdpSocket.read(); + _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime)); + _dhcpLeaseTime = ntohl(_dhcpLeaseTime); + _renewInSec = _dhcpLeaseTime; + break; + + default : + opt_len = _dhcpUdpSocket.read(); + // Skip over the rest of this option + while (opt_len--) + { + _dhcpUdpSocket.read(); + } + break; + } + } + } + + // Need to skip to end of the packet regardless here + _dhcpUdpSocket.flush(); + + return type; +} + + +/* + returns: + 0/DHCP_CHECK_NONE: nothing happened + 1/DHCP_CHECK_RENEW_FAIL: renew failed + 2/DHCP_CHECK_RENEW_OK: renew success + 3/DHCP_CHECK_REBIND_FAIL: rebind fail + 4/DHCP_CHECK_REBIND_OK: rebind success +*/ +int DhcpClass::checkLease(){ + //this uses a signed / unsigned trick to deal with millis overflow + unsigned long now = millis(); + signed long snow = (long)now; + int rc=DHCP_CHECK_NONE; + if (_lastCheck != 0){ + signed long factor; + //calc how many ms past the timeout we are + factor = snow - (long)_secTimeout; + //if on or passed the timeout, reduce the counters + if ( factor >= 0 ){ + //next timeout should be now plus 1000 ms minus parts of second in factor + _secTimeout = snow + 1000 - factor % 1000; + //how many seconds late are we, minimum 1 + factor = factor / 1000 +1; + + //reduce the counters by that mouch + //if we can assume that the cycle time (factor) is fairly constant + //and if the remainder is less than cycle time * 2 + //do it early instead of late + if(_renewInSec < factor*2 ) + _renewInSec = 0; + else + _renewInSec -= factor; + + if(_rebindInSec < factor*2 ) + _rebindInSec = 0; + else + _rebindInSec -= factor; + } + + //if we have a lease but should renew, do it + if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){ + _dhcp_state = STATE_DHCP_REREQUEST; + rc = 1 + request_DHCP_lease(); + } + + //if we have a lease or is renewing but should bind, do it + if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){ + //this should basically restart completely + _dhcp_state = STATE_DHCP_START; + reset_DHCP_lease(); + rc = 3 + request_DHCP_lease(); + } + } + else{ + _secTimeout = snow + 1000; + } + + _lastCheck = now; + return rc; +} + +IPAddress DhcpClass::getLocalIp() +{ + return IPAddress(_dhcpLocalIp); +} + +IPAddress DhcpClass::getSubnetMask() +{ + return IPAddress(_dhcpSubnetMask); +} + +IPAddress DhcpClass::getGatewayIp() +{ + return IPAddress(_dhcpGatewayIp); +} + +IPAddress DhcpClass::getDhcpServerIp() +{ + return IPAddress(_dhcpDhcpServerIp); +} + +IPAddress DhcpClass::getDnsServerIp() +{ + return IPAddress(_dhcpDnsServerIp); +} + +void DhcpClass::printByte(char * buf, uint8_t n ) { + char *str = &buf[1]; + buf[0]='0'; + do { + unsigned long m = n; + n /= 16; + char c = m - 16 * n; + *str-- = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); +} diff --git a/STM32F4/libraries/arduino_uip/Dhcp.h b/STM32F4/libraries/arduino_uip/Dhcp.h new file mode 100644 index 0000000..cc3cd35 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/Dhcp.h @@ -0,0 +1,178 @@ +// DHCP Library v0.3 - April 25, 2009 +// Author: Jordan Terrell - blog.jordanterrell.com + +#ifndef Dhcp_h +#define Dhcp_h + +#include "UIPUdp.h" + +/* DHCP state machine. */ +#define STATE_DHCP_START 0 +#define STATE_DHCP_DISCOVER 1 +#define STATE_DHCP_REQUEST 2 +#define STATE_DHCP_LEASED 3 +#define STATE_DHCP_REREQUEST 4 +#define STATE_DHCP_RELEASE 5 + +#define DHCP_FLAGSBROADCAST 0x8000 + +/* UDP port numbers for DHCP */ +#define DHCP_SERVER_PORT 67 /* from server to client */ +#define DHCP_CLIENT_PORT 68 /* from client to server */ + +/* DHCP message OP code */ +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +/* DHCP message type */ +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE10MB 1 +#define DHCP_HTYPE100MB 2 + +#define DHCP_HLENETHERNET 6 +#define DHCP_HOPS 0 +#define DHCP_SECS 0 + +#define MAGIC_COOKIE 0x63825363 +#define MAX_DHCP_OPT 16 + +#define HOST_NAME "ENC28J" +#define DEFAULT_LEASE (900) //default lease time in seconds + +#define DHCP_CHECK_NONE (0) +#define DHCP_CHECK_RENEW_FAIL (1) +#define DHCP_CHECK_RENEW_OK (2) +#define DHCP_CHECK_REBIND_FAIL (3) +#define DHCP_CHECK_REBIND_OK (4) + +enum +{ + padOption = 0, + subnetMask = 1, + timerOffset = 2, + routersOnSubnet = 3, + /* timeServer = 4, + nameServer = 5,*/ + dns = 6, + /*logServer = 7, + cookieServer = 8, + lprServer = 9, + impressServer = 10, + resourceLocationServer = 11,*/ + hostName = 12, + /*bootFileSize = 13, + meritDumpFile = 14,*/ + domainName = 15, + /*swapServer = 16, + rootPath = 17, + extentionsPath = 18, + IPforwarding = 19, + nonLocalSourceRouting = 20, + policyFilter = 21, + maxDgramReasmSize = 22, + defaultIPTTL = 23, + pathMTUagingTimeout = 24, + pathMTUplateauTable = 25, + ifMTU = 26, + allSubnetsLocal = 27, + broadcastAddr = 28, + performMaskDiscovery = 29, + maskSupplier = 30, + performRouterDiscovery = 31, + routerSolicitationAddr = 32, + staticRoute = 33, + trailerEncapsulation = 34, + arpCacheTimeout = 35, + ethernetEncapsulation = 36, + tcpDefaultTTL = 37, + tcpKeepaliveInterval = 38, + tcpKeepaliveGarbage = 39, + nisDomainName = 40, + nisServers = 41, + ntpServers = 42, + vendorSpecificInfo = 43, + netBIOSnameServer = 44, + netBIOSdgramDistServer = 45, + netBIOSnodeType = 46, + netBIOSscope = 47, + xFontServer = 48, + xDisplayManager = 49,*/ + dhcpRequestedIPaddr = 50, + dhcpIPaddrLeaseTime = 51, + /*dhcpOptionOverload = 52,*/ + dhcpMessageType = 53, + dhcpServerIdentifier = 54, + dhcpParamRequest = 55, + /*dhcpMsg = 56, + dhcpMaxMsgSize = 57,*/ + dhcpT1value = 58, + dhcpT2value = 59, + /*dhcpClassIdentifier = 60,*/ + dhcpClientIdentifier = 61, + endOption = 255 +}; + +typedef struct _RIP_MSG_FIXED +{ + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + uint32_t xid; + uint16_t secs; + uint16_t flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[6]; +}RIP_MSG_FIXED; + +class DhcpClass { +private: + uint32_t _dhcpInitialTransactionId; + uint32_t _dhcpTransactionId; + uint8_t _dhcpMacAddr[6]; + uint8_t _dhcpLocalIp[4]; + uint8_t _dhcpSubnetMask[4]; + uint8_t _dhcpGatewayIp[4]; + uint8_t _dhcpDhcpServerIp[4]; + uint8_t _dhcpDnsServerIp[4]; + uint32_t _dhcpLeaseTime; + uint32_t _dhcpT1, _dhcpT2; + signed long _renewInSec; + signed long _rebindInSec; + signed long _lastCheck; + unsigned long _timeout; + unsigned long _responseTimeout; + unsigned long _secTimeout; + uint8_t _dhcp_state; + UIPUDP _dhcpUdpSocket; + + int request_DHCP_lease(); + void reset_DHCP_lease(); + void presend_DHCP(); + void send_DHCP_MESSAGE(uint8_t, uint16_t); + void printByte(char *, uint8_t); + + uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId); +public: + IPAddress getLocalIp(); + IPAddress getSubnetMask(); + IPAddress getGatewayIp(); + IPAddress getDhcpServerIp(); + IPAddress getDnsServerIp(); + + int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000); + int checkLease(); +}; + +#endif diff --git a/STM32F4/libraries/arduino_uip/Dns.cpp b/STM32F4/libraries/arduino_uip/Dns.cpp new file mode 100644 index 0000000..d6d31bd --- /dev/null +++ b/STM32F4/libraries/arduino_uip/Dns.cpp @@ -0,0 +1,421 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "Udp.h" +#include "utility/util.h" + +#include "Dns.h" +#include +//#include +#include "Arduino.h" + + +#define SOCKET_NONE 255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE 8 +#define DNS_HEADER_SIZE 12 +#define TTL_SIZE 4 +#define QUERY_FLAG (0) +#define RESPONSE_FLAG (1<<15) +#define QUERY_RESPONSE_MASK (1<<15) +#define OPCODE_STANDARD_QUERY (0) +#define OPCODE_INVERSE_QUERY (1<<11) +#define OPCODE_STATUS_REQUEST (2<<11) +#define OPCODE_MASK (15<<11) +#define AUTHORITATIVE_FLAG (1<<10) +#define TRUNCATION_FLAG (1<<9) +#define RECURSION_DESIRED_FLAG (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR (0) +#define RESP_FORMAT_ERROR (1) +#define RESP_SERVER_FAILURE (2) +#define RESP_NAME_ERROR (3) +#define RESP_NOT_IMPLEMENTED (4) +#define RESP_REFUSED (5) +#define RESP_MASK (15) +#define TYPE_A (0x0001) +#define CLASS_IN (0x0001) +#define LABEL_COMPRESSION_MASK (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT 53 + +// Possible return codes from ProcessResponse +#define SUCCESS 1 +#define TIMED_OUT -1 +#define INVALID_SERVER -2 +#define TRUNCATED -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ + iDNSServer = aDNSServer; + iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ + // See if we've been given a valid IP address + const char* p =aIPAddrString; + while (*p && ( (*p == '.') || ((*p >= '0') && (*p <= '9')) )) + { + p++; + } + + if (*p == '\0') + { + // It's looking promising, we haven't found any invalid characters + p = aIPAddrString; + int segment =0; + int segmentValue =0; + while (*p && (segment < 4)) + { + if (*p == '.') + { + // We've reached the end of a segment + if (segmentValue > 255) + { + // You can't have IP address segments that don't fit in a byte + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + segment++; + segmentValue = 0; + } + } + else + { + // Next digit + segmentValue = (segmentValue*10)+(*p - '0'); + } + p++; + } + // We've reached the end of address, but there'll still be the last + // segment to deal with + if ((segmentValue > 255) || (segment > 3)) + { + // You can't have IP address segments that don't fit in a byte, + // or more than four segments + return 0; + } + else + { + aResult[segment] = (byte)segmentValue; + return 1; + } + } + else + { + return 0; + } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ + int ret =0; + + // See if it's a numeric IP address + if (inet_aton(aHostname, aResult)) + { + // It is, our work here is done + return 1; + } + + // Check we've got a valid DNS server to use + if (iDNSServer == INADDR_NONE) + { + return INVALID_SERVER; + } + + // Find a socket to use + if (iUdp.begin(1024+(millis() & 0xF)) == 1) + { + // Try up to three times + int retries = 0; +// while ((retries < 3) && (ret <= 0)) + { + // Send DNS request + ret = iUdp.beginPacket(iDNSServer, DNS_PORT); + if (ret != 0) + { + // Now output the request data + ret = BuildRequest(aHostname); + if (ret != 0) + { + // And finally send the request + ret = iUdp.endPacket(); + if (ret != 0) + { + // Now wait for a response + int wait_retries = 0; + ret = TIMED_OUT; + while ((wait_retries < 3) && (ret == TIMED_OUT)) + { + ret = ProcessResponse(5000, aResult); + wait_retries++; + } + } + } + } + retries++; + } + + // We're done with the socket now + iUdp.stop(); + } + + return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ + // Build header + // 1 1 1 1 1 1 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ID | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // |QR| Opcode |AA|TC|RD|RA| Z | RCODE | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | QDCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ANCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | NSCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // | ARCOUNT | + // +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ + // As we only support one request at a time at present, we can simplify + // some of this header + iRequestId = millis(); // generate a random ID + uint16_t twoByteBuffer; + + // FIXME We should also check that there's enough space available to write to, rather + // FIXME than assume there's enough space (as the code does at present) + iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + + twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(1); // One question record + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = 0; // Zero answer records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // and zero additional records + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + // Build question + const char* start =aName; + const char* end =start; + uint8_t len; + // Run through the name being requested + while (*end) + { + // Find out how long this section of the name is + end = start; + while (*end && (*end != '.') ) + { + end++; + } + + if (end-start > 0) + { + // Write out the size of this section + len = end-start; + iUdp.write(&len, sizeof(len)); + // And then write out the section + iUdp.write((uint8_t*)start, end-start); + } + start = end+1; + } + + // We've got to the end of the question name, so + // terminate it with a zero-length section + len = 0; + iUdp.write(&len, sizeof(len)); + // Finally the type and class of question + twoByteBuffer = htons(TYPE_A); + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + + twoByteBuffer = htons(CLASS_IN); // Internet class of question + iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + // Success! Everything buffered okay + return 1; +} + + +uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) +{ + uint32_t startTime = millis(); + + // Wait for a response packet + while(iUdp.parsePacket() <= 0) + { + if((millis() - startTime) > aTimeout) + return TIMED_OUT; + delay(50); + } + + // We've had a reply! + // Read the UDP header + uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header + // Check that it's a response from the right server and the right port + if ( (iDNSServer != iUdp.remoteIP()) || + (iUdp.remotePort() != DNS_PORT) ) + { + // It's not from who we expected + return INVALID_SERVER; + } + + // Read through the rest of the response + if (iUdp.available() < DNS_HEADER_SIZE) + { + return TRUNCATED; + } + iUdp.read(header, DNS_HEADER_SIZE); + + uint16_t header_flags = htons(*((uint16_t*)&header[2])); + // Check that it's a response to this request + if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || + ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) + { + // Mark the entire packet as read + iUdp.flush(); + return INVALID_RESPONSE; + } + // Check for any errors in the response (or in our request) + // although we don't do anything to get round these + if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) + { + // Mark the entire packet as read + iUdp.flush(); + return -5; //INVALID_RESPONSE; + } + + // And make sure we've got (at least) one answer + uint16_t answerCount = htons(*((uint16_t*)&header[6])); + if (answerCount == 0 ) + { + // Mark the entire packet as read + iUdp.flush(); + return -6; //INVALID_RESPONSE; + } + + // Skip over any questions + for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) + { + // Skip over the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if (len > 0) + { + // Don't need to actually read the data out for the string, just + // advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } while (len != 0); + + // Now jump over the type and class + for (int i =0; i < 4; i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + + // Now we're up to the bit we're interested in, the answer + // There might be more than one answer (although we'll just use the first + // type A answer) and some authority and additional resource records but + // we're going to ignore all of them. + + for (uint16_t i =0; i < answerCount; i++) + { + // Skip the name + uint8_t len; + do + { + iUdp.read(&len, sizeof(len)); + if ((len & LABEL_COMPRESSION_MASK) == 0) + { + // It's just a normal label + if (len > 0) + { + // And it's got a length + // Don't need to actually read the data out for the string, + // just advance ptr to beyond it + while(len--) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + else + { + // This is a pointer to a somewhere else in the message for the + // rest of the name. We don't care about the name, and RFC1035 + // says that a name is either a sequence of labels ended with a + // 0 length octet or a pointer or a sequence of labels ending in + // a pointer. Either way, when we get here we're at the end of + // the name + // Skip over the pointer + iUdp.read(); // we don't care about the returned byte + // And set len so that we drop out of the name loop + len = 0; + } + } while (len != 0); + + // Check the type and class + uint16_t answerType; + uint16_t answerClass; + iUdp.read((uint8_t*)&answerType, sizeof(answerType)); + iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + + // Ignore the Time-To-Live as we don't do any caching + for (int i =0; i < TTL_SIZE; i++) + { + iUdp.read(); // we don't care about the returned byte + } + + // And read out the length of this answer + // Don't need header_flags anymore, so we can reuse it here + iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + + if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) + { + if (htons(header_flags) != 4) + { + // It's a weird size + // Mark the entire packet as read + iUdp.flush(); + return -9;//INVALID_RESPONSE; + } + iUdp.read(aAddress.raw_address(), 4); + return SUCCESS; + } + else + { + // This isn't an answer type we're after, move onto the next one + for (uint16_t i =0; i < htons(header_flags); i++) + { + iUdp.read(); // we don't care about the returned byte + } + } + } + + // Mark the entire packet as read + iUdp.flush(); + + // If we get here then we haven't found an answer + return -10;//INVALID_RESPONSE; +} + diff --git a/STM32F4/libraries/arduino_uip/Dns.h b/STM32F4/libraries/arduino_uip/Dns.h new file mode 100644 index 0000000..4ccb1e1 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for Enc28J60-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#ifndef DNSClient_h +#define DNSClient_h + +#include + +class DNSClient +{ +public: + // ctor + void begin(const IPAddress& aDNSServer); + + /** Convert a numeric IP address string into a four-byte IP address. + @param aIPAddrString IP address to convert + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int inet_aton(const char *aIPAddrString, IPAddress& aResult); + + /** Resolve the given hostname to an IP address. + @param aHostname Name to be resolved + @param aResult IPAddress structure to store the returned IP address + @result 1 if aIPAddrString was successfully converted to an IP address, + else error code + */ + int getHostByName(const char* aHostname, IPAddress& aResult); + +protected: + uint16_t BuildRequest(const char* aName); + uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress); + + IPAddress iDNSServer; + uint16_t iRequestId; + UIPUDP iUdp; +}; + +#endif diff --git a/STM32F4/libraries/arduino_uip/README b/STM32F4/libraries/arduino_uip/README new file mode 100644 index 0000000..321b334 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/README @@ -0,0 +1,227 @@ +This is UIPEthernet version 1.09 + +An plugin-replacement of the stock Arduino Ethernet library for ENC28J60 shields and breakout boards. Full support for persistent (streaming) TCP-connections and UDP (Client and Server each), ARP, ICMP, DHCP and DNS. +Just include 'UIPEthernet.h' instead of 'Ethernet.h' and use all your code written for the stock Arduino Ethernet lib! + +UIPEthernet is written as a wrapper around the mature uIP Stack by Adam Dunkels, which provides the low-level implementation for all supported protocols. To overcome the memory-constrains (a 'regular' uIP-application does all processing in RAM) the ENC28J60 internal memory is used for all stream buffers (in and out). Only 400-600 Bytes of Arduinos RAM are used (depending on the number of concurrently open connections). As of Flash-memory a ATmega368-based Arduino is the minimum requirenment. + +This library is written by Norbert Truchsess + +uIP was written by Adam Dunkels of the Networked Embedded Systems group at the Swedish Institute of Computer Science. + +This library was inspired by the SerialIP implementation by Adam Nielsen , actually I took this code as a starting point, but in the latest versions there are very few lines left. + +Installation +------------ + +To install the libraries, you need to place them into your "libraries" folder. You can find it within your Arduino IDE distribution within the "hardware" folder. + + C:\> cd [path to Arduino distribution]\libraries + C:\> git clone https://github.com/ntruchsess/arduino_uip UIPEthernet + +Be sure to restart the IDE if it was running. + +On a Mac, you will want to create a folder named "libraries" in in the "Documents" -> "Arduino" folder within your home directory. Clone the project there (and restart the IDE, if it was running during this process). + + $ cd ~/Documents/Arduino/libraries + $ git clone https://github.com/ntruchsess/arduino_uip UIPEthernet + +Or you download the zipped version of the library from https://github.com/ntruchsess/arduino_uip/releases, and copy the contained directory UIPEthernet to [path to Arduino distribution]\libraries\UIPEthernet. + +If you are running Arduino-IDE 1.5.x use release-version 1.59 or checkout branch 'Arduino_1.5.x' + +Additional information can be found on the Arduino website: http://www.arduino.cc/en/Hacking/Libraries + +Documentation +------------- + +For more information visit: + + - UIPEthernet Repository on github: + https://github.com/ntruchsess/arduino_uip + + - Arduino Ethernet library description + http://arduino.cc/en/Reference/Ethernet + (Arduino_uip uses the same API as that, just include "UIPEthernet.h", "UIPClient.h", "UIPServer.h" and "UIPUDP.h" instead of the stock "Ethernet.h", "EthernetClient.h", "EthernetServer.h " and "EthernetUDP.h") + + - uIP API reference: + http://www.sics.se/~adam/uip/uip-1.0-refman/ + + - Arduino forums + http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl + + - uIP homepage: + http://www.sics.se/~adam/uip/index.php/Main_Page + +Licenses +------------- + +UIPEthernet.h +UIPEthernet.cpp +UIPServer.h +UIPServer.cpp +UIPClient.h +UIPClient.cpp +UIPUdp.h +UIPUdp.cpp +utility/mempool.h +utility/mempool.cpp + +Copyright (c) 2013 Norbert Truchsess +All rights reserved. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +-------------- + +utility/enc28j60.h + +Author : Pascal Stang (c)2005 +Modified by Norbert Truchsess +Copyright: GPL V2 + +-------------- + +utility/Enc28J60Network.h +utility/Enc28J60Network.cpp + +Copyright (c) 2013 Norbert Truchsess +All rights reserved. + +inspired and based on enc28j60.c file from the AVRlib library by Pascal Stang. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +-------------- + +utility/uip.c +utility/uip_arp.h +utility/uip_arp.c +utility/uip_arch.h +utility/uip.h +utility/uipopt.h + +Copyright (c) 2001-2003, Adam Dunkels , . +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +-------------- + +uip-conf.h +utility/uip-neighbor.h +utility/uip-neighbor.c +utility/uip_timer.h +utility/uip_timer.c +utility/uip_clock.h + +Author Adam Dunkels Adam Dunkels , +Copyright (c) 2004,2006, Swedish Institute of Computer Science. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the Institute nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +-------------- + +Dhcp.h +Dhcp.cpp + +DHCP Library v0.3 - April 25, 2009 +Author: Jordan Terrell - blog.jordanterrell.com +- as included in Arduinos stock Ethernet-library, no special licence mentioned here + +-------------- + +Dns.h +Dns.cpp + +(c) Copyright 2009-2010 MCQN Ltd. +Released under Apache License, version 2.0 + +-------------- + +clock-arch.h +clock-arch.c + +Copyright (c) 2010 Adam Nielsen +All rights reserved. + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/STM32F4/libraries/arduino_uip/UIPClient.cpp b/STM32F4/libraries/arduino_uip/UIPClient.cpp new file mode 100644 index 0000000..a1c0540 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPClient.cpp @@ -0,0 +1,586 @@ +/* + UIPClient.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +extern "C" +{ +#import "utility/uip-conf.h" +#import "utility/uip.h" +#import "utility/uip_arp.h" +#import "string.h" +} +#include "UIPEthernet.h" +#include "UIPClient.h" +#include "Dns.h" + +#ifdef UIPETHERNET_DEBUG_CLIENT +#include "HardwareSerial.h" +#endif + +#define Serial SerialUSB + + +#define UIP_TCP_PHYH_LEN UIP_LLH_LEN+UIP_IPTCPH_LEN + +uip_userdata_t UIPClient::all_data[UIP_CONNS]; + +UIPClient::UIPClient() : + data(NULL) +{ +} + +UIPClient::UIPClient(uip_userdata_t* conn_data) : + data(conn_data) +{ +} + +int +UIPClient::connect(IPAddress ip, uint16_t port) +{ + stop(); + uip_ipaddr_t ipaddr; + uip_ip_addr(ipaddr, ip); + struct uip_conn* conn = uip_connect(&ipaddr, htons(port)); + if (conn) + { +#if UIP_CONNECT_TIMEOUT > 0 + int32_t timeout = millis() + 1000 * UIP_CONNECT_TIMEOUT; +#endif + while((conn->tcpstateflags & UIP_TS_MASK) != UIP_CLOSED) + { + UIPEthernetClass::tick(); + if ((conn->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) + { + data = (uip_userdata_t*) conn->appstate; +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("connected, state: ")); + Serial.print(data->state); + Serial.print(F(", first packet in: ")); + Serial.println(data->packets_in[0]); +#endif + return 1; + } +#if UIP_CONNECT_TIMEOUT > 0 + if (((int32_t)(millis() - timeout)) > 0) + { + conn->tcpstateflags = UIP_CLOSED; + break; + } +#endif + } + } + return 0; +} + +int +UIPClient::connect(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; +#if UIP_UDP + DNSClient dns; + IPAddress remote_addr; + + dns.begin(UIPEthernetClass::_dnsServerAddress); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return connect(remote_addr, port); + } +#endif + return ret; +} + +void +UIPClient::stop() +{ + if (data && data->state) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("before stop(), with data")); + _dumpAllData(); +#endif + _flushBlocks(&data->packets_in[0]); + if (data->state & UIP_CLIENT_REMOTECLOSED) + { + data->state = 0; + } + else + { + data->state |= UIP_CLIENT_CLOSE; + } +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("after stop()")); + _dumpAllData(); +#endif + } +#ifdef UIPETHERNET_DEBUG_CLIENT + else + { + Serial.println(F("stop(), data: NULL")); + } +#endif + data = NULL; + UIPEthernetClass::tick(); +} + +uint8_t +UIPClient::connected() +{ + return (data && (data->packets_in[0] != NOBLOCK || (data->state & UIP_CLIENT_CONNECTED))) ? 1 : 0; +} + +bool +UIPClient::operator==(const UIPClient& rhs) +{ + return data && rhs.data && (data == rhs.data); +} + +UIPClient::operator bool() +{ + UIPEthernetClass::tick(); + return data && (!(data->state & UIP_CLIENT_REMOTECLOSED) || data->packets_in[0] != NOBLOCK); +} + +size_t +UIPClient::write(uint8_t c) +{ + return _write(data, &c, 1); +} + +size_t +UIPClient::write(const uint8_t *buf, size_t size) +{ + return _write(data, buf, size); +} + +size_t +UIPClient::_write(uip_userdata_t* u, const uint8_t *buf, size_t size) +{ + int remain = size; + uint16_t written; +#if UIP_ATTEMPTS_ON_WRITE > 0 + uint16_t attempts = UIP_ATTEMPTS_ON_WRITE; +#endif + repeat: + UIPEthernetClass::tick(); + if (u && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + { + uint8_t p = _currentBlock(&u->packets_out[0]); + if (u->packets_out[p] == NOBLOCK) + { +newpacket: + u->packets_out[p] = Enc28J60Network::allocBlock(UIP_SOCKET_DATALEN); + if (u->packets_out[p] == NOBLOCK) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if ((--attempts)>0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + u->out_pos = 0; + } +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient.write: writePacket(")); + Serial.print(u->packets_out[p]); + Serial.print(F(") pos: ")); + Serial.print(u->out_pos); + Serial.print(F(", buf[")); + Serial.print(size-remain); + Serial.print(F("-")); + Serial.print(remain); + Serial.print(F("]: '")); + Serial.write((uint8_t*)buf+size-remain,remain); + Serial.println(F("'")); +#endif + written = Enc28J60Network::writePacket(u->packets_out[p],u->out_pos,(uint8_t*)buf+size-remain,remain); + remain -= written; + u->out_pos+=written; + if (remain > 0) + { + if (p == UIP_SOCKET_NUMPACKETS-1) + { +#if UIP_ATTEMPTS_ON_WRITE > 0 + if ((--attempts)>0) +#endif +#if UIP_ATTEMPTS_ON_WRITE != 0 + goto repeat; +#endif + goto ready; + } + p++; + goto newpacket; + } +ready: +#if UIP_CLIENT_TIMER >= 0 + u->timer = millis()+UIP_CLIENT_TIMER; +#endif + return size-remain; + } + return -1; +} + +int +UIPClient::available() +{ + if (*this) + return _available(data); + return 0; +} + +int +UIPClient::_available(uip_userdata_t *u) +{ + int len = 0; + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + len += Enc28J60Network::blockSize(u->packets_in[i]); + } + return len; +} + +int +UIPClient::read(uint8_t *buf, size_t size) +{ + if (*this) + { + uint16_t remain = size; + if (data->packets_in[0] == NOBLOCK) + return 0; + uint16_t read; + do + { + read = Enc28J60Network::readPacket(data->packets_in[0],0,buf+size-remain,remain); + if (read == Enc28J60Network::blockSize(data->packets_in[0])) + { + remain -= read; + _eatBlock(&data->packets_in[0]); + if (uip_stopped(&uip_conns[data->state & UIP_CLIENT_SOCKETS]) && !(data->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + data->state |= UIP_CLIENT_RESTART; + if (data->packets_in[0] == NOBLOCK) + { + if (data->state & UIP_CLIENT_REMOTECLOSED) + { + data->state = 0; + data = NULL; + } + return size-remain; + } + } + else + { + Enc28J60Network::resizeBlock(data->packets_in[0],read); + break; + } + } + while(remain > 0); + return size; + } + return -1; +} + +int +UIPClient::read() +{ + uint8_t c; + if (read(&c,1) < 0) + return -1; + return c; +} + +int +UIPClient::peek() +{ + if (*this) + { + if (data->packets_in[0] != NOBLOCK) + { + uint8_t c; + Enc28J60Network::readPacket(data->packets_in[0],0,&c,1); + return c; + } + } + return -1; +} + +void +UIPClient::flush() +{ + if (*this) + { + _flushBlocks(&data->packets_in[0]); + } +} + +void +uipclient_appcall(void) +{ + uint16_t send_len = 0; + uip_userdata_t *u = (uip_userdata_t*)uip_conn->appstate; + if (!u && uip_connected()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_connected")); + UIPClient::_dumpAllData(); +#endif + u = (uip_userdata_t*) UIPClient::_allocateData(); + if (u) + { + uip_conn->appstate = u; +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient allocated state: ")); + Serial.println(u->state,BIN); +#endif + } +#ifdef UIPETHERNET_DEBUG_CLIENT + else + Serial.println(F("UIPClient allocation failed")); +#endif + } + if (u) + { + if (uip_newdata()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.print(F("UIPClient uip_newdata, uip_len:")); + Serial.println(uip_len); +#endif + if (uip_len && !(u->state & (UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED))) + { + for (uint8_t i=0; i < UIP_SOCKET_NUMPACKETS; i++) + { + if (u->packets_in[i] == NOBLOCK) + { + u->packets_in[i] = Enc28J60Network::allocBlock(uip_len); + if (u->packets_in[i] != NOBLOCK) + { + Enc28J60Network::copyPacket(u->packets_in[i],0,UIPEthernetClass::in_packet,((uint8_t*)uip_appdata)-uip_buf,uip_len); + if (i == UIP_SOCKET_NUMPACKETS-1) + uip_stop(); + goto finish_newdata; + } + } + } + UIPEthernetClass::packetstate &= ~UIPETHERNET_FREEPACKET; + uip_stop(); + } + } +finish_newdata: + if (u->state & UIP_CLIENT_RESTART) + { + u->state &= ~UIP_CLIENT_RESTART; + uip_restart(); + } + // If the connection has been closed, save received but unread data. + if (uip_closed() || uip_timedout()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_closed")); + UIPClient::_dumpAllData(); +#endif + // drop outgoing packets not sent yet: + UIPClient::_flushBlocks(&u->packets_out[0]); + if (u->packets_in[0] != NOBLOCK) + { + ((uip_userdata_closed_t *)u)->lport = uip_conn->lport; + u->state |= UIP_CLIENT_REMOTECLOSED; + } + else + u->state = 0; + // disassociate appdata. +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("after UIPClient uip_closed")); + UIPClient::_dumpAllData(); +#endif + uip_conn->appstate = NULL; + goto finish; + } + if (uip_acked()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient uip_acked")); +#endif + UIPClient::_eatBlock(&u->packets_out[0]); + } + if (uip_poll() || uip_rexmit()) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + //Serial.println(F("UIPClient uip_poll")); +#endif + if (u->packets_out[0] != NOBLOCK) + { + if (u->packets_out[1] == NOBLOCK) + { + send_len = u->out_pos; + if (send_len > 0) + { + Enc28J60Network::resizeBlock(u->packets_out[0],0,send_len); + } + } + else + send_len = Enc28J60Network::blockSize(u->packets_out[0]); + if (send_len > 0) + { + UIPEthernetClass::uip_hdrlen = ((uint8_t*)uip_appdata)-uip_buf; + UIPEthernetClass::uip_packet = Enc28J60Network::allocBlock(UIPEthernetClass::uip_hdrlen+send_len); + if (UIPEthernetClass::uip_packet != NOBLOCK) + { + Enc28J60Network::copyPacket(UIPEthernetClass::uip_packet,UIPEthernetClass::uip_hdrlen,u->packets_out[0],0,send_len); + UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET; + } + } + goto finish; + } + } + // don't close connection unless all outgoing packets are sent + if (u->state & UIP_CLIENT_CLOSE) + { +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("UIPClient state UIP_CLIENT_CLOSE")); + UIPClient::_dumpAllData(); +#endif + if (u->packets_out[0] == NOBLOCK) + { + u->state = 0; + uip_conn->appstate = NULL; + uip_close(); +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("no blocks out -> free userdata")); + UIPClient::_dumpAllData(); +#endif + } + else + { + uip_stop(); +#ifdef UIPETHERNET_DEBUG_CLIENT + Serial.println(F("blocks outstanding transfer -> uip_stop()")); +#endif + } + } + } + finish: + uip_send(uip_appdata,send_len); + uip_len = send_len; +} + +uip_userdata_t * +UIPClient::_allocateData() +{ + for ( uint8_t sock = 0; sock < UIP_CONNS; sock++ ) + { + uip_userdata_t* data = &UIPClient::all_data[sock]; + if (!data->state) + { + data->state = sock | UIP_CLIENT_CONNECTED; + memset(&data->packets_in[0],0,sizeof(uip_userdata_t)-sizeof(data->state)); + return data; + } + } + return NULL; +} + +uint8_t +UIPClient::_currentBlock(memhandle* block) +{ + for (uint8_t i = 1; i < UIP_SOCKET_NUMPACKETS; i++) + { + if (block[i] == NOBLOCK) + return i-1; + } + return UIP_SOCKET_NUMPACKETS-1; +} + +void +UIPClient::_eatBlock(memhandle* block) +{ +#ifdef UIPETHERNET_DEBUG_CLIENT + memhandle* start = block; + Serial.print(F("eatblock(")); + Serial.print(*block); + Serial.print(F("): ")); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Serial.print(start[i]); + Serial.print(F(" ")); + } + Serial.print(F("-> ")); +#endif + Enc28J60Network::freeBlock(block[0]); + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS-1; i++) + { + block[i] = block[i+1]; + } + block[UIP_SOCKET_NUMPACKETS-1] = NOBLOCK; +#ifdef UIPETHERNET_DEBUG_CLIENT + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Serial.print(start[i]); + Serial.print(F(" ")); + } + Serial.println(); +#endif +} + +void +UIPClient::_flushBlocks(memhandle* block) +{ + for (uint8_t i = 0; i < UIP_SOCKET_NUMPACKETS; i++) + { + Enc28J60Network::freeBlock(block[i]); + block[i] = NOBLOCK; + } +} + +#ifdef UIPETHERNET_DEBUG_CLIENT +void +UIPClient::_dumpAllData() { + for (uint8_t i=0; i < UIP_CONNS; i++) + { + Serial.print(F("UIPClient::all_data[")); + Serial.print(i); + Serial.print(F("], state:")); + Serial.println(all_data[i].state, BIN); + Serial.print(F("packets_in: ")); + for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++) + { + Serial.print(all_data[i].packets_in[j]); + Serial.print(F(" ")); + } + Serial.println(); + if (all_data[i].state & UIP_CLIENT_REMOTECLOSED) + { + Serial.print(F("state remote closed, local port: ")); + Serial.println(htons(((uip_userdata_closed_t *)(&all_data[i]))->lport)); + } + else + { + Serial.print(F("packets_out: ")); + for (uint8_t j=0; j < UIP_SOCKET_NUMPACKETS; j++) + { + Serial.print(all_data[i].packets_out[j]); + Serial.print(F(" ")); + } + Serial.println(); + Serial.print(F("out_pos: ")); + Serial.println(all_data[i].out_pos); + } + } +} +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPClient.h b/STM32F4/libraries/arduino_uip/UIPClient.h new file mode 100644 index 0000000..6c0c006 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPClient.h @@ -0,0 +1,112 @@ +/* + UIPClient.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPCLIENT_H +#define UIPCLIENT_H + +#include "ethernet_comp.h" +#include "Print.h" +#import "Client.h" +#import "utility/mempool.h" + +extern "C" { + #import "utility/uip.h" +} + +#define UIP_SOCKET_DATALEN UIP_TCP_MSS +//#define UIP_SOCKET_NUMPACKETS UIP_RECEIVE_WINDOW/UIP_TCP_MSS+1 +#ifndef UIP_SOCKET_NUMPACKETS +#define UIP_SOCKET_NUMPACKETS 5 +#endif + +#define UIP_CLIENT_CONNECTED 0x10 +#define UIP_CLIENT_CLOSE 0x20 +#define UIP_CLIENT_REMOTECLOSED 0x40 +#define UIP_CLIENT_RESTART 0x80 +#define UIP_CLIENT_STATEFLAGS (UIP_CLIENT_CONNECTED | UIP_CLIENT_CLOSE | UIP_CLIENT_REMOTECLOSED | UIP_CLIENT_RESTART) +#define UIP_CLIENT_SOCKETS ~UIP_CLIENT_STATEFLAGS + +typedef uint8_t uip_socket_ptr; + +typedef struct { + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + uint16_t lport; /**< The local TCP port, in network byte order. */ +} uip_userdata_closed_t; + +typedef struct { + uint8_t state; + memhandle packets_in[UIP_SOCKET_NUMPACKETS]; + memhandle packets_out[UIP_SOCKET_NUMPACKETS]; + memaddress out_pos; +#if UIP_CLIENT_TIMER >= 0 + unsigned long timer; +#endif +} uip_userdata_t; + +class UIPClient : public Client { + +public: + UIPClient(); + int connect(IPAddress ip, uint16_t port); + int connect(const char *host, uint16_t port); + int read(uint8_t *buf, size_t size); + void stop(); + uint8_t connected(); + operator bool(); + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + + size_t write(uint8_t); + size_t write(const uint8_t *buf, size_t size); + int available(); + int read(); + int peek(); + void flush(); + + using Print::write; + +private: + UIPClient(struct uip_conn *_conn); + UIPClient(uip_userdata_t* conn_data); + + uip_userdata_t* data; + + static uip_userdata_t all_data[UIP_CONNS]; + static uip_userdata_t* _allocateData(); + + static size_t _write(uip_userdata_t *,const uint8_t *buf, size_t size); + static int _available(uip_userdata_t *); + + static uint8_t _currentBlock(memhandle* blocks); + static void _eatBlock(memhandle* blocks); + static void _flushBlocks(memhandle* blocks); + +#ifdef UIPETHERNET_DEBUG_CLIENT + static void _dumpAllData(); +#endif + + friend class UIPEthernetClass; + friend class UIPServer; + + friend void uipclient_appcall(void); + +}; + +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPEthernet.cpp b/STM32F4/libraries/arduino_uip/UIPEthernet.cpp new file mode 100644 index 0000000..397209a --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPEthernet.cpp @@ -0,0 +1,486 @@ +/* + UIPEthernet.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include +#include "UIPEthernet.h" +#include "utility/Enc28J60Network.h" + +#if(defined UIPETHERNET_DEBUG || defined UIPETHERNET_DEBUG_CHKSUM) +#include "HardwareSerial.h" +#endif + +#define Serial SerialUSB + +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +#include "utility/uip_timer.h" +} + +#define ETH_HDR ((struct uip_eth_hdr *)&uip_buf[0]) + +memhandle UIPEthernetClass::in_packet(NOBLOCK); +memhandle UIPEthernetClass::uip_packet(NOBLOCK); +uint8_t UIPEthernetClass::uip_hdrlen(0); +uint8_t UIPEthernetClass::packetstate(0); + +IPAddress UIPEthernetClass::_dnsServerAddress; +DhcpClass* UIPEthernetClass::_dhcp(NULL); + +unsigned long UIPEthernetClass::periodic_timer; + +// Because uIP isn't encapsulated within a class we have to use global +// variables, so we can only have one TCP/IP stack per program. + +UIPEthernetClass::UIPEthernetClass() +{ +} + +#if UIP_UDP +int +UIPEthernetClass::begin(const uint8_t* mac) +{ + static DhcpClass s_dhcp; + _dhcp = &s_dhcp; + // Initialise the basic info + init(mac); + + // Now try to get our config info from a DHCP server + int ret = _dhcp->beginWithDHCP((uint8_t*)mac); + if(ret == 1) + { + // We've successfully found a DHCP server and got our configuration info, so set things + // accordingly + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + } + return ret; +} +#endif + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip) +{ + IPAddress dns = ip; + dns[3] = 1; + begin(mac, ip, dns); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns) +{ + IPAddress gateway = ip; + gateway[3] = 1; + begin(mac, ip, dns, gateway); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway) +{ + IPAddress subnet(255, 255, 255, 0); + begin(mac, ip, dns, gateway, subnet); +} + +void +UIPEthernetClass::begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) +{ + init(mac); + configure(ip,dns,gateway,subnet); +} + +int UIPEthernetClass::maintain(){ + tick(); + int rc = DHCP_CHECK_NONE; +#if UIP_UDP + if(_dhcp != NULL){ + //we have a pointer to dhcp, use it + rc = _dhcp->checkLease(); + switch ( rc ){ + case DHCP_CHECK_NONE: + //nothing done + break; + case DHCP_CHECK_RENEW_OK: + case DHCP_CHECK_REBIND_OK: + //we might have got a new IP. + configure(_dhcp->getLocalIp(),_dhcp->getDnsServerIp(),_dhcp->getGatewayIp(),_dhcp->getSubnetMask()); + break; + default: + //this is actually a error, it will retry though + break; + } + } + return rc; +#endif +} + +IPAddress UIPEthernetClass::localIP() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_gethostaddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::subnetMask() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_getnetmask(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::gatewayIP() +{ + IPAddress ret; + uip_ipaddr_t a; + uip_getdraddr(a); + return ip_addr_uip(a); +} + +IPAddress UIPEthernetClass::dnsServerIP() +{ + return _dnsServerAddress; +} + +void +UIPEthernetClass::tick() +{ + if (in_packet == NOBLOCK) + { + in_packet = Enc28J60Network::receivePacket(); +#ifdef UIPETHERNET_DEBUG + if (in_packet != NOBLOCK) + { + Serial.print(F("--------------\r\nreceivePacket: ")); + Serial.println(in_packet); + } +#endif + } + if (in_packet != NOBLOCK) + { + packetstate = UIPETHERNET_FREEPACKET; + uip_len = Enc28J60Network::blockSize(in_packet); + if (uip_len > 0) + { + Enc28J60Network::readPacket(in_packet,0,(uint8_t*)uip_buf,UIP_BUFSIZE); + if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_IP)) + { + uip_packet = in_packet; //required for upper_layer_checksum of in_packet! +#ifdef UIPETHERNET_DEBUG + Serial.print(F("readPacket type IP, uip_len: ")); + Serial.println(uip_len); +#endif + uip_arp_ipin(); + uip_input(); + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } + else if (ETH_HDR ->type == HTONS(UIP_ETHTYPE_ARP)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("readPacket type ARP, uip_len: ")); + Serial.println(uip_len); +#endif + uip_arp_arpin(); + if (uip_len > 0) + { + network_send(); + } + } + } + if (in_packet != NOBLOCK && (packetstate & UIPETHERNET_FREEPACKET)) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("freeing packet: ")); + Serial.println(in_packet); +#endif + Enc28J60Network::freePacket(); + in_packet = NOBLOCK; + } + } + + unsigned long now = millis(); + +#if UIP_CLIENT_TIMER >= 0 + boolean periodic = (long)( now - periodic_timer ) >= 0; + for (int i = 0; i < UIP_CONNS; i++) + { +#else + if ((long)( now - periodic_timer ) >= 0) + { + periodic_timer = now + UIP_PERIODIC_TIMER; + + for (int i = 0; i < UIP_CONNS; i++) + { +#endif + uip_conn = &uip_conns[i]; +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { +#endif + uip_process(UIP_TIMER); +#if UIP_CLIENT_TIMER >= 0 + } + else + { + if ((long)( now - ((uip_userdata_t*)uip_conn->appstate)->timer) >= 0) + uip_process(UIP_POLL_REQUEST); + else + continue; + } +#endif + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. + if (uip_len > 0) + { + uip_arp_out(); + network_send(); + } + } +#if UIP_CLIENT_TIMER >= 0 + if (periodic) + { + periodic_timer = now + UIP_PERIODIC_TIMER; +#endif +#if UIP_UDP + for (int i = 0; i < UIP_UDP_CONNS; i++) + { + uip_udp_periodic(i); + // If the above function invocation resulted in data that + // should be sent out on the Enc28J60Network, the global variable + // uip_len is set to a value > 0. */ + if (uip_len > 0) + { + UIPUDP::_send((uip_udp_userdata_t *)(uip_udp_conns[i].appstate)); + } + } +#endif /* UIP_UDP */ + } +} + +boolean UIPEthernetClass::network_send() +{ + if (packetstate & UIPETHERNET_SENDPACKET) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("Enc28J60Network_send uip_packet: ")); + Serial.print(uip_packet); + Serial.print(F(", hdrlen: ")); + Serial.println(uip_hdrlen); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_hdrlen); + packetstate &= ~ UIPETHERNET_SENDPACKET; + goto sendandfree; + } + uip_packet = Enc28J60Network::allocBlock(uip_len); + if (uip_packet != NOBLOCK) + { +#ifdef UIPETHERNET_DEBUG + Serial.print(F("Enc28J60Network_send uip_buf (uip_len): ")); + Serial.print(uip_len); + Serial.print(F(", packet: ")); + Serial.println(uip_packet); +#endif + Enc28J60Network::writePacket(uip_packet,0,uip_buf,uip_len); + goto sendandfree; + } + return false; +sendandfree: + Enc28J60Network::sendPacket(uip_packet); + Enc28J60Network::freeBlock(uip_packet); + uip_packet = NOBLOCK; + return true; +} + +void UIPEthernetClass::init(const uint8_t* mac) { + periodic_timer = millis() + UIP_PERIODIC_TIMER; + + Enc28J60Network::init((uint8_t*)mac); + uip_seteth_addr(mac); + + uip_init(); + uip_arp_init(); +} + +void UIPEthernetClass::configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet) { + uip_ipaddr_t ipaddr; + + uip_ip_addr(ipaddr, ip); + uip_sethostaddr(ipaddr); + + uip_ip_addr(ipaddr, gateway); + uip_setdraddr(ipaddr); + + uip_ip_addr(ipaddr, subnet); + uip_setnetmask(ipaddr); + + _dnsServerAddress = dns; +} + +UIPEthernetClass UIPEthernet; + +/*---------------------------------------------------------------------------*/ +uint16_t +UIPEthernetClass::chksum(uint16_t sum, const uint8_t *data, uint16_t len) +{ + uint16_t t; + const uint8_t *dataptr; + const uint8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} + +/*---------------------------------------------------------------------------*/ + +uint16_t +UIPEthernetClass::ipchksum(void) +{ + uint16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + return (sum == 0) ? 0xffff : htons(sum); +} + +/*---------------------------------------------------------------------------*/ +uint16_t +#if UIP_UDP +UIPEthernetClass::upper_layer_chksum(uint8_t proto) +#else +uip_tcpchksum(void) +#endif +{ + uint16_t upper_layer_len; + uint16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ +#if UIP_UDP + sum = upper_layer_len + proto; +#else + sum = upper_layer_len + UIP_PROTO_TCP; +#endif + /* Sum IP source and destination addresses. */ + sum = UIPEthernetClass::chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + uint8_t upper_layer_memlen; +#if UIP_UDP + switch(proto) + { +// case UIP_PROTO_ICMP: +// case UIP_PROTO_ICMP6: +// upper_layer_memlen = upper_layer_len; +// break; + case UIP_PROTO_UDP: + upper_layer_memlen = UIP_UDPH_LEN; + break; + default: +// case UIP_PROTO_TCP: +#endif + upper_layer_memlen = (BUF->tcpoffset >> 4) << 2; +#if UIP_UDP + break; + } +#endif + sum = UIPEthernetClass::chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], upper_layer_memlen); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print(F("chksum uip_buf[")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN); + Serial.print(F("-")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print(F("]: ")); + Serial.println(htons(sum),HEX); +#endif + if (upper_layer_memlen < upper_layer_len) + { + sum = Enc28J60Network::chksum( + sum, + UIPEthernetClass::uip_packet, + UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen, + upper_layer_len - upper_layer_memlen + ); +#ifdef UIPETHERNET_DEBUG_CHKSUM + Serial.print(F("chksum uip_packet(")); + Serial.print(uip_packet); + Serial.print(F(")[")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_memlen); + Serial.print(F("-")); + Serial.print(UIP_IPH_LEN + UIP_LLH_LEN + upper_layer_len); + Serial.print(F("]: ")); + Serial.println(htons(sum),HEX); +#endif + } + return (sum == 0) ? 0xffff : htons(sum); +} + +uint16_t +uip_ipchksum(void) +{ + return UIPEthernet.ipchksum(); +} + +#if UIP_UDP +uint16_t +uip_tcpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_TCP); + return sum; +} + +uint16_t +uip_udpchksum(void) +{ + uint16_t sum = UIPEthernet.upper_layer_chksum(UIP_PROTO_UDP); + return sum; +} +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPEthernet.h b/STM32F4/libraries/arduino_uip/UIPEthernet.h new file mode 100644 index 0000000..ff49707 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPEthernet.h @@ -0,0 +1,129 @@ +/* + UIPEthernet.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPETHERNET_H +#define UIPETHERNET_H + +#define UIP_UDP 1 + +//#define UIPETHERNET_DEBUG +//#define UIPETHERNET_DEBUG_CHKSUM +//#define UIPETHERNET_DEBUG_UDP +//#define UIPETHERNET_DEBUG_CLIENT + +#include "ethernet_comp.h" +#include +#include "Dhcp.h" +#include "IPAddress.h" +#include "utility/Enc28J60Network.h" +#include "UIPClient.h" +#include "UIPServer.h" +#include "UIPUdp.h" + +extern "C" +{ +#include "utility/uip_timer.h" +#include "utility/uip.h" +} + +#define UIPETHERNET_FREEPACKET 1 +#define UIPETHERNET_SENDPACKET 2 +#define UIPETHERNET_BUFFERREAD 4 + +#define uip_ip_addr(addr, ip) do { \ + ((u16_t *)(addr))[0] = HTONS(((ip[0]) << 8) | (ip[1])); \ + ((u16_t *)(addr))[1] = HTONS(((ip[2]) << 8) | (ip[3])); \ + } while(0) + +#define ip_addr_uip(a) IPAddress(a[0] & 0xFF, a[0] >> 8 , a[1] & 0xFF, a[1] >> 8) //TODO this is not IPV6 capable + +#define uip_seteth_addr(eaddr) do {uip_ethaddr.addr[0] = eaddr[0]; \ + uip_ethaddr.addr[1] = eaddr[1];\ + uip_ethaddr.addr[2] = eaddr[2];\ + uip_ethaddr.addr[3] = eaddr[3];\ + uip_ethaddr.addr[4] = eaddr[4];\ + uip_ethaddr.addr[5] = eaddr[5];} while(0) + +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +class UIPEthernetClass +{ +public: + UIPEthernetClass(); + + int begin(const uint8_t* mac); + void begin(const uint8_t* mac, IPAddress ip); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway); + void begin(const uint8_t* mac, IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + // maintain() must be called at regular intervals to process the incoming serial + // data and issue IP events to the sketch. It does not return until all IP + // events have been processed. Renews dhcp-lease if required. + int maintain(); + + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + IPAddress dnsServerIP(); + +private: + static memhandle in_packet; + static memhandle uip_packet; + static uint8_t uip_hdrlen; + static uint8_t packetstate; + + static IPAddress _dnsServerAddress; + static DhcpClass* _dhcp; + + static unsigned long periodic_timer; + + static void init(const uint8_t* mac); + static void configure(IPAddress ip, IPAddress dns, IPAddress gateway, IPAddress subnet); + + static void tick(); + + static boolean network_send(); + + friend class UIPServer; + + friend class UIPClient; + + friend class UIPUDP; + + static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); + static uint16_t ipchksum(void); +#if UIP_UDP + static uint16_t upper_layer_chksum(uint8_t proto); +#endif + friend uint16_t uip_ipchksum(void); + friend uint16_t uip_tcpchksum(void); + friend uint16_t uip_udpchksum(void); + + friend void uipclient_appcall(void); + friend void uipudp_appcall(void); + +#if UIP_CONF_IPV6 + uint16_t uip_icmp6chksum(void); +#endif /* UIP_CONF_IPV6 */ +}; + +extern UIPEthernetClass UIPEthernet; + +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPServer.cpp b/STM32F4/libraries/arduino_uip/UIPServer.cpp new file mode 100644 index 0000000..21c7ef5 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPServer.cpp @@ -0,0 +1,63 @@ +/* + UIPServer.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#include "UIPEthernet.h" +#include "UIPServer.h" +extern "C" { + #include "utility/uip-conf.h" +} + +UIPServer::UIPServer(uint16_t port) : _port(htons(port)) +{ +} + +UIPClient UIPServer::available() +{ + UIPEthernetClass::tick(); + for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ ) + { + if (data->packets_in[0] != NOBLOCK + && (((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port) + || ((data->state & UIP_CLIENT_REMOTECLOSED) && ((uip_userdata_closed_t *)data)->lport == _port))) + return UIPClient(data); + } + return UIPClient(); +} + +void UIPServer::begin() +{ + uip_listen(_port); + UIPEthernetClass::tick(); +} + +size_t UIPServer::write(uint8_t c) +{ + return write(&c,1); +} + +size_t UIPServer::write(const uint8_t *buf, size_t size) +{ + size_t ret = 0; + for ( uip_userdata_t* data = &UIPClient::all_data[0]; data < &UIPClient::all_data[UIP_CONNS]; data++ ) + { + if ((data->state & UIP_CLIENT_CONNECTED) && uip_conns[data->state & UIP_CLIENT_SOCKETS].lport ==_port) + ret += UIPClient::_write(data,buf,size); + } + return ret; +} + diff --git a/STM32F4/libraries/arduino_uip/UIPServer.h b/STM32F4/libraries/arduino_uip/UIPServer.h new file mode 100644 index 0000000..0cc0619 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPServer.h @@ -0,0 +1,40 @@ +/* + UIPServer.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ +#ifndef UIPSERVER_H +#define UIPSERVER_H + +#include "ethernet_comp.h" +#import "Server.h" +#import "UIPClient.h" + +class UIPServer : public Server { + +public: + UIPServer(uint16_t); + UIPClient available(); + void begin(); + size_t write(uint8_t); + size_t write(const uint8_t *buf, size_t size); + using Print::write; + +private: + uint16_t _port; +}; + +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPUdp.cpp b/STM32F4/libraries/arduino_uip/UIPUdp.cpp new file mode 100644 index 0000000..f9ba4e3 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPUdp.cpp @@ -0,0 +1,385 @@ +/* + UIPUdp.cpp - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "UIPEthernet.h" +#include "UIPUdp.h" +#include "Dns.h" + +#ifdef UIPETHERNET_DEBUG_UDP +#include "HardwareSerial.h" +#endif + +#define Serial SerialUSB + +extern "C" { +#include "utility/uip-conf.h" +#include "utility/uip.h" +#include "utility/uip_arp.h" +} + +#if UIP_UDP +#define UIP_ARPHDRSIZE 42 +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + +// Constructor +UIPUDP::UIPUDP() : + _uip_udp_conn(NULL) +{ + memset(&appdata,0,sizeof(appdata)); +} + +// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use +uint8_t +UIPUDP::begin(uint16_t port) +{ + if (!_uip_udp_conn) + { + _uip_udp_conn = uip_udp_new(NULL, 0); + } + if (_uip_udp_conn) + { + uip_udp_bind(_uip_udp_conn,htons(port)); + _uip_udp_conn->appstate = &appdata; + return 1; + } + return 0; +} + +// Finish with the UDP socket +void +UIPUDP::stop() +{ + if (_uip_udp_conn) + { + uip_udp_remove(_uip_udp_conn); + _uip_udp_conn->appstate = NULL; + _uip_udp_conn=NULL; + Enc28J60Network::freeBlock(appdata.packet_in); + Enc28J60Network::freeBlock(appdata.packet_next); + Enc28J60Network::freeBlock(appdata.packet_out); + memset(&appdata,0,sizeof(appdata)); + } +} + +// Sending UDP packets + +// Start building up a packet to send to the remote host specific in ip and port +// Returns 1 if successful, 0 if there was a problem with the supplied IP address or port +int +UIPUDP::beginPacket(IPAddress ip, uint16_t port) +{ + UIPEthernetClass::tick(); + if (ip && port) + { + uip_ipaddr_t ripaddr; + uip_ip_addr(&ripaddr, ip); +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp beginPacket, ")); +#endif + if (_uip_udp_conn) + { + _uip_udp_conn->rport = htons(port); + uip_ipaddr_copy(_uip_udp_conn->ripaddr, &ripaddr); + } + else + { + _uip_udp_conn = uip_udp_new(&ripaddr,htons(port)); + if (_uip_udp_conn) + { +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("new connection, ")); +#endif + _uip_udp_conn->appstate = &appdata; + } + else + { +#ifdef UIPETHERNET_DEBUG_UDP + Serial.println(F("failed to allocate new connection")); +#endif + return 0; + } + } +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("rip: ")); + Serial.print(ip); + Serial.print(F(", port: ")); + Serial.println(port); +#endif + } + if (_uip_udp_conn) + { + if (appdata.packet_out == NOBLOCK) + { + appdata.packet_out = Enc28J60Network::allocBlock(UIP_UDP_MAXPACKETSIZE); + appdata.out_pos = UIP_UDP_PHYH_LEN; + if (appdata.packet_out != NOBLOCK) + return 1; +#ifdef UIPETHERNET_DEBUG_UDP + else + Serial.println(F("failed to allocate memory for packet")); +#endif + } +#ifdef UIPETHERNET_DEBUG_UDP + else + Serial.println(F("previous packet on that connection not sent yet")); +#endif + } + return 0; +} + +// Start building up a packet to send to the remote host specific in host and port +// Returns 1 if successful, 0 if there was a problem resolving the hostname or port +int +UIPUDP::beginPacket(const char *host, uint16_t port) +{ + // Look up the host first + int ret = 0; + DNSClient dns; + IPAddress remote_addr; + + dns.begin(UIPEthernet.dnsServerIP()); + ret = dns.getHostByName(host, remote_addr); + if (ret == 1) { + return beginPacket(remote_addr, port); + } else { + return ret; + } +} + +// Finish off this packet and send it +// Returns 1 if the packet was sent successfully, 0 if there was an error +int +UIPUDP::endPacket() +{ + if (_uip_udp_conn && appdata.packet_out != NOBLOCK) + { + appdata.send = true; + Enc28J60Network::resizeBlock(appdata.packet_out,0,appdata.out_pos); + uip_udp_periodic_conn(_uip_udp_conn); + if (uip_len > 0) + { + _send(&appdata); + return 1; + } + } + return 0; +} + +// Write a single byte into the packet +size_t +UIPUDP::write(uint8_t c) +{ + return write(&c,1); +} + +// Write size bytes from buffer into the packet +size_t +UIPUDP::write(const uint8_t *buffer, size_t size) +{ + if (appdata.packet_out != NOBLOCK) + { + size_t ret = Enc28J60Network::writePacket(appdata.packet_out,appdata.out_pos,(uint8_t*)buffer,size); + appdata.out_pos += ret; + return ret; + } + return 0; +} + +// Start processing the next available incoming packet +// Returns the size of the packet in bytes, or 0 if no packets are available +int +UIPUDP::parsePacket() +{ + UIPEthernetClass::tick(); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F("udp parsePacket freeing previous packet: ")); + Serial.println(appdata.packet_in); + } +#endif + Enc28J60Network::freeBlock(appdata.packet_in); + + appdata.packet_in = appdata.packet_next; + appdata.packet_next = NOBLOCK; + +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F("udp parsePacket received packet: ")); + Serial.print(appdata.packet_in); + } +#endif + int size = Enc28J60Network::blockSize(appdata.packet_in); +#ifdef UIPETHERNET_DEBUG_UDP + if (appdata.packet_in != NOBLOCK) + { + Serial.print(F(", size: ")); + Serial.println(size); + } +#endif + return size; +} + +// Number of bytes remaining in the current packet +int +UIPUDP::available() +{ + UIPEthernetClass::tick(); + return Enc28J60Network::blockSize(appdata.packet_in); +} + +// Read a single byte from the current packet +int +UIPUDP::read() +{ + unsigned char c; + if (read(&c,1) > 0) + { + return c; + } + return -1; +} + +// Read up to len bytes from the current packet and place them into buffer +// Returns the number of bytes read, or 0 if none are available +int +UIPUDP::read(unsigned char* buffer, size_t len) +{ + UIPEthernetClass::tick(); + if (appdata.packet_in != NOBLOCK) + { + memaddress read = Enc28J60Network::readPacket(appdata.packet_in,0,buffer,len); + if (read == Enc28J60Network::blockSize(appdata.packet_in)) + { + Enc28J60Network::freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; + } + else + Enc28J60Network::resizeBlock(appdata.packet_in,read); + return read; + } + return 0; +} + +// Return the next byte from the current packet without moving on to the next byte +int +UIPUDP::peek() +{ + UIPEthernetClass::tick(); + if (appdata.packet_in != NOBLOCK) + { + unsigned char c; + if (Enc28J60Network::readPacket(appdata.packet_in,0,&c,1) == 1) + return c; + } + return -1; +} + +// Finish reading the current packet +void +UIPUDP::flush() +{ + UIPEthernetClass::tick(); + Enc28J60Network::freeBlock(appdata.packet_in); + appdata.packet_in = NOBLOCK; +} + +// Return the IP address of the host who sent the current incoming packet +IPAddress +UIPUDP::remoteIP() +{ + return _uip_udp_conn ? ip_addr_uip(_uip_udp_conn->ripaddr) : IPAddress(); +} + +// Return the port of the host who sent the current incoming packet +uint16_t +UIPUDP::remotePort() +{ + return _uip_udp_conn ? ntohs(_uip_udp_conn->rport) : 0; +} + +// uIP callback function + +void +uipudp_appcall(void) { + if (uip_udp_userdata_t *data = (uip_udp_userdata_t *)(uip_udp_conn->appstate)) + { + if (uip_newdata()) + { + if (data->packet_next == NOBLOCK) + { + uip_udp_conn->rport = UDPBUF->srcport; + uip_ipaddr_copy(uip_udp_conn->ripaddr,UDPBUF->srcipaddr); + data->packet_next = Enc28J60Network::allocBlock(ntohs(UDPBUF->udplen)-UIP_UDPH_LEN); + //if we are unable to allocate memory the packet is dropped. udp doesn't guarantee packet delivery + if (data->packet_next != NOBLOCK) + { + //discard Linklevel and IP and udp-header and any trailing bytes: + Enc28J60Network::copyPacket(data->packet_next,0,UIPEthernetClass::in_packet,UIP_UDP_PHYH_LEN,Enc28J60Network::blockSize(data->packet_next)); + #ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_newdata received packet: ")); + Serial.print(data->packet_next); + Serial.print(F(", size: ")); + Serial.println(Enc28J60Network::blockSize(data->packet_next)); + #endif + } + } + } + if (uip_poll() && data->send) + { + //set uip_slen (uip private) by calling uip_udp_send +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_poll preparing packet to send: ")); + Serial.print(data->packet_out); + Serial.print(F(", size: ")); + Serial.println(Enc28J60Network::blockSize(data->packet_out)); +#endif + UIPEthernetClass::uip_packet = data->packet_out; + UIPEthernetClass::uip_hdrlen = UIP_UDP_PHYH_LEN; + uip_udp_send(data->out_pos - (UIP_UDP_PHYH_LEN)); + } + } +} + +void +UIPUDP::_send(uip_udp_userdata_t *data) { + uip_arp_out(); //add arp + if (uip_len == UIP_ARPHDRSIZE) + { + UIPEthernetClass::uip_packet = NOBLOCK; + UIPEthernetClass::packetstate &= ~UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + Serial.println(F("udp, uip_poll results in ARP-packet")); +#endif + } + else + //arp found ethaddr for ip (otherwise packet is replaced by arp-request) + { + data->send = false; + data->packet_out = NOBLOCK; + UIPEthernetClass::packetstate |= UIPETHERNET_SENDPACKET; +#ifdef UIPETHERNET_DEBUG_UDP + Serial.print(F("udp, uip_packet to send: ")); + Serial.println(UIPEthernetClass::uip_packet); +#endif + } + UIPEthernetClass::network_send(); +} +#endif diff --git a/STM32F4/libraries/arduino_uip/UIPUdp.h b/STM32F4/libraries/arduino_uip/UIPUdp.h new file mode 100644 index 0000000..b007a3c --- /dev/null +++ b/STM32F4/libraries/arduino_uip/UIPUdp.h @@ -0,0 +1,126 @@ +/* + UIPUdp.h - Arduino implementation of a uIP wrapper class. + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef UIPUDP_H +#define UIPUDP_H + +#include "ethernet_comp.h" +#include "Arduino.h" +#include +#include "utility/mempool.h" +extern "C" { + #include "utility/uip.h" +} + +#define UIP_UDP_MAXDATALEN 1500 +#define UIP_UDP_PHYH_LEN UIP_LLH_LEN+UIP_IPUDPH_LEN +#define UIP_UDP_MAXPACKETSIZE UIP_UDP_MAXDATALEN+UIP_UDP_PHYH_LEN + +typedef struct { + memaddress out_pos; + memhandle packet_next; + memhandle packet_in; + memhandle packet_out; + boolean send; +} uip_udp_userdata_t; + +class UIPUDP : public UDP +{ + +private: + struct uip_udp_conn *_uip_udp_conn; + + uip_udp_userdata_t appdata; + +public: + UIPUDP(); // Constructor + uint8_t + begin(uint16_t);// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + void + stop(); // Finish with the UDP socket + + // Sending UDP packets + + // Start building up a packet to send to the remote host specific in ip and port + // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port + int + beginPacket(IPAddress ip, uint16_t port); + // Start building up a packet to send to the remote host specific in host and port + // Returns 1 if successful, 0 if there was a problem resolving the hostname or port + int + beginPacket(const char *host, uint16_t port); + // Finish off this packet and send it + // Returns 1 if the packet was sent successfully, 0 if there was an error + int + endPacket(); + // Write a single byte into the packet + size_t + write(uint8_t); + // Write size bytes from buffer into the packet + size_t + write(const uint8_t *buffer, size_t size); + + using Print::write; + + // Start processing the next available incoming packet + // Returns the size of the packet in bytes, or 0 if no packets are available + int + parsePacket(); + // Number of bytes remaining in the current packet + int + available(); + // Read a single byte from the current packet + int + read(); + // Read up to len bytes from the current packet and place them into buffer + // Returns the number of bytes read, or 0 if none are available + int + read(unsigned char* buffer, size_t len); + // Read up to len characters from the current packet and place them into buffer + // Returns the number of characters read, or 0 if none are available + int + read(char* buffer, size_t len) + { + return read((unsigned char*) buffer, len); + } + ; + // Return the next byte from the current packet without moving on to the next byte + int + peek(); + void + flush(); // Finish reading the current packet + + // Return the IP address of the host who sent the current incoming packet + IPAddress + remoteIP(); + + // Return the port of the host who sent the current incoming packet + uint16_t + remotePort(); + +private: + + friend void uipudp_appcall(void); + + friend class UIPEthernetClass; + static void _send(uip_udp_userdata_t *data); + +}; + +#endif diff --git a/STM32F4/libraries/arduino_uip/ethernet_comp.h b/STM32F4/libraries/arduino_uip/ethernet_comp.h new file mode 100644 index 0000000..4cec2ab --- /dev/null +++ b/STM32F4/libraries/arduino_uip/ethernet_comp.h @@ -0,0 +1,9 @@ +#ifndef ETHERNET_COMP_H +#define ETHERNET_COMP_H + +#define Ethernet UIPEthernet +#define EthernetClient UIPClient +#define EthernetServer UIPServer +#define EthernetUDP UIPUDP + +#endif diff --git a/STM32F4/libraries/arduino_uip/examples/AdvancedChatServer/AdvancedChatServer.ino b/STM32F4/libraries/arduino_uip/examples/AdvancedChatServer/AdvancedChatServer.ino new file mode 100644 index 0000000..bc2f094 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/AdvancedChatServer/AdvancedChatServer.ino @@ -0,0 +1,104 @@ +/* + Advanced Chat Server + + A simple server that distributes any incoming messages to all + connected clients but the client the message comes from. + To use telnet to your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield. + + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) + + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe + redesigned to make use of operator== 25 Nov 2013 + by Norbert Truchsess + + */ + +#include + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. + +byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,0,6); + +// telnet defaults to port 23 +EthernetServer server(23); + +EthernetClient clients[4]; + +void setup() { + // initialize the ethernet device + Ethernet.begin(mac, ip); + // start listening for clients + server.begin(); + // Open serial communications and wait for port to open: + Serial.begin(9600); + while (!Serial) { + ; // wait for serial port to connect. Needed for Leonardo only + } + + + Serial.print("Chat server address:"); + Serial.println(Ethernet.localIP()); +} + +void loop() { + // wait for a new client: + EthernetClient client = server.available(); + + if (client) { + + boolean newClient = true; + for (byte i=0;i<4;i++) { + //check whether this client refers to the same socket as one of the existing instances: + if (clients[i]==client) { + newClient = false; + break; + } + } + + if (newClient) { + //check which of the existing clients can be overridden: + for (byte i=0;i<4;i++) { + if (!clients[i] && clients[i]!=client) { + clients[i] = client; + // clead out the input buffer: + client.flush(); + // clead out the input buffer: + client.flush(); + Serial.println("We have a new client"); + client.println("Hello, client!"); + client.print("my IP: "); + client.println(Ethernet.localIP()); + break; + } + } + } + + if (client.available() > 0) { + // read the bytes incoming from the client: + char thisChar = client.read(); + // echo the bytes back to all other connected clients: + for (byte i=0;i<4;i++) { + if (clients[i] && clients[i]!=client) { + clients[i].write(thisChar); + } + } + // echo the bytes to the server as well: + Serial.write(thisChar); + } + } + for (byte i=0;i<4;i++) { + if (!(clients[i].connected())) { + // client.stop() invalidates the internal socket-descriptor, so next use of == will allways return false; + clients[i].stop(); + } + } +} diff --git a/STM32F4/libraries/arduino_uip/examples/EchoServer/EchoServer.ino b/STM32F4/libraries/arduino_uip/examples/EchoServer/EchoServer.ino new file mode 100644 index 0000000..62d66e4 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/EchoServer/EchoServer.ino @@ -0,0 +1,58 @@ +/* + * UIPEthernet EchoServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This Hello World example sets up a server at 192.168.1.6 on port 1000. + * Telnet here to access the service. The uIP stack will also respond to + * pings to test if you have successfully established a TCP connection to + * the Arduino. + * + * This example was based upon uIP hello-world by Adam Dunkels + * Ported to the Arduino IDE by Adam Nielsen + * Adaption to Enc28J60 by Norbert Truchsess + */ + +#include +// The connection_data struct needs to be defined in an external file. +#include +#include + +EthernetServer server = EthernetServer(1000); + +void setup() +{ + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + IPAddress myIP(192,168,0,6); + + Ethernet.begin(mac,myIP); + + server.begin(); +} + +void loop() +{ + size_t size; + + if (EthernetClient client = server.available()) + { + if (client) + { + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg,size); + Serial.write(msg,size); + client.write(msg,size); + free(msg); + } + } + } +} diff --git a/STM32F4/libraries/arduino_uip/examples/TcpClient/TcpClient.ino b/STM32F4/libraries/arduino_uip/examples/TcpClient/TcpClient.ino new file mode 100644 index 0000000..444b36a --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/TcpClient/TcpClient.ino @@ -0,0 +1,77 @@ +/* + * UIPEthernet TcpClient example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This TcpClient example gets its local ip-address via dhcp and sets + * up a tcp socket-connection to 192.168.0.1 port 5000 every 5 Seconds. + * After sending a message it waits for a response. After receiving the + * response the client disconnects and tries to reconnect after 5 seconds. + * + * Copyright (C) 2013 by Norbert Truchsess + */ + +#include +#include + +EthernetClient client; +signed long next; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + Ethernet.begin(mac); + + Serial.print("localIP: "); + Serial.println(Ethernet.localIP()); + Serial.print("subnetMask: "); + Serial.println(Ethernet.subnetMask()); + Serial.print("gatewayIP: "); + Serial.println(Ethernet.gatewayIP()); + Serial.print("dnsServerIP: "); + Serial.println(Ethernet.dnsServerIP()); + + next = 0; +} + +void loop() { + + if (((signed long)(millis() - next)) > 0) + { + next = millis() + 5000; + Serial.println("Client connect"); + // replace hostname with name of machine running tcpserver.pl +// if (client.connect("server.local",5000)) + if (client.connect(IPAddress(192,168,0,1),5000)) + { + Serial.println("Client connected"); + client.println("DATA from Client"); + while(client.available()==0) + { + if (next - millis() < 0) + goto close; + } + int size; + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg,size); + Serial.write(msg,size); + free(msg); + } +close: + //disconnect client + Serial.println("Client disconnect"); + client.stop(); + } + else + Serial.println("Client connect failed"); + } +} diff --git a/STM32F4/libraries/arduino_uip/examples/TcpServer/TcpServer.ino b/STM32F4/libraries/arduino_uip/examples/TcpServer/TcpServer.ino new file mode 100644 index 0000000..ad91059 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/TcpServer/TcpServer.ino @@ -0,0 +1,74 @@ +/* + * UIPEthernet EchoServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This Hello World example sets up a server at 192.168.1.6 on port 1000. + * Telnet here to access the service. The uIP stack will also respond to + * pings to test if you have successfully established a TCP connection to + * the Arduino. + * + * This example was based upon uIP hello-world by Adam Dunkels + * Ported to the Arduino IDE by Adam Nielsen + * Adaption to Enc28J60 by Norbert Truchsess + */ + +#include +#include +#include + + + +EthernetServer server = EthernetServer(23); + + +void setup() +{ + Serial.begin(115200); + delay(3000); + Serial.println("TCP Server starting ..."); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + IPAddress myIP(10,111,111,5); + + Ethernet.begin(mac, myIP); // Static IP +// Ethernet.begin(mac); // DHCP + Serial.print("localIP: "); + Serial.println(Ethernet.localIP().toCharArray()); + Serial.print("subnetMask: "); + Serial.println(Ethernet.subnetMask().toCharArray()); + Serial.print("gatewayIP: "); + Serial.println(Ethernet.gatewayIP().toCharArray()); + Serial.print("dnsServerIP: "); + Serial.println(Ethernet.dnsServerIP().toCharArray()); + + server.begin(); +} + +void loop() +{ + size_t size; + + if (EthernetClient client = server.available()) + { + Serial.println("Client connected !"); + while((size = client.available()) > 0) + { + uint8_t* msg = (uint8_t*)malloc(size); + size = client.read(msg, size); + Serial.print("Client Data received ! size="); + Serial.println(size); + Serial.write(msg, size); + free(msg); + } + client.println("DATA from Server!"); + client.stop(); + } + +} + diff --git a/STM32F4/libraries/arduino_uip/examples/UdpClient/UdpClient.ino b/STM32F4/libraries/arduino_uip/examples/UdpClient/UdpClient.ino new file mode 100644 index 0000000..aad56b4 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/UdpClient/UdpClient.ino @@ -0,0 +1,93 @@ +/* + * UIPEthernet UdpClient example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This UdpClient example tries to send a packet via udp to 192.168.0.1 + * on port 5000 every 5 seconds. After successfully sending the packet it + * waits for up to 5 seconds for a response on the local port that has been + * implicitly opened when sending the packet. + * + * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) + */ + +#include + +EthernetUDP udp; +unsigned long next; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + + Ethernet.begin(mac,IPAddress(192,168,0,6)); + + next = millis()+5000; +} + +void loop() { + + int success; + int len = 0; + + if (((signed long)(millis()-next))>0) + { + do + { + success = udp.beginPacket(IPAddress(192,168,0,1),5000); + Serial.print("beginPacket: "); + Serial.println(success ? "success" : "failed"); + //beginPacket fails if remote ethaddr is unknown. In this case an + //arp-request is send out first and beginPacket succeeds as soon + //the arp-response is received. + } + while (!success && ((signed long)(millis()-next))<0); + if (!success ) + goto stop; + + success = udp.write("hello world from arduino"); + + Serial.print("bytes written: "); + Serial.println(success); + + success = udp.endPacket(); + + Serial.print("endPacket: "); + Serial.println(success ? "success" : "failed"); + + do + { + //check for new udp-packet: + success = udp.parsePacket(); + } + while (!success && ((signed long)(millis()-next))<0); + if (!success ) + goto stop; + + Serial.print("received: '"); + do + { + int c = udp.read(); + Serial.write(c); + len++; + } + while ((success = udp.available())>0); + Serial.print("', "); + Serial.print(len); + Serial.println(" bytes"); + + //finish reading this packet: + udp.flush(); + + stop: + udp.stop(); + next = millis()+5000; + } +} diff --git a/STM32F4/libraries/arduino_uip/examples/UdpServer/UdpServer.ino b/STM32F4/libraries/arduino_uip/examples/UdpServer/UdpServer.ino new file mode 100644 index 0000000..3b12d75 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/examples/UdpServer/UdpServer.ino @@ -0,0 +1,88 @@ +/* + * UIPEthernet UdpServer example. + * + * UIPEthernet is a TCP/IP stack that can be used with a enc28j60 based + * Ethernet-shield. + * + * UIPEthernet uses the fine uIP stack by Adam Dunkels + * + * ----------------- + * + * This UdpServer example sets up a udp-server at 192.168.0.6 on port 5000. + * send packet via upd to test + * + * Copyright (C) 2013 by Norbert Truchsess (norbert.truchsess@t-online.de) + */ + +#include + +EthernetUDP udp; + +void setup() { + + Serial.begin(9600); + + uint8_t mac[6] = {0x00,0x01,0x02,0x03,0x04,0x05}; + + Ethernet.begin(mac,IPAddress(192,168,0,6)); + + int success = udp.begin(5000); + + Serial.print("initialize: "); + Serial.println(success ? "success" : "failed"); + +} + +void loop() { + + //check for new udp-packet: + int size = udp.parsePacket(); + if (size > 0) { + do + { + char* msg = (char*)malloc(size+1); + int len = udp.read(msg,size+1); + msg[len]=0; + Serial.print("received: '"); + Serial.print(msg); + free(msg); + } + while ((size = udp.available())>0); + //finish reading this packet: + udp.flush(); + Serial.println("'"); + int success; + do + { + Serial.print("remote ip: "); + Serial.println(udp.remoteIP()); + Serial.print("remote port: "); + Serial.println(udp.remotePort()); + //send new packet back to ip/port of client. This also + //configures the current connection to ignore packets from + //other clients! + success = udp.beginPacket(udp.remoteIP(),udp.remotePort()); + Serial.print("beginPacket: "); + Serial.println(success ? "success" : "failed"); + //beginPacket fails if remote ethaddr is unknown. In this case an + //arp-request is send out first and beginPacket succeeds as soon + //the arp-response is received. + } + while (!success); + + success = udp.println("hello world from arduino"); + + Serial.print("bytes written: "); + Serial.println(success); + + success = udp.endPacket(); + + Serial.print("endPacket: "); + Serial.println(success ? "success" : "failed"); + + udp.stop(); + //restart with new connection to receive packets from other clients + Serial.print("restart connection: "); + Serial.println (udp.begin(5000) ? "success" : "failed"); + } +} diff --git a/STM32F4/libraries/arduino_uip/keywords.txt b/STM32F4/libraries/arduino_uip/keywords.txt new file mode 100644 index 0000000..83ff854 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/keywords.txt @@ -0,0 +1,58 @@ +####################################### +# Syntax Coloring Map for SerialIP +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +UIPEthernet KEYWORD1 +UIPServer KEYWORD1 +UIPClient KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +PSOCK_BEGIN KEYWORD2 +PSOCK_CLOSE KEYWORD2 +PSOCK_END KEYWORD2 +PSOCK_EXIT KEYWORD2 +PSOCK_INIT KEYWORD2 +PSOCK_READBUF KEYWORD2 +PSOCK_READTO KEYWORD2 +PSOCK_SEND KEYWORD2 +PSOCK_SEND_STR KEYWORD2 + +uip_listen KEYWORD2 +uip_unlisten KEYWORD2 +uip_connect KEYWORD2 +uip_outstanding KEYWORD2 +uip_send KEYWORD2 +uip_datalen KEYWORD2 +uip_close KEYWORD2 +uip_abort KEYWORD2 +uip_stop KEYWORD2 +uip_stopped KEYWORD2 +uip_restart KEYWORD2 +uip_acked KEYWORD2 +uip_connected KEYWORD2 +uip_closed KEYWORD2 +uip_aborted KEYWORD2 +uip_timedout KEYWORD2 +uip_rexmit KEYWORD2 +uip_poll KEYWORD2 +uip_initialmss KEYWORD2 +uip_mss KEYWORD2 +uip_ipaddr KEYWORD2 +uip_ipaddr_maskcmp KEYWORD2 +uip_ipaddr_mask KEYWORD2 +HTONS KEYWORD2 +htons KEYWORD2 + +use_device KEYWORD2 +set_uip_callback KEYWORD2 +set_gateway KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/STM32F4/libraries/arduino_uip/library.properties b/STM32F4/libraries/arduino_uip/library.properties new file mode 100644 index 0000000..8ee6394 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/library.properties @@ -0,0 +1,10 @@ +name=UIPEthernet +author=ntruchsess +email=Norbert Truchsess +sentence=Ethernet library for ENC28J60 +paragraph=implements the same API as stock Ethernet-lib. Just replace the include of Ethernet.h with UIPEthernet.h +url=https://github.com/ntruchsess/arduino_uip +architectures=STM32F1 +version=1.04 +dependencies= +core-dependencies=arduino (>=1.5.0) diff --git a/STM32F4/libraries/arduino_uip/tests/perl/tcpclient.pl b/STM32F4/libraries/arduino_uip/tests/perl/tcpclient.pl new file mode 100755 index 0000000..e6884dc --- /dev/null +++ b/STM32F4/libraries/arduino_uip/tests/perl/tcpclient.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl +#tcpclient.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$client_socket); + +# creating object interface of IO::Socket::INET modules which internally creates +# socket, binds and connects to the TCP server running on the specific port. +$socket = new IO::Socket::INET ( +PeerHost => '192.168.0.6', +PeerPort => '1000', +Proto => 'tcp', +) or die "ERROR in Socket Creation : $!\n"; + +print "TCP Connection Success.\n"; + +# write on the socket to server. +$data = "DATA from Client"; +print $socket "$data\n"; +# we can also send the data through IO::Socket::INET module, +# $socket->send($data); + +# read the socket data sent by server. +$data = <$socket>; +# we can also read from socket through recv() in IO::Socket::INET +# $socket->recv($data,1024); +print "Received from Server : $data\n"; + +sleep (10); +$socket->close(); \ No newline at end of file diff --git a/STM32F4/libraries/arduino_uip/tests/perl/tcpserver.pl b/STM32F4/libraries/arduino_uip/tests/perl/tcpserver.pl new file mode 100755 index 0000000..17405a3 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/tests/perl/tcpserver.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl +#tcpserver.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$client_socket); +my ($peeraddress,$peerport); + +# creating object interface of IO::Socket::INET modules which internally does +# socket creation, binding and listening at the specified port address. +$socket = new IO::Socket::INET ( +LocalHost => '192.168.0.1', +LocalPort => '5000', +Proto => 'tcp', +Listen => 5, +Reuse => 1 +) or die "ERROR in Socket Creation : $!\n"; + +print "SERVER Waiting for client connection on port 5000\n"; + +while(1) +{ + # waiting for new client connection. + $client_socket = $socket->accept(); + + # get the host and port number of newly connected client. + $peer_address = $client_socket->peerhost(); + $peer_port = $client_socket->peerport(); + + print "Accepted New Client Connection From : $peer_address, $peer_port\n "; + + # read operation on the newly accepted client + $data = <$client_socket>; + # we can also read from socket through recv() in IO::Socket::INET + # $client_socket->recv($data,1024); + print "Received from Client : $data\n"; + + # write operation on the newly accepted client. + $data = "DATA from Server"; + print $client_socket "$data\n"; + # we can also send the data through IO::Socket::INET module, + # $client_socket->send($data); + + sleep(1); + + $client_socket->close(); +} + +$socket->close(); + diff --git a/STM32F4/libraries/arduino_uip/tests/perl/udpclient.pl b/STM32F4/libraries/arduino_uip/tests/perl/udpclient.pl new file mode 100755 index 0000000..bc9e6a2 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/tests/perl/udpclient.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl +#udpclient.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$data); + +# We call IO::Socket::INET->new() to create the UDP Socket +# and bind with the PeerAddr. +$socket = new IO::Socket::INET ( +PeerAddr => '192.168.0.6:5000', +Proto => 'udp' +) or die "ERROR in Socket Creation : $!\n"; +#send operation +$data = "data from client"; +$socket->send($data); + +#read operation +$data = <$socket>; +print "Data received from socket : $data\n "; + +sleep(10); +$socket->close(); diff --git a/STM32F4/libraries/arduino_uip/tests/perl/udpserver.pl b/STM32F4/libraries/arduino_uip/tests/perl/udpserver.pl new file mode 100755 index 0000000..e728a46 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/tests/perl/udpserver.pl @@ -0,0 +1,40 @@ +#!/usr/bin/perl +#udpserver.pl + +use IO::Socket::INET; + +# flush after every write +$| = 1; + +my ($socket,$received_data); +my ($peeraddress,$peerport); + +# we call IO::Socket::INET->new() to create the UDP Socket and bound +# to specific port number mentioned in LocalPort and there is no need to provide +# LocalAddr explicitly as in TCPServer. +$socket = new IO::Socket::INET ( +LocalPort => '5000', +Proto => 'udp', +) or die "ERROR in Socket Creation : $!\n"; + +while(1) +{ +# read operation on the socket +$socket->recv($recieved_data,1024); + +#get the peerhost and peerport at which the recent data received. +$peer_address = $socket->peerhost(); +$peer_port = $socket->peerport(); +print "($peer_address , $peer_port) said : $recieved_data\n"; + +#send the data to the client at which the read/write operations done recently. +$data = "data from server\n"; + +$socket->send($data); + +print $socket "$data"; + +} + +$socket->close(); + diff --git a/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.cpp b/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.cpp new file mode 100644 index 0000000..1b6b189 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.cpp @@ -0,0 +1,646 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + based on enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "Enc28J60Network.h" +#include "Arduino.h" + +extern "C" { +//#include +#include "enc28j60.h" +#include "uip.h" +} + +#ifdef ENC28J60DEBUG +#include "HardwareSerial.h" +#endif + +//#define Serial SerialUSB +//#define SPI SPIEth +extern SPIClass SPI; + +// set CS to 0 = active +#define CSACTIVE digitalWrite(ENC28J60_CONTROL_CS, LOW) +// set CS to 1 = passive +#define CSPASSIVE digitalWrite(ENC28J60_CONTROL_CS, HIGH) +// +#define waitspi() while(!(SPSR&(1< ip checksum for theses bytes=f7f9 + // in binary these poitions are:11 0000 0011 1111 + // This is hex 303F->EPMM0=0x3f,EPMM1=0x30 + //TODO define specific pattern to receive dhcp-broadcast packages instead of setting ERFCON_BCEN! +// enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam + writeReg(ERXFCON, ERXFCON_UCEN|ERXFCON_CRCEN|ERXFCON_PMEN|ERXFCON_BCEN); + writeRegPair(EPMM0, 0x303f); + writeRegPair(EPMCSL, 0xf7f9); + // + // + // do bank 2 stuff + // enable MAC receive + // and bring MAC out of reset (writes 0x00 to MACON2) + writeRegPair(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS); + //----------------writeRegPair(MACON2, 0x00); + // enable automatic padding to 60bytes and CRC operations + writeOp(ENC28J60_BIT_FIELD_SET, MACON3, MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN); + // set inter-frame gap (non-back-to-back) + writeRegPair(MAIPGL, 0x0C12); + // set inter-frame gap (back-to-back) + writeReg(MABBIPG, 0x12); + // Set the maximum packet size which the controller will accept + // Do not send packets longer than MAX_FRAMELEN: + writeRegPair(MAMXFLL, MAX_FRAMELEN); + // do bank 3 stuff + // write MAC address + // NOTE: MAC address in ENC28J60 is byte-backward + writeReg(MAADR5, macaddr[0]); + writeReg(MAADR4, macaddr[1]); + writeReg(MAADR3, macaddr[2]); + writeReg(MAADR2, macaddr[3]); + writeReg(MAADR1, macaddr[4]); + writeReg(MAADR0, macaddr[5]); + // no loopback of transmitted frames + phyWrite(PHCON2, PHCON2_HDLDIS); + // switch to bank 0 + setBank(ECON1); + // enable interrutps + writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE); + // enable packet reception + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + //Configure leds + phyWrite(PHLCON,0x476); + + byte rev = readReg(EREVID); + // microchip forgot to step the number on the silcon when they + // released the revision B7. 6 is now rev B7. We still have + // to see what they do when they release B8. At the moment + // there is no B8 out yet + if (rev > 5) ++rev; +#ifdef ENC28J60DEBUG + Serial.print("ENC28J60::initialize returns "); + Serial.println(rev); +#endif +// return rev; +} + + +memhandle +Enc28J60Network::receivePacket() +{ + uint8_t rxstat; + uint16_t len; + // check if a packet has been received and buffered + //if( !(readReg(EIR) & EIR_PKTIF) ){ + // The above does not work. See Rev. B4 Silicon Errata point 6. + if (readReg(EPKTCNT) != 0) + { + uint16_t readPtr = nextPacketPtr+6 > RXSTOP_INIT ? nextPacketPtr+6-RXSTOP_INIT+RXSTART_INIT : nextPacketPtr+6; + // Set the read pointer to the start of the received packet + writeRegPair(ERDPTL, nextPacketPtr); + // read the next packet pointer + nextPacketPtr = readOp(ENC28J60_READ_BUF_MEM, 0); + nextPacketPtr |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + // read the packet length (see datasheet page 43) + len = readOp(ENC28J60_READ_BUF_MEM, 0); + len |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; + len -= 4; //remove the CRC count + // read the receive status (see datasheet page 43) + rxstat = readOp(ENC28J60_READ_BUF_MEM, 0); + //rxstat |= readOp(ENC28J60_READ_BUF_MEM, 0) << 8; +#ifdef ENC28J60DEBUG + Serial.print("receivePacket ["); + Serial.print(readPtr,HEX); + Serial.print("-"); + Serial.print((readPtr+len) % (RXSTOP_INIT+1),HEX); + Serial.print("], next: "); + Serial.print(nextPacketPtr,HEX); + Serial.print(", stat: "); + Serial.print(rxstat,HEX); + Serial.print(", count: "); + Serial.print(readReg(EPKTCNT)); + Serial.print(" -> "); + Serial.println((rxstat & 0x80)!=0 ? "OK" : "failed"); +#endif + // decrement the packet counter indicate we are done with this packet + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC); + // check CRC and symbol errors (see datasheet page 44, table 7-3): + // The ERXFCON.CRCEN is set by default. Normally we should not + // need to check this. + if ((rxstat & 0x80) != 0) + { + receivePkt.begin = readPtr; + receivePkt.size = len; +#ifdef ENC28J60DEBUG + Serial.print("receivePkt.size="); + Serial.println(len); +#endif + return UIP_RECEIVEBUFFERHANDLE; + } + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); + } + return (NOBLOCK); +} + +void +Enc28J60Network::setERXRDPT() +{ + writeRegPair(ERXRDPTL, nextPacketPtr == RXSTART_INIT ? RXSTOP_INIT : nextPacketPtr-1); +} + +memaddress +Enc28J60Network::blockSize(memhandle handle) +{ + return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; +} + +void +Enc28J60Network::sendPacket(memhandle handle) +{ + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin-1; + uint16_t end = start + packet->size; + + // backup data at control-byte position + uint8_t data = readByte(start); + // write control-byte (if not 0 anyway) + if (data) + writeByte(start, 0); + +#ifdef ENC28J60DEBUG + Serial.print("sendPacket("); + Serial.print(handle); + Serial.print(") ["); + Serial.print(start,HEX); + Serial.print("-"); + Serial.print(end,HEX); + Serial.print("]: "); + for (uint16_t i=start; i<=end; i++) + { + Serial.print(readByte(i),HEX); + Serial.print(" "); + } + Serial.println(); +#endif + + // TX start + writeRegPair(ETXSTL, start); + // Set the TXND pointer to correspond to the packet size given + writeRegPair(ETXNDL, end); + // send the contents of the transmit buffer onto the network + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS); + // Reset the transmit logic problem. See Rev. B4 Silicon Errata point 12. + if( (readReg(EIR) & EIR_TXERIF) ) + { + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRTS); + } + + //restore data on control-byte position + if (data) + writeByte(start, data); +} + +uint16_t +Enc28J60Network::setReadPtr(memhandle handle, memaddress position, uint16_t len) +{ + memblock *packet = handle == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[handle]; + memaddress start = handle == UIP_RECEIVEBUFFERHANDLE && packet->begin + position > RXSTOP_INIT ? packet->begin + position-RXSTOP_INIT+RXSTART_INIT : packet->begin + position; + + writeRegPair(ERDPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + return len; +} + +uint16_t +Enc28J60Network::readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + len = setReadPtr(handle, position, len); + readBuffer(len, buffer); + return len; +} + +uint16_t +Enc28J60Network::writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len) +{ + memblock *packet = &blocks[handle]; + uint16_t start = packet->begin + position; + + writeRegPair(EWRPTL, start); + + if (len > packet->size - position) + len = packet->size - position; + writeBuffer(len, buffer); + return len; +} + + +void Enc28J60Network::enableBroadcast (bool temporary) { + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN); + if(!temporary) + broadcast_enabled = true; +} + +void Enc28J60Network::disableBroadcast (bool temporary) { + if(!temporary) + broadcast_enabled = false; + if(!broadcast_enabled) + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN); +} + +void Enc28J60Network::enableMulticast () { + writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN); +} + +void Enc28J60Network::disableMulticast () { + writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN); +} + +byte Enc28J60Network::readRegByte (uint8_t address) { + setBank(address); + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void Enc28J60Network::writeRegByte (uint8_t address, uint8_t data) { + setBank(address); + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + + +uint8_t Enc28J60Network::readByte(uint16_t addr) +{ + writeRegPair(ERDPTL, addr); + + CSACTIVE; + SPI.transfer(ENC28J60_READ_BUF_MEM); + uint8_t data = SPI.transfer(0x00); + CSPASSIVE; + return data; +} + +void Enc28J60Network::writeByte(uint16_t addr, uint8_t data) +{ + writeRegPair(EWRPTL, addr); + + CSACTIVE; + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + SPI.transfer(data); + CSPASSIVE; +} + +void +Enc28J60Network::copyPacket(memhandle dest_pkt, memaddress dest_pos, memhandle src_pkt, memaddress src_pos, uint16_t len) +{ + memblock *dest = &blocks[dest_pkt]; + memblock *src = src_pkt == UIP_RECEIVEBUFFERHANDLE ? &receivePkt : &blocks[src_pkt]; + memaddress start = src_pkt == UIP_RECEIVEBUFFERHANDLE && src->begin + src_pos > RXSTOP_INIT ? src->begin + src_pos-RXSTOP_INIT+RXSTART_INIT : src->begin + src_pos; + enc28J60_mempool_block_move_callback(dest->begin+dest_pos,start,len); + // Move the RX read pointer to the start of the next received packet + // This frees the memory we just read out + setERXRDPT(); +} + +void +enc28J60_mempool_block_move_callback(memaddress dest, memaddress src, memaddress len) +{ +//void +//Enc28J60Network::memblock_mv_cb(uint16_t dest, uint16_t src, uint16_t len) +//{ + //as ENC28J60 DMA is unable to copy single bytes: + if (len == 1) + { + Enc28J60Network::writeByte(dest,Enc28J60Network::readByte(src)); + } + else + { + // calculate address of last byte + len += src - 1; + + /* 1. Appropriately program the EDMAST, EDMAND + and EDMADST register pairs. The EDMAST + registers should point to the first byte to copy + from, the EDMAND registers should point to the + last byte to copy and the EDMADST registers + should point to the first byte in the destination + range. The destination range will always be + linear, never wrapping at any values except from + 8191 to 0 (the 8-Kbyte memory boundary). + Extreme care should be taken when + programming the start and end pointers to + prevent a never ending DMA operation which + would overwrite the entire 8-Kbyte buffer. + */ + Enc28J60Network::writeRegPair(EDMASTL, src); + Enc28J60Network::writeRegPair(EDMADSTL, dest); + + if ((src <= RXSTOP_INIT)&& (len > RXSTOP_INIT))len -= (RXSTOP_INIT-RXSTART_INIT); + Enc28J60Network::writeRegPair(EDMANDL, len); + + /* + 2. If an interrupt at the end of the copy process is + desired, set EIE.DMAIE and EIE.INTIE and + clear EIR.DMAIF. + + 3. Verify that ECON1.CSUMEN is clear. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_CSUMEN); + + /* 4. Start the DMA copy by setting ECON1.DMAST. */ + Enc28J60Network::writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST); + + // wait until runnig DMA is completed + while (Enc28J60Network::readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST); + } +} + +void +Enc28J60Network::freePacket() +{ + setERXRDPT(); +} + +uint8_t +Enc28J60Network::readOp(uint8_t op, uint8_t address) +{ + CSACTIVE; + // issue read command + SPI.transfer(op | (address & ADDR_MASK)); + byte result = SPI.transfer(0x00); + if (address & 0x80) + result = SPI.transfer(0x00); + CSPASSIVE; + return result; +} + +void +Enc28J60Network::writeOp(uint8_t op, uint8_t address, uint8_t data) +{ + CSACTIVE; + // issue write command + SPI.transfer(op | (address & ADDR_MASK)); + SPI.transfer(data); + CSPASSIVE; +} + +void +Enc28J60Network::readBuffer(uint16_t len, uint8_t* data) +{ + CSACTIVE; + // issue read command + SPI.transfer(ENC28J60_READ_BUF_MEM); + while (len--) { + *data++ = SPI.transfer(0x00); + } + CSPASSIVE; +} + +void +Enc28J60Network::writeBuffer(uint16_t len, uint8_t* data) +{ + CSACTIVE; + // issue write command + SPI.transfer(ENC28J60_WRITE_BUF_MEM); + while (len--) { + SPI.transfer(*data++); + } + CSPASSIVE; +} + +void +Enc28J60Network::setBank(uint8_t address) +{ + // set the bank (if needed) + if((address & BANK_MASK) != bank) + { + // set the bank + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, (ECON1_BSEL1|ECON1_BSEL0)); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, (address & BANK_MASK)>>5); + bank = (address & BANK_MASK); + } +} + +uint8_t +Enc28J60Network::readReg(uint8_t address) +{ + // set the bank + setBank(address); + // do the read + return readOp(ENC28J60_READ_CTRL_REG, address); +} + +void +Enc28J60Network::writeReg(uint8_t address, uint8_t data) +{ + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, data); +} + +void +Enc28J60Network::writeRegPair(uint8_t address, uint16_t data) +{ + // set the bank + setBank(address); + // do the write + writeOp(ENC28J60_WRITE_CTRL_REG, address, (data&0xFF)); + writeOp(ENC28J60_WRITE_CTRL_REG, address+1, (data) >> 8); +} + +void +Enc28J60Network::phyWrite(uint8_t address, uint16_t data) +{ + // set the PHY register address + writeReg(MIREGADR, address); + // write the PHY data + writeRegPair(MIWRL, data); + // wait until the PHY write completes + while(readReg(MISTAT) & MISTAT_BUSY){ + delayMicroseconds(15); + } +} + +uint16_t +Enc28J60Network::phyRead(uint8_t address) +{ + writeReg(MIREGADR,address); + writeReg(MICMD, MICMD_MIIRD); + // wait until the PHY read completes + while(readReg(MISTAT) & MISTAT_BUSY){ + delayMicroseconds(15); + } //and MIRDH + writeReg(MICMD, 0); + return (readReg(MIRDL) | readReg(MIRDH) << 8); +} + +void +Enc28J60Network::clkout(uint8_t clk) +{ + //setup clkout: 2 is 12.5MHz: + writeReg(ECOCON, clk & 0x7); +} + +// read the revision of the chip: +uint8_t +Enc28J60Network::getrev(void) +{ + return(readReg(EREVID)); +} + +uint16_t +Enc28J60Network::chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len) +{ + uint16_t t; + len = setReadPtr(handle, pos, len)-1; + CSACTIVE; + // issue read command + SPI.transfer(ENC28J60_READ_BUF_MEM); + uint16_t i; + for (i = 0; i < len; i+=2) + { + // read data + t = SPI.transfer(0x00) << 8; + t += SPI.transfer(0x00); + sum += t; + if(sum < t) { + sum++; // carry + } + } + if(i == len) { + t = (SPI.transfer(0x00) << 8) + 0; + sum += t; + if(sum < t) { + sum++; // carry + } + } + CSPASSIVE; + + // Return sum in host byte order. + + return sum; +} + +void +Enc28J60Network::powerOff() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); +} + +void +Enc28J60Network::powerOn() +{ + writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); + delay(50); + writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); + delay(50); +} + +bool +Enc28J60Network::linkStatus() +{ + return (phyRead(PHSTAT2) & 0x0400) > 0; +} + +Enc28J60Network Enc28J60; diff --git a/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.h b/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.h new file mode 100644 index 0000000..4aee588 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/Enc28J60Network.h @@ -0,0 +1,108 @@ +/* + Enc28J60NetworkClass.h + UIPEthernet network driver for Microchip ENC28J60 Ethernet Interface. + + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + inspired by enc28j60.c file from the AVRlib library by Pascal Stang. + For AVRlib See http://www.procyonengineering.com/ + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef Enc28J60Network_H_ +#define Enc28J60Network_H_ + +#include +#include "mempool.h" + +//#define ENC28J60_CONTROL_CS SS +//#define SPI_MOSI MOSI +//#define SPI_MISO MISO +//#define SPI_SCK SCK +//#define SPI_SS SS + +#define ENC28J60_CONTROL_CS PC8 +//#define SPI_MOSI PA7 +//#define SPI_MISO PA6 +//#define SPI_SCK PA5 +//#define SPI_SS PA8 + +#define UIP_RECEIVEBUFFERHANDLE 0xff + +//#define ENC28J60DEBUG + +/* + * Empfangen von ip-header, arp etc... + * wenn tcp/udp -> tcp/udp-callback -> assign new packet to connection + */ + +class Enc28J60Network : public MemoryPool +{ + +private: + static uint16_t nextPacketPtr; + static uint8_t bank; + + static struct memblock receivePkt; + + static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions) + + static uint8_t readOp(uint8_t op, uint8_t address); + static void writeOp(uint8_t op, uint8_t address, uint8_t data); + static uint16_t setReadPtr(memhandle handle, memaddress position, uint16_t len); + static void setERXRDPT(); + static void readBuffer(uint16_t len, uint8_t* data); + static void writeBuffer(uint16_t len, uint8_t* data); + static uint8_t readByte(uint16_t addr); + static void writeByte(uint16_t addr, uint8_t data); + static void setBank(uint8_t address); + static uint8_t readReg(uint8_t address); + static void writeReg(uint8_t address, uint8_t data); + static void writeRegPair(uint8_t address, uint16_t data); + static void phyWrite(uint8_t address, uint16_t data); + static uint16_t phyRead(uint8_t address); + static void clkout(uint8_t clk); + + static void enableBroadcast (bool temporary); + static void disableBroadcast (bool temporary); + static void enableMulticast (); + static void disableMulticast (); + + static uint8_t readRegByte (uint8_t address); + static void writeRegByte (uint8_t address, uint8_t data); + + friend void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +public: + + uint8_t getrev(void); + void powerOn(); + void powerOff(); + bool linkStatus(); + + static void init(uint8_t* macaddr); + static memhandle receivePacket(); + static void freePacket(); + static memaddress blockSize(memhandle handle); + static void sendPacket(memhandle handle); + static uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); + static void copyPacket(memhandle dest, memaddress dest_pos, memhandle src, memaddress src_pos, uint16_t len); + static uint16_t chksum(uint16_t sum, memhandle handle, memaddress pos, uint16_t len); +}; + +extern Enc28J60Network Enc28J60; +#endif /* Enc28J60NetworkClass_H_ */ diff --git a/STM32F4/libraries/arduino_uip/utility/clock-arch.cpp b/STM32F4/libraries/arduino_uip/utility/clock-arch.cpp new file mode 100644 index 0000000..5f020ba --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/clock-arch.cpp @@ -0,0 +1,30 @@ +/* + clock-arch.c - Arduino implementation of uIP clock device. + Copyright (c) 2010 Adam Nielsen + All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "clock-arch.h" + +extern "C" { +clock_time_t +clock_time(void) +{ + return (clock_time_t) millis(); +} +} diff --git a/STM32F4/libraries/arduino_uip/utility/clock-arch.h b/STM32F4/libraries/arduino_uip/utility/clock-arch.h new file mode 100644 index 0000000..d7a828b --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/clock-arch.h @@ -0,0 +1,27 @@ +/* + clock-arch.h - Arduino implementation of uIP clock device. + Copyright (c) 2010 Adam Nielsen + All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef clock_h_ +#define clock_h_ + +typedef unsigned long clock_time_t; +#define CLOCK_CONF_SECOND 1000 + +#endif diff --git a/STM32F4/libraries/arduino_uip/utility/enc28j60.h b/STM32F4/libraries/arduino_uip/utility/enc28j60.h new file mode 100644 index 0000000..3a45c59 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/enc28j60.h @@ -0,0 +1,257 @@ +/***************************************************************************** +* +* Title : Microchip ENC28J60 Ethernet Interface Driver +* Author : Pascal Stang (c)2005 +* Modified by Norbert Truchsess +* Copyright: GPL V2 +* +*This driver provides initialization and transmit/receive +*functions for the Microchip ENC28J60 10Mb Ethernet Controller and PHY. +*This chip is novel in that it is a full MAC+PHY interface all in a 28-pin +*chip, using an SPI interface to the host processor. +* +* +*****************************************************************************/ + +#ifndef ENC28J60_H +#define ENC28J60_H +#include + +// ENC28J60 Control Registers +// Control register definitions are a combination of address, +// bank number, and Ethernet/MAC/PHY indicator bits. +// - Register address (bits 0-4) +// - Bank number (bits 5-6) +// - MAC/PHY indicator (bit 7) +#define ADDR_MASK 0x1F +#define BANK_MASK 0x60 +#define SPRD_MASK 0x80 +// All-bank registers +#define EIE 0x1B +#define EIR 0x1C +#define ESTAT 0x1D +#define ECON2 0x1E +#define ECON1 0x1F +// Bank 0 registers +#define ERDPTL (0x00|0x00) +#define ERDPTH (0x01|0x00) +#define EWRPTL (0x02|0x00) +#define EWRPTH (0x03|0x00) +#define ETXSTL (0x04|0x00) +#define ETXSTH (0x05|0x00) +#define ETXNDL (0x06|0x00) +#define ETXNDH (0x07|0x00) +#define ERXSTL (0x08|0x00) +#define ERXSTH (0x09|0x00) +#define ERXNDL (0x0A|0x00) +#define ERXNDH (0x0B|0x00) +#define ERXRDPTL (0x0C|0x00) +#define ERXRDPTH (0x0D|0x00) +#define ERXWRPTL (0x0E|0x00) +#define ERXWRPTH (0x0F|0x00) +#define EDMASTL (0x10|0x00) +#define EDMASTH (0x11|0x00) +#define EDMANDL (0x12|0x00) +#define EDMANDH (0x13|0x00) +#define EDMADSTL (0x14|0x00) +#define EDMADSTH (0x15|0x00) +#define EDMACSL (0x16|0x00) +#define EDMACSH (0x17|0x00) +// Bank 1 registers +#define EHT0 (0x00|0x20) +#define EHT1 (0x01|0x20) +#define EHT2 (0x02|0x20) +#define EHT3 (0x03|0x20) +#define EHT4 (0x04|0x20) +#define EHT5 (0x05|0x20) +#define EHT6 (0x06|0x20) +#define EHT7 (0x07|0x20) +#define EPMM0 (0x08|0x20) +#define EPMM1 (0x09|0x20) +#define EPMM2 (0x0A|0x20) +#define EPMM3 (0x0B|0x20) +#define EPMM4 (0x0C|0x20) +#define EPMM5 (0x0D|0x20) +#define EPMM6 (0x0E|0x20) +#define EPMM7 (0x0F|0x20) +#define EPMCSL (0x10|0x20) +#define EPMCSH (0x11|0x20) +#define EPMOL (0x14|0x20) +#define EPMOH (0x15|0x20) +#define EWOLIE (0x16|0x20) +#define EWOLIR (0x17|0x20) +#define ERXFCON (0x18|0x20) +#define EPKTCNT (0x19|0x20) +// Bank 2 registers +#define MACON1 (0x00|0x40|0x80) +#define MACON2 (0x01|0x40|0x80) +#define MACON3 (0x02|0x40|0x80) +#define MACON4 (0x03|0x40|0x80) +#define MABBIPG (0x04|0x40|0x80) +#define MAIPGL (0x06|0x40|0x80) +#define MAIPGH (0x07|0x40|0x80) +#define MACLCON1 (0x08|0x40|0x80) +#define MACLCON2 (0x09|0x40|0x80) +#define MAMXFLL (0x0A|0x40|0x80) +#define MAMXFLH (0x0B|0x40|0x80) +#define MAPHSUP (0x0D|0x40|0x80) +#define MICON (0x11|0x40|0x80) +#define MICMD (0x12|0x40|0x80) +#define MIREGADR (0x14|0x40|0x80) +#define MIWRL (0x16|0x40|0x80) +#define MIWRH (0x17|0x40|0x80) +#define MIRDL (0x18|0x40|0x80) +#define MIRDH (0x19|0x40|0x80) +// Bank 3 registers +#define MAADR1 (0x00|0x60|0x80) +#define MAADR0 (0x01|0x60|0x80) +#define MAADR3 (0x02|0x60|0x80) +#define MAADR2 (0x03|0x60|0x80) +#define MAADR5 (0x04|0x60|0x80) +#define MAADR4 (0x05|0x60|0x80) +#define EBSTSD (0x06|0x60) +#define EBSTCON (0x07|0x60) +#define EBSTCSL (0x08|0x60) +#define EBSTCSH (0x09|0x60) +#define MISTAT (0x0A|0x60|0x80) +#define EREVID (0x12|0x60) +#define ECOCON (0x15|0x60) +#define EFLOCON (0x17|0x60) +#define EPAUSL (0x18|0x60) +#define EPAUSH (0x19|0x60) +// PHY registers +#define PHCON1 0x00 +#define PHSTAT1 0x01 +#define PHHID1 0x02 +#define PHHID2 0x03 +#define PHCON2 0x10 +#define PHSTAT2 0x11 +#define PHIE 0x12 +#define PHIR 0x13 +#define PHLCON 0x14 + +// ENC28J60 ERXFCON Register Bit Definitions +#define ERXFCON_UCEN 0x80 +#define ERXFCON_ANDOR 0x40 +#define ERXFCON_CRCEN 0x20 +#define ERXFCON_PMEN 0x10 +#define ERXFCON_MPEN 0x08 +#define ERXFCON_HTEN 0x04 +#define ERXFCON_MCEN 0x02 +#define ERXFCON_BCEN 0x01 +// ENC28J60 EIE Register Bit Definitions +#define EIE_INTIE 0x80 +#define EIE_PKTIE 0x40 +#define EIE_DMAIE 0x20 +#define EIE_LINKIE 0x10 +#define EIE_TXIE 0x08 +#define EIE_WOLIE 0x04 +#define EIE_TXERIE 0x02 +#define EIE_RXERIE 0x01 +// ENC28J60 EIR Register Bit Definitions +#define EIR_PKTIF 0x40 +#define EIR_DMAIF 0x20 +#define EIR_LINKIF 0x10 +#define EIR_TXIF 0x08 +#define EIR_WOLIF 0x04 +#define EIR_TXERIF 0x02 +#define EIR_RXERIF 0x01 +// ENC28J60 ESTAT Register Bit Definitions +#define ESTAT_INT 0x80 +#define ESTAT_LATECOL 0x10 +#define ESTAT_RXBUSY 0x04 +#define ESTAT_TXABRT 0x02 +#define ESTAT_CLKRDY 0x01 +// ENC28J60 ECON2 Register Bit Definitions +#define ECON2_AUTOINC 0x80 +#define ECON2_PKTDEC 0x40 +#define ECON2_PWRSV 0x20 +#define ECON2_VRPS 0x08 +// ENC28J60 ECON1 Register Bit Definitions +#define ECON1_TXRST 0x80 +#define ECON1_RXRST 0x40 +#define ECON1_DMAST 0x20 +#define ECON1_CSUMEN 0x10 +#define ECON1_TXRTS 0x08 +#define ECON1_RXEN 0x04 +#define ECON1_BSEL1 0x02 +#define ECON1_BSEL0 0x01 +// ENC28J60 MACON1 Register Bit Definitions +#define MACON1_LOOPBK 0x10 +#define MACON1_TXPAUS 0x08 +#define MACON1_RXPAUS 0x04 +#define MACON1_PASSALL 0x02 +#define MACON1_MARXEN 0x01 +// ENC28J60 MACON2 Register Bit Definitions +#define MACON2_MARST 0x80 +#define MACON2_RNDRST 0x40 +#define MACON2_MARXRST 0x08 +#define MACON2_RFUNRST 0x04 +#define MACON2_MATXRST 0x02 +#define MACON2_TFUNRST 0x01 +// ENC28J60 MACON3 Register Bit Definitions +#define MACON3_PADCFG2 0x80 +#define MACON3_PADCFG1 0x40 +#define MACON3_PADCFG0 0x20 +#define MACON3_TXCRCEN 0x10 +#define MACON3_PHDRLEN 0x08 +#define MACON3_HFRMLEN 0x04 +#define MACON3_FRMLNEN 0x02 +#define MACON3_FULDPX 0x01 +// ENC28J60 MICMD Register Bit Definitions +#define MICMD_MIISCAN 0x02 +#define MICMD_MIIRD 0x01 +// ENC28J60 MISTAT Register Bit Definitions +#define MISTAT_NVALID 0x04 +#define MISTAT_SCAN 0x02 +#define MISTAT_BUSY 0x01 +// ENC28J60 PHY PHCON1 Register Bit Definitions +#define PHCON1_PRST 0x8000 +#define PHCON1_PLOOPBK 0x4000 +#define PHCON1_PPWRSV 0x0800 +#define PHCON1_PDPXMD 0x0100 +// ENC28J60 PHY PHSTAT1 Register Bit Definitions +#define PHSTAT1_PFDPX 0x1000 +#define PHSTAT1_PHDPX 0x0800 +#define PHSTAT1_LLSTAT 0x0004 +#define PHSTAT1_JBSTAT 0x0002 +// ENC28J60 PHY PHCON2 Register Bit Definitions +#define PHCON2_FRCLINK 0x4000 +#define PHCON2_TXDIS 0x2000 +#define PHCON2_JABBER 0x0400 +#define PHCON2_HDLDIS 0x0100 + +// ENC28J60 Packet Control Byte Bit Definitions +#define PKTCTRL_PHUGEEN 0x08 +#define PKTCTRL_PPADEN 0x04 +#define PKTCTRL_PCRCEN 0x02 +#define PKTCTRL_POVERRIDE 0x01 + +// SPI operation codes +#define ENC28J60_READ_CTRL_REG 0x00 +#define ENC28J60_READ_BUF_MEM 0x3A +#define ENC28J60_WRITE_CTRL_REG 0x40 +#define ENC28J60_WRITE_BUF_MEM 0x7A +#define ENC28J60_BIT_FIELD_SET 0x80 +#define ENC28J60_BIT_FIELD_CLR 0xA0 +#define ENC28J60_SOFT_RESET 0xFF + + +// The RXSTART_INIT should be zero. See Rev. B4 Silicon Errata +// buffer boundaries applied to internal 8K ram +// the entire available packet buffer space is allocated +// +// start with recbuf at 0/ +#define RXSTART_INIT 0x0 +// receive buffer end. make sure this is an odd value ( See Rev. B1,B4,B5,B7 Silicon Errata 'Memory (Ethernet Buffer)') +#define RXSTOP_INIT (0x1FFF-0x1800) +// start TX buffer RXSTOP_INIT+1 +#define TXSTART_INIT (RXSTOP_INIT+1) +// stp TX buffer at end of mem +#define TXSTOP_INIT 0x1FFF +// +// max frame length which the conroller will accept: +#define MAX_FRAMELEN 1500 // (note: maximum ethernet frame length would be 1518) +//#define MAX_FRAMELEN 600 + +#endif diff --git a/STM32F4/libraries/arduino_uip/utility/mempool.cpp b/STM32F4/libraries/arduino_uip/utility/mempool.cpp new file mode 100644 index 0000000..c2f7abf --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/mempool.cpp @@ -0,0 +1,168 @@ +/* + mempool.cpp - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#include "mempool.h" +#include + +#define POOLOFFSET 1 + +struct memblock MemoryPool::blocks[MEMPOOL_NUM_MEMBLOCKS+1]; + +void +MemoryPool::init() +{ + memset(&blocks[0], 0, sizeof(blocks)); + blocks[POOLSTART].begin = MEMPOOL_STARTADDRESS; + blocks[POOLSTART].size = 0; + blocks[POOLSTART].nextblock = NOBLOCK; +} + +memhandle +MemoryPool::allocBlock(memaddress size) +{ + memblock* best = NULL; + memhandle cur = POOLSTART; + memblock* block = &blocks[POOLSTART]; + memaddress bestsize = MEMPOOL_SIZE + 1; + + do + { + memhandle next = block->nextblock; + memaddress freesize = ( next == NOBLOCK ? blocks[POOLSTART].begin + MEMPOOL_SIZE : blocks[next].begin) - block->begin - block->size; + if (freesize == size) + { + best = &blocks[cur]; + goto found; + } + if (freesize > size && freesize < bestsize) + { + bestsize = freesize; + best = &blocks[cur]; + } + if (next == NOBLOCK) + { + if (best) + goto found; + else + goto collect; + } + block = &blocks[next]; + cur = next; + } + while (true); + + collect: + { + cur = POOLSTART; + block = &blocks[POOLSTART]; + memhandle next; + while ((next = block->nextblock) != NOBLOCK) + { + memaddress dest = block->begin + block->size; + memblock* nextblock = &blocks[next]; + memaddress* src = &nextblock->begin; + if (dest != *src) + { +#ifdef MEMPOOL_MEMBLOCK_MV + MEMPOOL_MEMBLOCK_MV(dest,*src,nextblock->size); +#endif + *src = dest; + } + block = nextblock; + } + if (blocks[POOLSTART].begin + MEMPOOL_SIZE - block->begin - block->size >= size) + best = block; + else + goto notfound; + } + + found: + { + block = &blocks[POOLOFFSET]; + for (cur = POOLOFFSET; cur < MEMPOOL_NUM_MEMBLOCKS + POOLOFFSET; cur++) + { + if (block->size) + { + block++; + continue; + } + memaddress address = best->begin + best->size; +#ifdef MEMBLOCK_ALLOC + MEMBLOCK_ALLOC(address,size); +#endif + block->begin = address; + block->size = size; + block->nextblock = best->nextblock; + best->nextblock = cur; + return cur; + } + } + + notfound: return NOBLOCK; +} + +void +MemoryPool::freeBlock(memhandle handle) +{ + if (handle == NOBLOCK) + return; + memblock *b = &blocks[POOLSTART]; + + do + { + memhandle next = b->nextblock; + if (next == handle) + { + memblock *f = &blocks[next]; +#ifdef MEMBLOCK_FREE + MEMBLOCK_FREE(f->begin,f->size); +#endif + b->nextblock = f->nextblock; + f->size = 0; + f->nextblock = NOBLOCK; + return; + } + if (next == NOBLOCK) + return; + b = &blocks[next]; + } + while (true); +} + +void +MemoryPool::resizeBlock(memhandle handle, memaddress position) +{ + memblock * block = &blocks[handle]; + block->begin += position; + block->size -= position; +} + +void +MemoryPool::resizeBlock(memhandle handle, memaddress position, memaddress size) +{ + memblock * block = &blocks[handle]; + block->begin += position; + block->size = size; +} + +memaddress +MemoryPool::blockSize(memhandle handle) +{ + return blocks[handle].size; +} diff --git a/STM32F4/libraries/arduino_uip/utility/mempool.h b/STM32F4/libraries/arduino_uip/utility/mempool.h new file mode 100644 index 0000000..2a1db21 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/mempool.h @@ -0,0 +1,54 @@ +/* + mempool.h - sleek implementation of a memory pool + Copyright (c) 2013 Norbert Truchsess + All rights reserved. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#ifndef MEMPOOL_H +#define MEMPOOL_H + +#include + +#define POOLSTART 0 +#define NOBLOCK 0 + +#include "mempool_conf.h" + +struct memblock +{ + memaddress begin; + memaddress size; + memhandle nextblock; +}; + +class MemoryPool +{ +#ifdef MEMPOOLTEST_H + friend class MemoryPoolTest; +#endif + +protected: + static struct memblock blocks[MEMPOOL_NUM_MEMBLOCKS+1]; + +public: + static void init(); + static memhandle allocBlock(memaddress); + static void freeBlock(memhandle); + static void resizeBlock(memhandle handle, memaddress position); + static void resizeBlock(memhandle handle, memaddress position, memaddress size); + static memaddress blockSize(memhandle); +}; +#endif diff --git a/STM32F4/libraries/arduino_uip/utility/mempool_conf.h b/STM32F4/libraries/arduino_uip/utility/mempool_conf.h new file mode 100644 index 0000000..9615f92 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/mempool_conf.h @@ -0,0 +1,34 @@ +#ifndef MEMPOOLCONF_H +#define MEMPOOLCONF_H +#include "uipethernet-conf.h" +extern "C" { + #include "uipopt.h" + #include "enc28j60.h" +} +#include + +typedef uint16_t memaddress; +typedef uint8_t memhandle; + +#if UIP_SOCKET_NUMPACKETS and UIP_CONNS +#define NUM_TCP_MEMBLOCKS (UIP_SOCKET_NUMPACKETS*2)*UIP_CONNS +#else +#define NUM_TCP_MEMBLOCKS 0 +#endif + +#if UIP_UDP and UIP_UDP_CONNS +#define NUM_UDP_MEMBLOCKS 3*UIP_UDP_CONNS +#else +#define NUM_UDP_MEMBLOCKS 0 +#endif + +#define MEMPOOL_NUM_MEMBLOCKS (NUM_TCP_MEMBLOCKS+NUM_UDP_MEMBLOCKS) + +#define MEMPOOL_STARTADDRESS TXSTART_INIT+1 +#define MEMPOOL_SIZE TXSTOP_INIT-TXSTART_INIT + +void enc28J60_mempool_block_move_callback(memaddress,memaddress,memaddress); + +#define MEMPOOL_MEMBLOCK_MV(dest,src,size) enc28J60_mempool_block_move_callback(dest,src,size) + +#endif diff --git a/STM32F4/libraries/arduino_uip/utility/uip-conf.h b/STM32F4/libraries/arduino_uip/utility/uip-conf.h new file mode 100644 index 0000000..814aeb9 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip-conf.h @@ -0,0 +1,185 @@ +/** + * UIPEthernet Project-specific configuration options + * Copyright (c) 2013 Norbert Truchsess + * @{ + * + * uIP has a number of configuration options that can be overridden + * for each project. These are kept in a project-specific uip-conf.h + * file and all configuration names have the prefix UIP_CONF. + */ + +/* + * Copyright (c) 2006, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + */ + +#ifndef __UIP_CONF_H__ +#define __UIP_CONF_H__ + +#include +#include "uipethernet-conf.h" + +/** + * 8 bit datatype + * + * This typedef defines the 8-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint8_t u8_t; + +/** + * 16 bit datatype + * + * This typedef defines the 16-bit type used throughout uIP. + * + * \hideinitializer + */ +typedef uint16_t u16_t; + +/** + * Statistics datatype + * + * This typedef defines the dataype used for keeping statistics in + * uIP. + * + * \hideinitializer + */ +typedef unsigned short uip_stats_t; + +/** + * Maximum number of TCP connections. + * (see uipethernet-conf.h) + * \hideinitializer + * + * #define UIP_CONF_MAX_CONNECTIONS 4 + */ + +/** + * Maximum number of listening TCP ports. + * + * \hideinitializer + */ +#define UIP_CONF_MAX_LISTENPORTS 4 + +/** + * uIP buffer size. + * + * \hideinitializer + */ +#define UIP_CONF_BUFFER_SIZE 98 +//#define UIP_CONF_BUFFER_SIZE 118 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ + +#define UIP_CONF_TCP_MSS 512 + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#define UIP_CONF_RECEIVE_WINDOW 512 + +/** + * CPU byte order. + * + * \hideinitializer + */ +#define UIP_CONF_BYTE_ORDER LITTLE_ENDIAN + +/** + * Logging on or off + * + * \hideinitializer + */ +#define UIP_CONF_LOGGING 0 + +/** + * UDP support on or off + * (see uipethernet-conf.h) + * \hideinitializer + * + * #define UIP_CONF_UDP 1 + * + * #define UIP_CONF_UDP_CONNS 4 + */ + +/** + * UDP checksums on or off + * + * \hideinitializer + */ +#define UIP_CONF_UDP_CHECKSUMS 1 + +/** + * UDP Broadcast (receive) on or off + * (see uipethernet-conf.h) + * \hideinitializer + * #define UIP_CONF_BROADCAST 1 + */ + + +/** + * uIP statistics on or off + * + * \hideinitializer + */ +#define UIP_CONF_STATISTICS 0 + +// SLIP +//#define UIP_CONF_LLH_LEN 0 + +typedef void* uip_tcp_appstate_t; + +void uipclient_appcall(void); + +#define UIP_APPCALL uipclient_appcall + +typedef void* uip_udp_appstate_t; + +void uipudp_appcall(void); + +#define UIP_UDP_APPCALL uipudp_appcall + +#define CC_REGISTER_ARG register + +#define UIP_ARCH_CHKSUM 1 + +#endif /* __UIP_CONF_H__ */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip.c b/STM32F4/libraries/arduino_uip/utility/uip.c new file mode 100644 index 0000000..84ea8c3 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip.c @@ -0,0 +1,1897 @@ +#define DEBUG_PRINTF(...) /*printf(__VA_ARGS__)*/ + +/** + * \defgroup uip The uIP TCP/IP stack + * @{ + * + * uIP is an implementation of the TCP/IP protocol stack intended for + * small 8-bit and 16-bit microcontrollers. + * + * uIP provides the necessary protocols for Internet communication, + * with a very small code footprint and RAM requirements - the uIP + * code size is on the order of a few kilobytes and RAM usage is on + * the order of a few hundred bytes. + */ + +/** + * \file + * The uIP TCP/IP stack code. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.c,v 1.65 2006/06/11 21:46:39 adam Exp $ + * + */ + +/* + * uIP is a small implementation of the IP, UDP and TCP protocols (as + * well as some basic ICMP stuff). The implementation couples the IP, + * UDP, TCP and the application layers very tightly. To keep the size + * of the compiled code down, this code frequently uses the goto + * statement. While it would be possible to break the uip_process() + * function into many smaller functions, this would increase the code + * size because of the overhead of parameter passing and the fact that + * the optimier would not be as efficient. + * + * The principle is that we have a small buffer, called the uip_buf, + * in which the device driver puts an incoming packet. The TCP/IP + * stack parses the headers in the packet, and calls the + * application. If the remote host has sent data to the application, + * this data is present in the uip_buf and the application read the + * data from there. It is up to the application to put this data into + * a byte stream if needed. The application will not be fed with data + * that is out of sequence. + * + * If the application whishes to send data to the peer, it should put + * its data into the uip_buf. The uip_appdata pointer points to the + * first available byte. The TCP/IP stack will calculate the + * checksums, and fill in the necessary header fields and finally send + * the packet back to the peer. +*/ + +#include "uip.h" +#include "uipopt.h" +#include "uip_arch.h" + +#if UIP_CONF_IPV6 +#include "uip-neighbor.h" +#endif /* UIP_CONF_IPV6 */ + +#include + +/*---------------------------------------------------------------------------*/ +/* Variable definitions. */ + + +/* The IP address of this host. If it is defined to be fixed (by + setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set + here. Otherwise, the address */ +#if UIP_FIXEDADDR > 0 +const uip_ipaddr_t uip_hostaddr = + {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1), + HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)}; +const uip_ipaddr_t uip_draddr = + {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1), + HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)}; +const uip_ipaddr_t uip_netmask = + {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1), + HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)}; +#else +uip_ipaddr_t uip_hostaddr, uip_draddr, uip_netmask; +#endif /* UIP_FIXEDADDR */ + +static const uip_ipaddr_t all_ones_addr = +#if UIP_CONF_IPV6 + {0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff}; +#else /* UIP_CONF_IPV6 */ + {0xffff,0xffff}; +#endif /* UIP_CONF_IPV6 */ +static const uip_ipaddr_t all_zeroes_addr = +#if UIP_CONF_IPV6 + {0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000}; +#else /* UIP_CONF_IPV6 */ + {0x0000,0x0000}; +#endif /* UIP_CONF_IPV6 */ + + +#if UIP_FIXEDETHADDR +const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0, + UIP_ETHADDR1, + UIP_ETHADDR2, + UIP_ETHADDR3, + UIP_ETHADDR4, + UIP_ETHADDR5}}; +#else +struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +#endif + +#ifndef UIP_CONF_EXTERNAL_BUFFER +u8_t uip_buf[UIP_BUFSIZE + 2]; /* The packet buffer that contains + incoming packets. */ +#endif /* UIP_CONF_EXTERNAL_BUFFER */ + +void *uip_appdata; /* The uip_appdata pointer points to + application data. */ +void *uip_sappdata; /* The uip_appdata pointer points to + the application data which is to + be sent. */ +#if UIP_URGDATA > 0 +void *uip_urgdata; /* The uip_urgdata pointer points to + urgent data (out-of-band data), if + present. */ +u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + +u16_t uip_len, uip_slen; + /* The uip_len is either 8 or 16 bits, + depending on the maximum packet + size. */ + +u8_t uip_flags; /* The uip_flags variable is used for + communication between the TCP/IP stack + and the application program. */ +struct uip_conn *uip_conn; /* uip_conn always points to the current + connection. */ + +struct uip_conn uip_conns[UIP_CONNS]; + /* The uip_conns array holds all TCP + connections. */ +u16_t uip_listenports[UIP_LISTENPORTS]; + /* The uip_listenports list all currently + listning ports. */ +#if UIP_UDP +struct uip_udp_conn *uip_udp_conn; +struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +static u16_t ipid; /* Ths ipid variable is an increasing + number that is used for the IP ID + field. */ + +void uip_setipid(u16_t id) { ipid = id; } + +static u8_t iss[4]; /* The iss variable is used for the TCP + initial sequence number. */ + +#if UIP_ACTIVE_OPEN +static u16_t lastport; /* Keeps track of the last port used for + a new connection. */ +#endif /* UIP_ACTIVE_OPEN */ + +/* Temporary variables. */ +u8_t uip_acc32[4]; +static u8_t c, opt; +static u16_t tmp16; + +/* Structures and definitions. */ +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 +#define TCP_PSH 0x08 +#define TCP_ACK 0x10 +#define TCP_URG 0x20 +#define TCP_CTL 0x3f + +#define TCP_OPT_END 0 /* End of TCP options list */ +#define TCP_OPT_NOOP 1 /* "No-operation" TCP option */ +#define TCP_OPT_MSS 2 /* Maximum segment size TCP option */ + +#define TCP_OPT_MSS_LEN 4 /* Length of TCP MSS option. */ + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 + +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 +#define ICMP6_NEIGHBOR_SOLICITATION 135 +#define ICMP6_NEIGHBOR_ADVERTISEMENT 136 + +#define ICMP6_FLAG_S (1 << 6) + +#define ICMP6_OPTION_SOURCE_LINK_ADDRESS 1 +#define ICMP6_OPTION_TARGET_LINK_ADDRESS 2 + + +/* Macros. */ +#define BUF ((struct uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define FBUF ((struct uip_tcpip_hdr *)&uip_reassbuf[0]) +#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN]) +#define UDPBUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) + + +#if UIP_STATISTICS == 1 +struct uip_stats uip_stat; +#define UIP_STAT(s) s +#else +#define UIP_STAT(s) +#endif /* UIP_STATISTICS == 1 */ + +#if UIP_LOGGING == 1 +#include +void uip_log(char *msg); +#define UIP_LOG(m) uip_log(m) +#else +#define UIP_LOG(m) +#endif /* UIP_LOGGING == 1 */ + +#if ! UIP_ARCH_ADD32 +void +uip_add32(u8_t *op32, u16_t op16) +{ + uip_acc32[3] = op32[3] + (op16 & 0xff); + uip_acc32[2] = op32[2] + (op16 >> 8); + uip_acc32[1] = op32[1]; + uip_acc32[0] = op32[0]; + + if(uip_acc32[2] < (op16 >> 8)) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + + + if(uip_acc32[3] < (op16 & 0xff)) { + ++uip_acc32[2]; + if(uip_acc32[2] == 0) { + ++uip_acc32[1]; + if(uip_acc32[1] == 0) { + ++uip_acc32[0]; + } + } + } +} + +#endif /* UIP_ARCH_ADD32 */ + +#if ! UIP_ARCH_CHKSUM +/*---------------------------------------------------------------------------*/ +static u16_t +chksum(u16_t sum, const u8_t *data, u16_t len) +{ + u16_t t; + const u8_t *dataptr; + const u8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} +/*---------------------------------------------------------------------------*/ +u16_t +uip_chksum(u16_t *data, u16_t len) +{ + return htons(chksum(0, (u8_t *)data, len)); +} +/*---------------------------------------------------------------------------*/ +#ifndef UIP_ARCH_IPCHKSUM +u16_t +uip_ipchksum(void) +{ + u16_t sum; + + sum = chksum(0, &uip_buf[UIP_LLH_LEN], UIP_IPH_LEN); + DEBUG_PRINTF("uip_ipchksum: sum 0x%04x\n", sum); + return (sum == 0) ? 0xffff : htons(sum); +} +#endif +/*---------------------------------------------------------------------------*/ +static u16_t +upper_layer_chksum(u8_t proto) +{ + u16_t upper_layer_len; + u16_t sum; + +#if UIP_CONF_IPV6 + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]); +#else /* UIP_CONF_IPV6 */ + upper_layer_len = (((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - UIP_IPH_LEN; +#endif /* UIP_CONF_IPV6 */ + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = upper_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (u8_t *)&BUF->srcipaddr[0], 2 * sizeof(uip_ipaddr_t)); + + /* Sum TCP header and data. */ + sum = chksum(sum, &uip_buf[UIP_IPH_LEN + UIP_LLH_LEN], + upper_layer_len); + + return (sum == 0) ? 0xffff : htons(sum); +} +/*---------------------------------------------------------------------------*/ +#if UIP_CONF_IPV6 +u16_t +uip_icmp6chksum(void) +{ + return upper_layer_chksum(UIP_PROTO_ICMP6); + +} +#endif /* UIP_CONF_IPV6 */ +/*---------------------------------------------------------------------------*/ +u16_t +uip_tcpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_TCP); +} +/*---------------------------------------------------------------------------*/ +#if UIP_UDP_CHECKSUMS +u16_t +uip_udpchksum(void) +{ + return upper_layer_chksum(UIP_PROTO_UDP); +} +#endif /* UIP_UDP_CHECKSUMS */ +#endif /* UIP_ARCH_CHKSUM */ +/*---------------------------------------------------------------------------*/ +void +uip_init(void) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + uip_listenports[c] = 0; + } + for(c = 0; c < UIP_CONNS; ++c) { + uip_conns[c].tcpstateflags = UIP_CLOSED; + } +#if UIP_ACTIVE_OPEN + lastport = 1024; +#endif /* UIP_ACTIVE_OPEN */ + +#if UIP_UDP + for(c = 0; c < UIP_UDP_CONNS; ++c) { + uip_udp_conns[c].lport = 0; + } +#endif /* UIP_UDP */ + + + /* IPv4 initialization. */ +#if UIP_FIXEDADDR == 0 + /* uip_hostaddr[0] = uip_hostaddr[1] = 0;*/ +#endif /* UIP_FIXEDADDR */ + +} +/*---------------------------------------------------------------------------*/ +#if UIP_ACTIVE_OPEN +struct uip_conn * +uip_connect(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_conn *conn, *cconn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + /* Check if this port is already in use, and if so try to find + another one. */ + for(c = 0; c < UIP_CONNS; ++c) { + conn = &uip_conns[c]; + if(conn->tcpstateflags != UIP_CLOSED && + conn->lport == htons(lastport)) { + goto again; + } + } + + conn = 0; + for(c = 0; c < UIP_CONNS; ++c) { + cconn = &uip_conns[c]; + if(cconn->tcpstateflags == UIP_CLOSED) { + conn = cconn; + break; + } + if(cconn->tcpstateflags == UIP_TIME_WAIT) { + if(conn == 0 || + cconn->timer > conn->timer) { + conn = cconn; + } + } + } + + if(conn == 0) { + return 0; + } + + conn->tcpstateflags = UIP_SYN_SENT; + + conn->snd_nxt[0] = iss[0]; + conn->snd_nxt[1] = iss[1]; + conn->snd_nxt[2] = iss[2]; + conn->snd_nxt[3] = iss[3]; + + conn->initialmss = conn->mss = UIP_TCP_MSS; + + conn->len = 1; /* TCP length of the SYN is one. */ + conn->nrtx = 0; + conn->timer = 1; /* Send the SYN next time around. */ + conn->rto = UIP_RTO; + conn->sa = 0; + conn->sv = 16; /* Initial value of the RTT variance. */ + conn->lport = htons(lastport); + conn->rport = rport; + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + + return conn; +} +#endif /* UIP_ACTIVE_OPEN */ +/*---------------------------------------------------------------------------*/ +#if UIP_UDP +struct uip_udp_conn * +uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport) +{ + register struct uip_udp_conn *conn; + + /* Find an unused local port. */ + again: + ++lastport; + + if(lastport >= 32000) { + lastport = 4096; + } + + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == htons(lastport)) { + goto again; + } + } + + + conn = 0; + for(c = 0; c < UIP_UDP_CONNS; ++c) { + if(uip_udp_conns[c].lport == 0) { + conn = &uip_udp_conns[c]; + break; + } + } + + if(conn == 0) { + return 0; + } + + conn->lport = HTONS(lastport); + conn->rport = rport; + if(ripaddr == NULL) { + memset(conn->ripaddr, 0, sizeof(uip_ipaddr_t)); + } else { + uip_ipaddr_copy(&conn->ripaddr, ripaddr); + } + conn->ttl = UIP_TTL; + + return conn; +} +#endif /* UIP_UDP */ +/*---------------------------------------------------------------------------*/ +void +uip_unlisten(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == port) { + uip_listenports[c] = 0; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +void +uip_listen(u16_t port) +{ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(uip_listenports[c] == 0) { + uip_listenports[c] = port; + return; + } + } +} +/*---------------------------------------------------------------------------*/ +/* XXX: IP fragment reassembly: not well-tested. */ + +#if UIP_REASSEMBLY && !UIP_CONF_IPV6 +#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN) +static u8_t uip_reassbuf[UIP_REASS_BUFSIZE]; +static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)]; +static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01}; +static u16_t uip_reasslen; +static u8_t uip_reassflags; +#define UIP_REASS_FLAG_LASTFRAG 0x01 +static u8_t uip_reasstmr; + +#define IP_MF 0x20 + +static u8_t +uip_reass(void) +{ + u16_t offset, len; + u16_t i; + + /* If ip_reasstmr is zero, no packet is present in the buffer, so we + write the IP header of the fragment into the reassembly + buffer. The timer is updated with the maximum age. */ + if(uip_reasstmr == 0) { + memcpy(uip_reassbuf, &BUF->vhl, UIP_IPH_LEN); + uip_reasstmr = UIP_REASS_MAXAGE; + uip_reassflags = 0; + /* Clear the bitmap. */ + memset(uip_reassbitmap, 0, sizeof(uip_reassbitmap)); + } + + /* Check if the incoming fragment matches the one currently present + in the reasembly buffer. If so, we proceed with copying the + fragment into the buffer. */ + if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] && + BUF->srcipaddr[1] == FBUF->srcipaddr[1] && + BUF->destipaddr[0] == FBUF->destipaddr[0] && + BUF->destipaddr[1] == FBUF->destipaddr[1] && + BUF->ipid[0] == FBUF->ipid[0] && + BUF->ipid[1] == FBUF->ipid[1]) { + + len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4; + offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8; + + /* If the offset or the offset + fragment length overflows the + reassembly buffer, we discard the entire packet. */ + if(offset > UIP_REASS_BUFSIZE || + offset + len > UIP_REASS_BUFSIZE) { + uip_reasstmr = 0; + goto nullreturn; + } + + /* Copy the fragment into the reassembly buffer, at the right + offset. */ + memcpy(&uip_reassbuf[UIP_IPH_LEN + offset], + (char *)BUF + (int)((BUF->vhl & 0x0f) * 4), + len); + + /* Update the bitmap. */ + if(offset / (8 * 8) == (offset + len) / (8 * 8)) { + /* If the two endpoints are in the same byte, we only update + that byte. */ + + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7] & + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } else { + /* If the two endpoints are in different bytes, we update the + bytes in the endpoints and fill the stuff inbetween with + 0xff. */ + uip_reassbitmap[offset / (8 * 8)] |= + bitmap_bits[(offset / 8 ) & 7]; + for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) { + uip_reassbitmap[i] = 0xff; + } + uip_reassbitmap[(offset + len) / (8 * 8)] |= + ~bitmap_bits[((offset + len) / 8 ) & 7]; + } + + /* If this fragment has the More Fragments flag set to zero, we + know that this is the last fragment, so we can calculate the + size of the entire packet. We also set the + IP_REASS_FLAG_LASTFRAG flag to indicate that we have received + the final fragment. */ + + if((BUF->ipoffset[0] & IP_MF) == 0) { + uip_reassflags |= UIP_REASS_FLAG_LASTFRAG; + uip_reasslen = offset + len; + } + + /* Finally, we check if we have a full packet in the buffer. We do + this by checking if we have the last fragment and if all bits + in the bitmap are set. */ + if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) { + /* Check all bytes up to and including all but the last byte in + the bitmap. */ + for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) { + if(uip_reassbitmap[i] != 0xff) { + goto nullreturn; + } + } + /* Check the last byte in the bitmap. It should contain just the + right amount of bits. */ + if(uip_reassbitmap[uip_reasslen / (8 * 8)] != + (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) { + goto nullreturn; + } + + /* If we have come this far, we have a full packet in the + buffer, so we allocate a pbuf and copy the packet into it. We + also reset the timer. */ + uip_reasstmr = 0; + memcpy(BUF, FBUF, uip_reasslen); + + /* Pretend to be a "normal" (i.e., not fragmented) IP packet + from now on. */ + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + BUF->len[0] = uip_reasslen >> 8; + BUF->len[1] = uip_reasslen & 0xff; + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + + return uip_reasslen; + } + } + + nullreturn: + return 0; +} +#endif /* UIP_REASSEMBLY */ +/*---------------------------------------------------------------------------*/ +static void +uip_add_rcv_nxt(u16_t n) +{ + uip_add32(uip_conn->rcv_nxt, n); + uip_conn->rcv_nxt[0] = uip_acc32[0]; + uip_conn->rcv_nxt[1] = uip_acc32[1]; + uip_conn->rcv_nxt[2] = uip_acc32[2]; + uip_conn->rcv_nxt[3] = uip_acc32[3]; +} +/*---------------------------------------------------------------------------*/ +void +uip_process(u8_t flag) +{ + register struct uip_conn *uip_connr = uip_conn; + +#if UIP_UDP + if(flag == UIP_UDP_SEND_CONN) { + goto udp_send; + } +#endif /* UIP_UDP */ + + uip_sappdata = uip_appdata = &uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN]; + + /* Check if we were invoked because of a poll request for a + particular connection. */ + if(flag == UIP_POLL_REQUEST) { + if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED && + !uip_outstanding(uip_connr)) { + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + goto drop; + + /* Check if we were invoked because of the perodic timer fireing. */ + } else if(flag == UIP_TIMER) { +#if UIP_REASSEMBLY + if(uip_reasstmr != 0) { + --uip_reasstmr; + } +#endif /* UIP_REASSEMBLY */ + /* Increase the initial sequence number. */ + if(++iss[3] == 0) { + if(++iss[2] == 0) { + if(++iss[1] == 0) { + ++iss[0]; + } + } + } + + /* Reset the length variables. */ + uip_len = 0; + uip_slen = 0; + + /* Check if the connection is in a state in which we simply wait + for the connection to time out. If so, we increase the + connection's timer and remove the connection if it times + out. */ + if(uip_connr->tcpstateflags == UIP_TIME_WAIT || + uip_connr->tcpstateflags == UIP_FIN_WAIT_2) { + ++(uip_connr->timer); + if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) { + uip_connr->tcpstateflags = UIP_CLOSED; + } + } else if(uip_connr->tcpstateflags != UIP_CLOSED) { + /* If the connection has outstanding data, we increase the + connection's timer and see if it has reached the RTO value + in which case we retransmit. */ + if(uip_outstanding(uip_connr)) { + if(uip_connr->timer-- == 0) { + if(uip_connr->nrtx == UIP_MAXRTX || + ((uip_connr->tcpstateflags == UIP_SYN_SENT || + uip_connr->tcpstateflags == UIP_SYN_RCVD) && + uip_connr->nrtx == UIP_MAXSYNRTX)) { + uip_connr->tcpstateflags = UIP_CLOSED; + + /* We call UIP_APPCALL() with uip_flags set to + UIP_TIMEDOUT to inform the application that the + connection has timed out. */ + uip_flags = UIP_TIMEDOUT; + UIP_APPCALL(); + + /* We also send a reset packet to the remote host. */ + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + /* Exponential backoff. */ + uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4? + 4: + uip_connr->nrtx); + ++(uip_connr->nrtx); + + /* Ok, so we need to retransmit. We do this differently + depending on which state we are in. In ESTABLISHED, we + call upon the application so that it may prepare the + data for the retransmit. In SYN_RCVD, we resend the + SYNACK that we sent earlier and in LAST_ACK we have to + retransmit our FINACK. */ + UIP_STAT(++uip_stat.tcp.rexmit); + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + case UIP_SYN_RCVD: + /* In the SYN_RCVD state, we should retransmit our + SYNACK. */ + goto tcp_send_synack; + +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In the SYN_SENT state, we retransmit out SYN. */ + BUF->flags = 0; + goto tcp_send_syn; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application + to do the actual retransmit after which we jump into + the code for sending out the packet (the apprexmit + label). */ + uip_flags = UIP_REXMIT; + UIP_APPCALL(); + goto apprexmit; + + case UIP_FIN_WAIT_1: + case UIP_CLOSING: + case UIP_LAST_ACK: + /* In all these states we should retransmit a FINACK. */ + goto tcp_send_finack; + + } + } + } else if((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_ESTABLISHED) { + /* If there was no need for a retransmission, we poll the + application for new data. */ + uip_flags = UIP_POLL; + UIP_APPCALL(); + goto appsend; + } + } + goto drop; + } +#if UIP_UDP + if(flag == UIP_UDP_TIMER) { + if(uip_udp_conn->lport != 0) { + uip_conn = NULL; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_len = uip_slen = 0; + uip_flags = UIP_POLL; + UIP_UDP_APPCALL(); + goto udp_send; + } else { + goto drop; + } + } +#endif + + /* This is where the input processing starts. */ + UIP_STAT(++uip_stat.ip.recv); + + /* Start of IP input header processing code. */ + +#if UIP_CONF_IPV6 + /* Check validity of the IP header. */ + if((BUF->vtc & 0xf0) != 0x60) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ipv6: invalid version."); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* Check validity of the IP header. */ + if(BUF->vhl != 0x45) { /* IP version and header length. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.vhlerr); + UIP_LOG("ip: invalid version or header length."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + /* Check the size of the packet. If the size reported to us in + uip_len is smaller the size reported in the IP header, we assume + that the packet has been corrupted in transit. If the size of + uip_len is larger than the size reported in the IP packet header, + the packet has been padded and we set uip_len to the correct + value.. */ + + if((BUF->len[0] << 8) + BUF->len[1] <= uip_len) { + uip_len = (BUF->len[0] << 8) + BUF->len[1]; +#if UIP_CONF_IPV6 + uip_len += 40; /* The length reported in the IPv6 header is the + length of the payload that follows the + header. However, uIP uses the uip_len variable + for holding the size of the entire packet, + including the IP header. For IPv4 this is not a + problem as the length field in the IPv4 header + contains the length of the entire packet. But + for IPv6 we need to add the size of the IPv6 + header (40 bytes). */ +#endif /* UIP_CONF_IPV6 */ + } else { + UIP_LOG("ip: packet shorter than reported in IP header."); + goto drop; + } + +#if !UIP_CONF_IPV6 + /* Check the fragment flag. */ + if((BUF->ipoffset[0] & 0x3f) != 0 || + BUF->ipoffset[1] != 0) { +#if UIP_REASSEMBLY + uip_len = uip_reass(); + if(uip_len == 0) { + goto drop; + } +#else /* UIP_REASSEMBLY */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.fragerr); + UIP_LOG("ip: fragment dropped."); + goto drop; +#endif /* UIP_REASSEMBLY */ + } +#endif /* UIP_CONF_IPV6 */ + + if(uip_ipaddr_cmp(uip_hostaddr, all_zeroes_addr)) { + /* If we are configured to use ping IP address configuration and + hasn't been assigned an IP address yet, we accept all ICMP + packets. */ +#if UIP_PINGADDRCONF && !UIP_CONF_IPV6 + if(BUF->proto == UIP_PROTO_ICMP) { + UIP_LOG("ip: possible ping config packet received."); + goto icmp_input; + } else { + UIP_LOG("ip: packet dropped since no address assigned."); + goto drop; + } +#endif /* UIP_PINGADDRCONF */ + + } else { + /* If IP broadcast support is configured, we check for a broadcast + UDP packet, which may be destined to us. */ +#if UIP_BROADCAST + DEBUG_PRINTF("UDP IP checksum 0x%04x\n", uip_ipchksum()); + if(BUF->proto == UIP_PROTO_UDP && + uip_ipaddr_cmp(BUF->destipaddr, all_ones_addr) + /*&& + uip_ipchksum() == 0xffff*/) { + goto udp_input; + } +#endif /* UIP_BROADCAST */ + + /* Check if the packet is destined for our IP address. */ +#if !UIP_CONF_IPV6 + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#else /* UIP_CONF_IPV6 */ + /* For IPv6, packet reception is a little trickier as we need to + make sure that we listen to certain multicast addresses (all + hosts multicast address, and the solicited-node multicast + address) as well. However, we will cheat here and accept all + multicast packets that are sent to the ff02::/16 addresses. */ + if(!uip_ipaddr_cmp(BUF->destipaddr, uip_hostaddr) && + BUF->destipaddr[0] != HTONS(0xff02)) { + UIP_STAT(++uip_stat.ip.drop); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + } + +#if !UIP_CONF_IPV6 + if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header + checksum. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.chkerr); + UIP_LOG("ip: bad checksum."); + goto drop; + } +#endif /* UIP_CONF_IPV6 */ + + if(BUF->proto == UIP_PROTO_TCP) { /* Check for TCP packet. If so, + proceed with TCP input + processing. */ + goto tcp_input; + } + +#if UIP_UDP + if(BUF->proto == UIP_PROTO_UDP) { + goto udp_input; + } +#endif /* UIP_UDP */ + +#if !UIP_CONF_IPV6 + /* ICMPv4 processing code follows. */ + if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp."); + goto drop; + } + +#if UIP_PINGADDRCONF + icmp_input: +#endif /* UIP_PINGADDRCONF */ + UIP_STAT(++uip_stat.icmp.recv); + + /* ICMP echo (i.e., ping) processing. This is simple, we only change + the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP + checksum before we return the packet. */ + if(ICMPBUF->type != ICMP_ECHO) { + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: not icmp echo."); + goto drop; + } + + /* If we are configured to use ping IP address assignment, we use + the destination IP address of this ping packet and assign it to + ourself. */ +#if UIP_PINGADDRCONF + if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) { + uip_hostaddr[0] = BUF->destipaddr[0]; + uip_hostaddr[1] = BUF->destipaddr[1]; + } +#endif /* UIP_PINGADDRCONF */ + + ICMPBUF->type = ICMP_ECHO_REPLY; + + if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1; + } else { + ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8); + } + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + + /* End of IPv4 input header processing code. */ +#else /* !UIP_CONF_IPV6 */ + + /* This is IPv6 ICMPv6 processing code. */ + DEBUG_PRINTF("icmp6_input: length %d\n", uip_len); + + if(BUF->proto != UIP_PROTO_ICMP6) { /* We only allow ICMPv6 packets from + here. */ + UIP_STAT(++uip_stat.ip.drop); + UIP_STAT(++uip_stat.ip.protoerr); + UIP_LOG("ip: neither tcp nor icmp6."); + goto drop; + } + + UIP_STAT(++uip_stat.icmp.recv); + + /* If we get a neighbor solicitation for our address we should send + a neighbor advertisement message back. */ + if(ICMPBUF->type == ICMP6_NEIGHBOR_SOLICITATION) { + if(uip_ipaddr_cmp(ICMPBUF->icmp6data, uip_hostaddr)) { + + if(ICMPBUF->options[0] == ICMP6_OPTION_SOURCE_LINK_ADDRESS) { + /* Save the sender's address in our neighbor list. */ + uip_neighbor_add(ICMPBUF->srcipaddr, &(ICMPBUF->options[2])); + } + + /* We should now send a neighbor advertisement back to where the + neighbor solicication came from. */ + ICMPBUF->type = ICMP6_NEIGHBOR_ADVERTISEMENT; + ICMPBUF->flags = ICMP6_FLAG_S; /* Solicited flag. */ + + ICMPBUF->reserved1 = ICMPBUF->reserved2 = ICMPBUF->reserved3 = 0; + + uip_ipaddr_copy(ICMPBUF->destipaddr, ICMPBUF->srcipaddr); + uip_ipaddr_copy(ICMPBUF->srcipaddr, uip_hostaddr); + ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; + ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ + memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + goto send; + + } + goto drop; + } else if(ICMPBUF->type == ICMP6_ECHO) { + /* ICMP echo (i.e., ping) processing. This is simple, we only + change the ICMP type from ECHO to ECHO_REPLY and update the + ICMP checksum before we return the packet. */ + + ICMPBUF->type = ICMP6_ECHO_REPLY; + + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + ICMPBUF->icmpchksum = 0; + ICMPBUF->icmpchksum = ~uip_icmp6chksum(); + + UIP_STAT(++uip_stat.icmp.sent); + goto send; + } else { + DEBUG_PRINTF("Unknown icmp6 message type %d\n", ICMPBUF->type); + UIP_STAT(++uip_stat.icmp.drop); + UIP_STAT(++uip_stat.icmp.typeerr); + UIP_LOG("icmp: unknown ICMP message."); + goto drop; + } + + /* End of IPv6 ICMP processing. */ + +#endif /* !UIP_CONF_IPV6 */ + +#if UIP_UDP + /* UDP input processing. */ + udp_input: + /* UDP processing is really just a hack. We don't do anything to the + UDP/IP headers, but let the UDP application do all the hard + work. If the application sets uip_slen, it has a packet to + send. */ +#if UIP_UDP_CHECKSUMS + uip_len = uip_len - UIP_IPUDPH_LEN; + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + if(UDPBUF->udpchksum != 0 && uip_udpchksum() != 0xffff) { + UIP_STAT(++uip_stat.udp.drop); + UIP_STAT(++uip_stat.udp.chkerr); + UIP_LOG("udp: bad checksum."); + goto drop; + } +#else /* UIP_UDP_CHECKSUMS */ + uip_len = uip_len - UIP_IPUDPH_LEN; +#endif /* UIP_UDP_CHECKSUMS */ + + /* Demultiplex this UDP packet between the UDP "connections". */ + for(uip_udp_conn = &uip_udp_conns[0]; + uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS]; + ++uip_udp_conn) { + /* If the local UDP port is non-zero, the connection is considered + to be used. If so, the local port number is checked against the + destination port number in the received packet. If the two port + numbers match, the remote port number is checked if the + connection is bound to a remote port. Finally, if the + connection is bound to a remote IP address, the source IP + address of the packet is checked. */ + if(uip_udp_conn->lport != 0 && + UDPBUF->destport == uip_udp_conn->lport && + (uip_udp_conn->rport == 0 || + UDPBUF->srcport == uip_udp_conn->rport) && + (uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_zeroes_addr) || + uip_ipaddr_cmp(uip_udp_conn->ripaddr, all_ones_addr) || + uip_ipaddr_cmp(BUF->srcipaddr, uip_udp_conn->ripaddr))) { + goto udp_found; + } + } + UIP_LOG("udp: no matching connection found"); + goto drop; + + udp_found: + uip_conn = NULL; + uip_flags = UIP_NEWDATA; + uip_sappdata = uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPUDPH_LEN]; + uip_slen = 0; + UIP_UDP_APPCALL(); + udp_send: + if(uip_slen == 0) { + goto drop; + } + uip_len = uip_slen + UIP_IPUDPH_LEN; + +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->ttl = uip_udp_conn->ttl; + BUF->proto = UIP_PROTO_UDP; + + UDPBUF->udplen = HTONS(uip_slen + UIP_UDPH_LEN); + UDPBUF->udpchksum = 0; + + BUF->srcport = uip_udp_conn->lport; + BUF->destport = uip_udp_conn->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_udp_conn->ripaddr); + + uip_appdata = &uip_buf[UIP_LLH_LEN + UIP_IPTCPH_LEN]; + +#if UIP_UDP_CHECKSUMS + /* Calculate UDP checksum. */ + UDPBUF->udpchksum = ~(uip_udpchksum()); + if(UDPBUF->udpchksum == 0) { + UDPBUF->udpchksum = 0xffff; + } +#endif /* UIP_UDP_CHECKSUMS */ + + goto ip_send_nolen; +#endif /* UIP_UDP */ + + /* TCP input processing. */ + tcp_input: + UIP_STAT(++uip_stat.tcp.recv); + + /* Start of TCP input header processing code. */ + + if(uip_tcpchksum() != 0xffff) { /* Compute and check the TCP + checksum. */ + UIP_STAT(++uip_stat.tcp.drop); + UIP_STAT(++uip_stat.tcp.chkerr); + UIP_LOG("tcp: bad checksum."); + goto drop; + } + + + /* Demultiplex this segment. */ + /* First check any active connections. */ + for(uip_connr = &uip_conns[0]; uip_connr <= &uip_conns[UIP_CONNS - 1]; + ++uip_connr) { + if(uip_connr->tcpstateflags != UIP_CLOSED && + BUF->destport == uip_connr->lport && + BUF->srcport == uip_connr->rport && + uip_ipaddr_cmp(BUF->srcipaddr, uip_connr->ripaddr)) { + goto found; + } + } + + /* If we didn't find and active connection that expected the packet, + either this packet is an old duplicate, or this is a SYN packet + destined for a connection in LISTEN. If the SYN flag isn't set, + it is an old packet and we send a RST. */ + if((BUF->flags & TCP_CTL) != TCP_SYN) { + goto reset; + } + + tmp16 = BUF->destport; + /* Next, check listening connections. */ + for(c = 0; c < UIP_LISTENPORTS; ++c) { + if(tmp16 == uip_listenports[c]) + goto found_listen; + } + + /* No matching connection found, so we send a RST packet. */ + UIP_STAT(++uip_stat.tcp.synrst); + reset: + + /* We do not send resets in response to resets. */ + if(BUF->flags & TCP_RST) { + goto drop; + } + + UIP_STAT(++uip_stat.tcp.rst); + + BUF->flags = TCP_RST | TCP_ACK; + uip_len = UIP_IPTCPH_LEN; + BUF->tcpoffset = 5 << 4; + + /* Flip the seqno and ackno fields in the TCP header. */ + c = BUF->seqno[3]; + BUF->seqno[3] = BUF->ackno[3]; + BUF->ackno[3] = c; + + c = BUF->seqno[2]; + BUF->seqno[2] = BUF->ackno[2]; + BUF->ackno[2] = c; + + c = BUF->seqno[1]; + BUF->seqno[1] = BUF->ackno[1]; + BUF->ackno[1] = c; + + c = BUF->seqno[0]; + BUF->seqno[0] = BUF->ackno[0]; + BUF->ackno[0] = c; + + /* We also have to increase the sequence number we are + acknowledging. If the least significant byte overflowed, we need + to propagate the carry to the other bytes as well. */ + if(++BUF->ackno[3] == 0) { + if(++BUF->ackno[2] == 0) { + if(++BUF->ackno[1] == 0) { + ++BUF->ackno[0]; + } + } + } + + /* Swap port numbers. */ + tmp16 = BUF->srcport; + BUF->srcport = BUF->destport; + BUF->destport = tmp16; + + /* Swap IP addresses. */ + uip_ipaddr_copy(BUF->destipaddr, BUF->srcipaddr); + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + + /* And send out the RST packet! */ + goto tcp_send_noconn; + + /* This label will be jumped to if we matched the incoming packet + with a connection in LISTEN. In that case, we should create a new + connection and send a SYNACK in return. */ + found_listen: + /* First we check if there are any connections avaliable. Unused + connections are kept in the same table as used connections, but + unused ones have the tcpstate set to CLOSED. Also, connections in + TIME_WAIT are kept track of and we'll use the oldest one if no + CLOSED connections are found. Thanks to Eddie C. Dost for a very + nice algorithm for the TIME_WAIT search. */ + uip_connr = 0; + for(c = 0; c < UIP_CONNS; ++c) { + if(uip_conns[c].tcpstateflags == UIP_CLOSED) { + uip_connr = &uip_conns[c]; + break; + } + if(uip_conns[c].tcpstateflags == UIP_TIME_WAIT) { + if(uip_connr == 0 || + uip_conns[c].timer > uip_connr->timer) { + uip_connr = &uip_conns[c]; + } + } + } + + if(uip_connr == 0) { + /* All connections are used already, we drop packet and hope that + the remote end will retransmit the packet at a time when we + have more spare connections. */ + UIP_STAT(++uip_stat.tcp.syndrop); + UIP_LOG("tcp: found no unused connections."); + goto drop; + } + uip_conn = uip_connr; + + /* Fill in the necessary fields for the new connection. */ + uip_connr->rto = uip_connr->timer = UIP_RTO; + uip_connr->sa = 0; + uip_connr->sv = 4; + uip_connr->nrtx = 0; + uip_connr->lport = BUF->destport; + uip_connr->rport = BUF->srcport; + uip_ipaddr_copy(uip_connr->ripaddr, BUF->srcipaddr); + uip_connr->tcpstateflags = UIP_SYN_RCVD; + + uip_connr->snd_nxt[0] = iss[0]; + uip_connr->snd_nxt[1] = iss[1]; + uip_connr->snd_nxt[2] = iss[2]; + uip_connr->snd_nxt[3] = iss[3]; + uip_connr->len = 1; + + /* rcv_nxt should be the seqno from the incoming packet + 1. */ + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_add_rcv_nxt(1); + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = ((u16_t)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + (u16_t)uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = uip_connr->mss = + tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + + /* Our response will be a SYNACK. */ +#if UIP_ACTIVE_OPEN + tcp_send_synack: + BUF->flags = TCP_ACK; + + tcp_send_syn: + BUF->flags |= TCP_SYN; +#else /* UIP_ACTIVE_OPEN */ + tcp_send_synack: + BUF->flags = TCP_SYN | TCP_ACK; +#endif /* UIP_ACTIVE_OPEN */ + + /* We send out the TCP Maximum Segment Size option with our + SYNACK. */ + BUF->optdata[0] = TCP_OPT_MSS; + BUF->optdata[1] = TCP_OPT_MSS_LEN; + BUF->optdata[2] = (UIP_TCP_MSS) / 256; + BUF->optdata[3] = (UIP_TCP_MSS) & 255; + uip_len = UIP_IPTCPH_LEN + TCP_OPT_MSS_LEN; + BUF->tcpoffset = ((UIP_TCPH_LEN + TCP_OPT_MSS_LEN) / 4) << 4; + goto tcp_send; + + /* This label will be jumped to if we found an active connection. */ + found: + uip_conn = uip_connr; + uip_flags = 0; + /* We do a very naive form of TCP reset processing; we just accept + any RST and kill our connection. We should in fact check if the + sequence number of this reset is wihtin our advertised window + before we accept the reset. */ + if(BUF->flags & TCP_RST) { + uip_connr->tcpstateflags = UIP_CLOSED; + UIP_LOG("tcp: got reset, aborting connection."); + uip_flags = UIP_ABORT; + UIP_APPCALL(); + goto drop; + } + /* Calculated the length of the data, if the application has sent + any data to us. */ + c = (BUF->tcpoffset >> 4) << 2; + /* uip_len will contain the length of the actual TCP data. This is + calculated by subtracing the length of the TCP header (in + c) and the length of the IP header (20 bytes). */ + uip_len = uip_len - c - UIP_IPH_LEN; + + /* First, check if the sequence number of the incoming packet is + what we're expecting next. If not, we send out an ACK with the + correct numbers in. */ + if(!(((uip_connr->tcpstateflags & UIP_TS_MASK) == UIP_SYN_SENT) && + ((BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)))) { + if((uip_len > 0 || ((BUF->flags & (TCP_SYN | TCP_FIN)) != 0)) && + (BUF->seqno[0] != uip_connr->rcv_nxt[0] || + BUF->seqno[1] != uip_connr->rcv_nxt[1] || + BUF->seqno[2] != uip_connr->rcv_nxt[2] || + BUF->seqno[3] != uip_connr->rcv_nxt[3])) { + goto tcp_send_ack; + } + } + + /* Next, check if the incoming segment acknowledges any outstanding + data. If so, we update the sequence number, reset the length of + the outstanding data, calculate RTT estimations, and reset the + retransmission timer. */ + if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) { + uip_add32(uip_connr->snd_nxt, uip_connr->len); + + if(BUF->ackno[0] == uip_acc32[0] && + BUF->ackno[1] == uip_acc32[1] && + BUF->ackno[2] == uip_acc32[2] && + BUF->ackno[3] == uip_acc32[3]) { + /* Update sequence number. */ + uip_connr->snd_nxt[0] = uip_acc32[0]; + uip_connr->snd_nxt[1] = uip_acc32[1]; + uip_connr->snd_nxt[2] = uip_acc32[2]; + uip_connr->snd_nxt[3] = uip_acc32[3]; + + + /* Do RTT estimation, unless we have done retransmissions. */ + if(uip_connr->nrtx == 0) { + signed char m; + m = uip_connr->rto - uip_connr->timer; + /* This is taken directly from VJs original code in his paper */ + m = m - (uip_connr->sa >> 3); + uip_connr->sa += m; + if(m < 0) { + m = -m; + } + m = m - (uip_connr->sv >> 2); + uip_connr->sv += m; + uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv; + + } + /* Set the acknowledged flag. */ + uip_flags = UIP_ACKDATA; + /* Reset the retransmission timer. */ + uip_connr->timer = uip_connr->rto; + + /* Reset length of outstanding data. */ + uip_connr->len = 0; + } + + } + + /* Do different things depending on in what state the connection is. */ + switch(uip_connr->tcpstateflags & UIP_TS_MASK) { + /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not + implemented, since we force the application to close when the + peer sends a FIN (hence the application goes directly from + ESTABLISHED to LAST_ACK). */ + case UIP_SYN_RCVD: + /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and + we are waiting for an ACK that acknowledges the data we sent + out the last time. Therefore, we want to have the UIP_ACKDATA + flag set. If so, we enter the ESTABLISHED state. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_flags = UIP_CONNECTED; + uip_connr->len = 0; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + goto drop; +#if UIP_ACTIVE_OPEN + case UIP_SYN_SENT: + /* In SYN_SENT, we wait for a SYNACK that is sent in response to + our SYN. The rcv_nxt is set to sequence number in the SYNACK + plus one, and we send an ACK. We move into the ESTABLISHED + state. */ + if((uip_flags & UIP_ACKDATA) && + (BUF->flags & TCP_CTL) == (TCP_SYN | TCP_ACK)) { + + /* Parse the TCP MSS option, if present. */ + if((BUF->tcpoffset & 0xf0) > 0x50) { + for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) { + opt = uip_buf[UIP_IPTCPH_LEN + UIP_LLH_LEN + c]; + if(opt == TCP_OPT_END) { + /* End of options. */ + break; + } else if(opt == TCP_OPT_NOOP) { + ++c; + /* NOP option. */ + } else if(opt == TCP_OPT_MSS && + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == TCP_OPT_MSS_LEN) { + /* An MSS option with the right option length. */ + tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) | + uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c]; + uip_connr->initialmss = + uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16; + + /* And we are done processing options. */ + break; + } else { + /* All other options have a length field, so that we easily + can skip past them. */ + if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) { + /* If the length field is zero, the options are malformed + and we don't process them further. */ + break; + } + c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c]; + } + } + } + uip_connr->tcpstateflags = UIP_ESTABLISHED; + uip_connr->rcv_nxt[0] = BUF->seqno[0]; + uip_connr->rcv_nxt[1] = BUF->seqno[1]; + uip_connr->rcv_nxt[2] = BUF->seqno[2]; + uip_connr->rcv_nxt[3] = BUF->seqno[3]; + uip_add_rcv_nxt(1); + uip_flags = UIP_CONNECTED | UIP_NEWDATA; + uip_connr->len = 0; + uip_len = 0; + uip_slen = 0; + UIP_APPCALL(); + goto appsend; + } + /* Inform the application that the connection failed */ + uip_flags = UIP_ABORT; + UIP_APPCALL(); + /* The connection is closed after we send the RST */ + uip_conn->tcpstateflags = UIP_CLOSED; + goto reset; +#endif /* UIP_ACTIVE_OPEN */ + + case UIP_ESTABLISHED: + /* In the ESTABLISHED state, we call upon the application to feed + data into the uip_buf. If the UIP_ACKDATA flag is set, the + application should put new data into the buffer, otherwise we are + retransmitting an old segment, and the application should put that + data into the buffer. + + If the incoming packet is a FIN, we should close the connection on + this side as well, and we send out a FIN and enter the LAST_ACK + state. We require that there is no outstanding data; otherwise the + sequence numbers will be screwed up. */ + + if(BUF->flags & TCP_FIN && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + if(uip_outstanding(uip_connr)) { + goto drop; + } + uip_add_rcv_nxt(1 + uip_len); + uip_flags |= UIP_CLOSE; + if(uip_len > 0) { + uip_flags |= UIP_NEWDATA; + } + UIP_APPCALL(); + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_LAST_ACK; + uip_connr->nrtx = 0; + tcp_send_finack: + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* Check the URG flag. If this is set, the segment carries urgent + data that we must pass to the application. */ + if((BUF->flags & TCP_URG) != 0) { +#if UIP_URGDATA > 0 + uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1]; + if(uip_urglen > uip_len) { + /* There is more urgent data in the next segment to come. */ + uip_urglen = uip_len; + } + uip_add_rcv_nxt(uip_urglen); + uip_len -= uip_urglen; + uip_urgdata = uip_appdata; + uip_appdata += uip_urglen; + } else { + uip_urglen = 0; +#else /* UIP_URGDATA > 0 */ + uip_appdata = ((char *)uip_appdata) + ((BUF->urgp[0] << 8) | BUF->urgp[1]); + uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1]; +#endif /* UIP_URGDATA > 0 */ + } + + /* If uip_len > 0 we have TCP data in the packet, and we flag this + by setting the UIP_NEWDATA flag and update the sequence number + we acknowledge. If the application has stopped the dataflow + using uip_stop(), we must not accept any data packets from the + remote host. */ + if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) { + uip_flags |= UIP_NEWDATA; + uip_add_rcv_nxt(uip_len); + } + + /* Check if the available buffer space advertised by the other end + is smaller than the initial MSS for this connection. If so, we + set the current MSS to the window size to ensure that the + application does not send more data than the other end can + handle. + + If the remote host advertises a zero window, we set the MSS to + the initial MSS so that the application will send an entire MSS + of data. This data will not be acknowledged by the receiver, + and the application will retransmit it. This is called the + "persistent timer" and uses the retransmission mechanim. + */ + tmp16 = ((u16_t)BUF->wnd[0] << 8) + (u16_t)BUF->wnd[1]; + if(tmp16 > uip_connr->initialmss || + tmp16 == 0) { + tmp16 = uip_connr->initialmss; + } + uip_connr->mss = tmp16; + + /* If this packet constitutes an ACK for outstanding data (flagged + by the UIP_ACKDATA flag, we should call the application since it + might want to send more data. If the incoming packet had data + from the peer (as flagged by the UIP_NEWDATA flag), the + application must also be notified. + + When the application is called, the global variable uip_len + contains the length of the incoming data. The application can + access the incoming data through the global pointer + uip_appdata, which usually points UIP_IPTCPH_LEN + UIP_LLH_LEN + bytes into the uip_buf array. + + If the application wishes to send any data, this data should be + put into the uip_appdata and the length of the data should be + put into uip_len. If the application don't have any data to + send, uip_len must be set to 0. */ + if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) { + uip_slen = 0; + UIP_APPCALL(); + + appsend: + + if(uip_flags & UIP_ABORT) { + uip_slen = 0; + uip_connr->tcpstateflags = UIP_CLOSED; + BUF->flags = TCP_RST | TCP_ACK; + goto tcp_send_nodata; + } + + if(uip_flags & UIP_CLOSE) { + uip_slen = 0; + uip_connr->len = 1; + uip_connr->tcpstateflags = UIP_FIN_WAIT_1; + uip_connr->nrtx = 0; + BUF->flags = TCP_FIN | TCP_ACK; + goto tcp_send_nodata; + } + + /* If uip_slen > 0, the application has data to be sent. */ + if(uip_slen > 0) { + + /* If the connection has acknowledged data, the contents of + the ->len variable should be discarded. */ + if((uip_flags & UIP_ACKDATA) != 0) { + uip_connr->len = 0; + } + + /* If the ->len variable is non-zero the connection has + already data in transit and cannot send anymore right + now. */ + if(uip_connr->len == 0) { + + /* The application cannot send more than what is allowed by + the mss (the minumum of the MSS and the available + window). */ + if(uip_slen > uip_connr->mss) { + uip_slen = uip_connr->mss; + } + + /* Remember how much data we send out now so that we know + when everything has been acknowledged. */ + uip_connr->len = uip_slen; + } else { + + /* If the application already had unacknowledged data, we + make sure that the application does not send (i.e., + retransmit) out more than it previously sent out. */ + uip_slen = uip_connr->len; + } + } + uip_connr->nrtx = 0; + apprexmit: + uip_appdata = uip_sappdata; + + /* If the application has data to be sent, or if the incoming + packet had new data in it, we must send out a packet. */ + if(uip_slen > 0 && uip_connr->len > 0) { + /* Add the length of the IP and TCP headers. */ + uip_len = uip_connr->len + UIP_TCPIP_HLEN; + /* We always set the ACK flag in response packets. */ + BUF->flags = TCP_ACK | TCP_PSH; + /* Send the packet. */ + goto tcp_send_noopts; + } + /* If there is no data to send, just send out a pure ACK if + there is newdata. */ + if(uip_flags & UIP_NEWDATA) { + uip_len = UIP_TCPIP_HLEN; + BUF->flags = TCP_ACK; + goto tcp_send_noopts; + } + } + goto drop; + case UIP_LAST_ACK: + /* We can close this connection if the peer has acknowledged our + FIN. This is indicated by the UIP_ACKDATA flag. */ + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_CLOSED; + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + } + break; + + case UIP_FIN_WAIT_1: + /* The application has closed the connection, but the remote host + hasn't closed its end yet. Thus we do nothing but wait for a + FIN from the other side. */ + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_connr->len = 0; + } else { + uip_connr->tcpstateflags = UIP_CLOSING; + } + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } else if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_FIN_WAIT_2; + uip_connr->len = 0; + goto drop; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_FIN_WAIT_2: + if(uip_len > 0) { + uip_add_rcv_nxt(uip_len); + } + if(BUF->flags & TCP_FIN) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + uip_add_rcv_nxt(1); + uip_flags = UIP_CLOSE; + UIP_APPCALL(); + goto tcp_send_ack; + } + if(uip_len > 0) { + goto tcp_send_ack; + } + goto drop; + + case UIP_TIME_WAIT: + goto tcp_send_ack; + + case UIP_CLOSING: + if(uip_flags & UIP_ACKDATA) { + uip_connr->tcpstateflags = UIP_TIME_WAIT; + uip_connr->timer = 0; + } + } + goto drop; + + + /* We jump here when we are ready to send the packet, and just want + to set the appropriate TCP sequence numbers in the TCP header. */ + tcp_send_ack: + BUF->flags = TCP_ACK; + tcp_send_nodata: + uip_len = UIP_IPTCPH_LEN; + tcp_send_noopts: + BUF->tcpoffset = (UIP_TCPH_LEN / 4) << 4; + tcp_send: + /* We're done with the input processing. We are now ready to send a + reply. Our job is to fill in all the fields of the TCP and IP + headers before calculating the checksum and finally send the + packet. */ + BUF->ackno[0] = uip_connr->rcv_nxt[0]; + BUF->ackno[1] = uip_connr->rcv_nxt[1]; + BUF->ackno[2] = uip_connr->rcv_nxt[2]; + BUF->ackno[3] = uip_connr->rcv_nxt[3]; + + BUF->seqno[0] = uip_connr->snd_nxt[0]; + BUF->seqno[1] = uip_connr->snd_nxt[1]; + BUF->seqno[2] = uip_connr->snd_nxt[2]; + BUF->seqno[3] = uip_connr->snd_nxt[3]; + + BUF->proto = UIP_PROTO_TCP; + + BUF->srcport = uip_connr->lport; + BUF->destport = uip_connr->rport; + + uip_ipaddr_copy(BUF->srcipaddr, uip_hostaddr); + uip_ipaddr_copy(BUF->destipaddr, uip_connr->ripaddr); + + if(uip_connr->tcpstateflags & UIP_STOPPED) { + /* If the connection has issued uip_stop(), we advertise a zero + window so that the remote host will stop sending data. */ + BUF->wnd[0] = BUF->wnd[1] = 0; + } else { + BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8); + BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); + } + + tcp_send_noconn: + BUF->ttl = UIP_TTL; +#if UIP_CONF_IPV6 + /* For IPv6, the IP length field does not include the IPv6 IP header + length. */ + BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); +#else /* UIP_CONF_IPV6 */ + BUF->len[0] = (uip_len >> 8); + BUF->len[1] = (uip_len & 0xff); +#endif /* UIP_CONF_IPV6 */ + + BUF->urgp[0] = BUF->urgp[1] = 0; + + /* Calculate TCP checksum. */ + BUF->tcpchksum = 0; + BUF->tcpchksum = ~(uip_tcpchksum()); + + ip_send_nolen: + +#if UIP_CONF_IPV6 + BUF->vtc = 0x60; + BUF->tcflow = 0x00; + BUF->flow = 0x00; +#else /* UIP_CONF_IPV6 */ + BUF->vhl = 0x45; + BUF->tos = 0; + BUF->ipoffset[0] = BUF->ipoffset[1] = 0; + ++ipid; + BUF->ipid[0] = ipid >> 8; + BUF->ipid[1] = ipid & 0xff; + /* Calculate IP checksum. */ + BUF->ipchksum = 0; + BUF->ipchksum = ~(uip_ipchksum()); + DEBUG_PRINTF("uip ip_send_nolen: chkecum 0x%04x\n", uip_ipchksum()); +#endif /* UIP_CONF_IPV6 */ + + UIP_STAT(++uip_stat.tcp.sent); + send: + DEBUG_PRINTF("Sending packet with length %d (%d)\n", uip_len, + (BUF->len[0] << 8) | BUF->len[1]); + + UIP_STAT(++uip_stat.ip.sent); + /* Return and let the caller do the actual transmission. */ + uip_flags = 0; + return; + drop: + uip_len = 0; + uip_flags = 0; + return; +} +/*---------------------------------------------------------------------------*/ +u16_t +htons(u16_t val) +{ + return HTONS(val); +} +/*---------------------------------------------------------------------------*/ +void +uip_send(const void *data, int len) +{ + uip_slen = len; + if(len > 0) { + if(data != uip_sappdata) { + memcpy(uip_sappdata, (data), uip_slen); + } + } +} +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip.h b/STM32F4/libraries/arduino_uip/utility/uip.h new file mode 100644 index 0000000..4fc0452 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip.h @@ -0,0 +1,1601 @@ + +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * Header file for the uIP TCP/IP stack. + * \author Adam Dunkels + * + * The uIP TCP/IP stack header file contains definitions for a number + * of C macros that are used by uIP programs as well as internal uIP + * structures, TCP/IP header structures and function declarations. + * + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip.h,v 1.40 2006/06/08 07:12:07 adam Exp $ + * + */ + +#ifndef __UIP_H__ +#define __UIP_H__ + +#include "uipopt.h" + +/** + * Repressentation of an IP address. + * + */ +typedef u16_t uip_ip4addr_t[2]; +typedef u16_t uip_ip6addr_t[8]; +#if UIP_CONF_IPV6 +typedef uip_ip6addr_t uip_ipaddr_t; +#else /* UIP_CONF_IPV6 */ +typedef uip_ip4addr_t uip_ipaddr_t; +#endif /* UIP_CONF_IPV6 */ + +/*---------------------------------------------------------------------------*/ +/* First, the functions that should be called from the + * system. Initialization, the periodic timer and incoming packets are + * handled by the following three functions. + */ + +/** + * \defgroup uipconffunc uIP configuration functions + * @{ + * + * The uIP configuration functions are used for setting run-time + * parameters in uIP such as IP addresses. + */ + +/** + * Set the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + + uip_ipaddr_t addr; + + uip_ipaddr(&addr, 192,168,1,2); + uip_sethostaddr(&addr); + + \endcode + * \param addr A pointer to an IP address of type uip_ipaddr_t; + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_sethostaddr(addr) uip_ipaddr_copy(uip_hostaddr, (addr)) + +/** + * Get the IP address of this host. + * + * The IP address is represented as a 4-byte array where the first + * octet of the IP address is put in the first member of the 4-byte + * array. + * + * Example: + \code + uip_ipaddr_t hostaddr; + + uip_gethostaddr(&hostaddr); + \endcode + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the currently configured IP address. + * + * \hideinitializer + */ +#define uip_gethostaddr(addr) uip_ipaddr_copy((addr), uip_hostaddr) + +/** + * Set the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the default router. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setdraddr(addr) uip_ipaddr_copy(uip_draddr, (addr)) + +/** + * Set the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable containing the IP + * address of the netmask. + * + * \sa uip_ipaddr() + * + * \hideinitializer + */ +#define uip_setnetmask(addr) uip_ipaddr_copy(uip_netmask, (addr)) + + +/** + * Get the default router's IP address. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address of the default router. + * + * \hideinitializer + */ +#define uip_getdraddr(addr) uip_ipaddr_copy((addr), uip_draddr) + +/** + * Get the netmask. + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the value of the netmask. + * + * \hideinitializer + */ +#define uip_getnetmask(addr) uip_ipaddr_copy((addr), uip_netmask) + +/** @} */ + +/** + * \defgroup uipinit uIP initialization functions + * @{ + * + * The uIP initialization functions are used for booting uIP. + */ + +/** + * uIP initialization function. + * + * This function should be called at boot up to initilize the uIP + * TCP/IP stack. + */ +void uip_init(void); + +/** + * uIP initialization function. + * + * This function may be used at boot time to set the initial ip_id. + */ +void uip_setipid(u16_t id); + +/** @} */ + +/** + * \defgroup uipdevfunc uIP device driver functions + * @{ + * + * These functions are used by a network device driver for interacting + * with uIP. + */ + +/** + * Process an incoming packet. + * + * This function should be called when the device driver has received + * a packet from the network. The packet from the device driver must + * be present in the uip_buf buffer, and the length of the packet + * should be placed in the uip_len variable. + * + * When the function returns, there may be an outbound packet placed + * in the uip_buf packet buffer. If so, the uip_len variable is set to + * the length of the packet. If no packet is to be sent out, the + * uip_len variable is set to 0. + * + * The usual way of calling the function is presented by the source + * code below. + \code + uip_len = devicedriver_poll(); + if(uip_len > 0) { + uip_input(); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uIP ARP code before calling + * this function: + \code + #define BUF ((struct uip_eth_hdr *)&uip_buf[0]) + uip_len = ethernet_devicedrver_poll(); + if(uip_len > 0) { + if(BUF->type == HTONS(UIP_ETHTYPE_IP)) { + uip_arp_ipin(); + uip_input(); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) { + uip_arp_arpin(); + if(uip_len > 0) { + ethernet_devicedriver_send(); + } + } + \endcode + * + * \hideinitializer + */ +#define uip_input() uip_process(UIP_DATA) + +/** + * Periodic processing for a connection identified by its number. + * + * This function does the necessary periodic processing (timers, + * polling) for a uIP TCP conneciton, and should be called when the + * periodic uIP timer goes off. It should be called for every + * connection, regardless of whether they are open of closed. + * + * When the function returns, it may have an outbound packet waiting + * for service in the uIP packet buffer, and if so the uip_len + * variable is set to a value larger than zero. The device driver + * should be called to send out the packet. + * + * The ususal way of calling the function is through a for() loop like + * this: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note If you are writing a uIP device driver that needs ARP + * (Address Resolution Protocol), e.g., when running uIP over + * Ethernet, you will need to call the uip_arp_out() function before + * calling the device driver: + \code + for(i = 0; i < UIP_CONNS; ++i) { + uip_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the connection which is to be periodically polled. + * + * \hideinitializer + */ +#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \ + uip_process(UIP_TIMER); } while (0) + +/** + * + * + */ +#define uip_conn_active(conn) (uip_conns[conn].tcpstateflags != UIP_CLOSED) + +/** + * Perform periodic processing for a connection identified by a pointer + * to its structure. + * + * Same as uip_periodic() but takes a pointer to the actual uip_conn + * struct instead of an integer as its argument. This function can be + * used to force periodic processing of a specific connection. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_periodic_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_TIMER); } while (0) + +/** + * Reuqest that a particular connection should be polled. + * + * Similar to uip_periodic_conn() but does not perform any timer + * processing. The application is polled for new data. + * + * \param conn A pointer to the uip_conn struct for the connection to + * be processed. + * + * \hideinitializer + */ +#define uip_poll_conn(conn) do { uip_conn = conn; \ + uip_process(UIP_POLL_REQUEST); } while (0) + + +#if UIP_UDP +/** + * Periodic processing for a UDP connection identified by its number. + * + * This function is essentially the same as uip_periodic(), but for + * UDP connections. It is called in a similar fashion as the + * uip_periodic() function: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + devicedriver_send(); + } + } + \endcode + * + * \note As for the uip_periodic() function, special care has to be + * taken when using uIP together with ARP and Ethernet: + \code + for(i = 0; i < UIP_UDP_CONNS; i++) { + uip_udp_periodic(i); + if(uip_len > 0) { + uip_arp_out(); + ethernet_devicedriver_send(); + } + } + \endcode + * + * \param conn The number of the UDP connection to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \ + uip_process(UIP_UDP_TIMER); } while (0) + +/** + * Periodic processing for a UDP connection identified by a pointer to + * its structure. + * + * Same as uip_udp_periodic() but takes a pointer to the actual + * uip_conn struct instead of an integer as its argument. This + * function can be used to force periodic processing of a specific + * connection. + * + * \param conn A pointer to the uip_udp_conn struct for the connection + * to be processed. + * + * \hideinitializer + */ +#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \ + uip_process(UIP_UDP_TIMER); } while (0) + + +#endif /* UIP_UDP */ + +/** + * The uIP packet buffer. + * + * The uip_buf array is used to hold incoming and outgoing + * packets. The device driver should place incoming data into this + * buffer. When sending data, the device driver should read the link + * level headers and the TCP/IP headers from this buffer. The size of + * the link level headers is configured by the UIP_LLH_LEN define. + * + * \note The application data need not be placed in this buffer, so + * the device driver must read it from the place pointed to by the + * uip_appdata pointer as illustrated by the following example: + \code + void + devicedriver_send(void) + { + hwsend(&uip_buf[0], UIP_LLH_LEN); + if(uip_len <= UIP_LLH_LEN + UIP_TCPIP_HLEN) { + hwsend(&uip_buf[UIP_LLH_LEN], uip_len - UIP_LLH_LEN); + } else { + hwsend(&uip_buf[UIP_LLH_LEN], UIP_TCPIP_HLEN); + hwsend(uip_appdata, uip_len - UIP_TCPIP_HLEN - UIP_LLH_LEN); + } + } + \endcode + */ +extern u8_t uip_buf[UIP_BUFSIZE+2]; + +/** @} */ + +/*---------------------------------------------------------------------------*/ +/* Functions that are used by the uIP application program. Opening and + * closing connections, sending and receiving data, etc. is all + * handled by the functions below. +*/ +/** + * \defgroup uipappfunc uIP application functions + * @{ + * + * Functions used by an application running of top of uIP. + */ + +/** + * Start listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_listen(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_listen(u16_t port); + +/** + * Stop listening to the specified port. + * + * \note Since this function expects the port number in network byte + * order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_unlisten(HTONS(80)); + \endcode + * + * \param port A 16-bit port number in network byte order. + */ +void uip_unlisten(u16_t port); + +/** + * Connect to a remote host using TCP. + * + * This function is used to start a new connection to the specified + * port on the specied host. It allocates a new connection identifier, + * sets the connection to the SYN_SENT state and sets the + * retransmission timer to 0. This will cause a TCP SYN segment to be + * sent out the next time this connection is periodically processed, + * which usually is done within 0.5 seconds after the call to + * uip_connect(). + * + * \note This function is avaliable only if support for active open + * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h. + * + * \note Since this function requires the port number to be in network + * byte order, a conversion using HTONS() or htons() is necessary. + * + \code + uip_ipaddr_t ipaddr; + + uip_ipaddr(&ipaddr, 192,168,1,2); + uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param ripaddr The IP address of the remote hot. + * + * \param port A 16-bit port number in network byte order. + * + * \return A pointer to the uIP connection identifier for the new connection, + * or NULL if no connection could be allocated. + * + */ +struct uip_conn *uip_connect(uip_ipaddr_t *ripaddr, u16_t port); + + + +/** + * \internal + * + * Check if a connection has outstanding (i.e., unacknowledged) data. + * + * \param conn A pointer to the uip_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_outstanding(conn) ((conn)->len) + +/** + * Send data on the current connection. + * + * This function is used to send out a single segment of TCP + * data. Only applications that have been invoked by uIP for event + * processing can send data. + * + * The amount of data that actually is sent out after a call to this + * funcion is determined by the maximum amount of data TCP allows. uIP + * will automatically crop the data so that only the appropriate + * amount of data is sent. The function uip_mss() can be used to query + * uIP for the amount of data that actually will be sent. + * + * \note This function does not guarantee that the sent data will + * arrive at the destination. If the data is lost in the network, the + * application will be invoked with the uip_rexmit() event being + * set. The application will then have to resend the data using this + * function. + * + * \param data A pointer to the data which is to be sent. + * + * \param len The maximum amount of data bytes to be sent. + * + * \hideinitializer + */ +void uip_send(const void *data, int len); + +/** + * The length of any incoming data that is currently avaliable (if avaliable) + * in the uip_appdata buffer. + * + * The test function uip_data() must first be used to check if there + * is any data available at all. + * + * \hideinitializer + */ +/*void uip_datalen(void);*/ +#define uip_datalen() uip_len + +/** + * The length of any out-of-band data (urgent data) that has arrived + * on the connection. + * + * \note The configuration parameter UIP_URGDATA must be set for this + * function to be enabled. + * + * \hideinitializer + */ +#define uip_urgdatalen() uip_urglen + +/** + * Close the current connection. + * + * This function will close the current connection in a nice way. + * + * \hideinitializer + */ +#define uip_close() (uip_flags = UIP_CLOSE) + +/** + * Abort the current connection. + * + * This function will abort (reset) the current connection, and is + * usually used when an error has occured that prevents using the + * uip_close() function. + * + * \hideinitializer + */ +#define uip_abort() (uip_flags = UIP_ABORT) + +/** + * Tell the sending host to stop sending data. + * + * This function will close our receiver's window so that we stop + * receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_stop() (uip_conn->tcpstateflags |= UIP_STOPPED) + +/** + * Find out if the current connection has been previously stopped with + * uip_stop(). + * + * \hideinitializer + */ +#define uip_stopped(conn) ((conn)->tcpstateflags & UIP_STOPPED) + +/** + * Restart the current connection, if is has previously been stopped + * with uip_stop(). + * + * This function will open the receiver's window again so that we + * start receiving data for the current connection. + * + * \hideinitializer + */ +#define uip_restart() do { uip_flags |= UIP_NEWDATA; \ + uip_conn->tcpstateflags &= ~UIP_STOPPED; \ + } while(0) + + +/* uIP tests that can be made to determine in what state the current + connection is, and what the application function should do. */ + +/** + * Is the current connection a UDP connection? + * + * This function checks whether the current connection is a UDP connection. + * + * \hideinitializer + * + */ +#define uip_udpconnection() (uip_conn == NULL) + +/** + * Is new incoming data available? + * + * Will reduce to non-zero if there is new data for the application + * present at the uip_appdata pointer. The size of the data is + * avaliable through the uip_len variable. + * + * \hideinitializer + */ +#define uip_newdata() (uip_flags & UIP_NEWDATA) + +/** + * Has previously sent data been acknowledged? + * + * Will reduce to non-zero if the previously sent data has been + * acknowledged by the remote host. This means that the application + * can send new data. + * + * \hideinitializer + */ +#define uip_acked() (uip_flags & UIP_ACKDATA) + +/** + * Has the connection just been connected? + * + * Reduces to non-zero if the current connection has been connected to + * a remote host. This will happen both if the connection has been + * actively opened (with uip_connect()) or passively opened (with + * uip_listen()). + * + * \hideinitializer + */ +#define uip_connected() (uip_flags & UIP_CONNECTED) + +/** + * Has the connection been closed by the other end? + * + * Is non-zero if the connection has been closed by the remote + * host. The application may then do the necessary clean-ups. + * + * \hideinitializer + */ +#define uip_closed() (uip_flags & UIP_CLOSE) + +/** + * Has the connection been aborted by the other end? + * + * Non-zero if the current connection has been aborted (reset) by the + * remote host. + * + * \hideinitializer + */ +#define uip_aborted() (uip_flags & UIP_ABORT) + +/** + * Has the connection timed out? + * + * Non-zero if the current connection has been aborted due to too many + * retransmissions. + * + * \hideinitializer + */ +#define uip_timedout() (uip_flags & UIP_TIMEDOUT) + +/** + * Do we need to retransmit previously data? + * + * Reduces to non-zero if the previously sent data has been lost in + * the network, and the application should retransmit it. The + * application should send the exact same data as it did the last + * time, using the uip_send() function. + * + * \hideinitializer + */ +#define uip_rexmit() (uip_flags & UIP_REXMIT) + +/** + * Is the connection being polled by uIP? + * + * Is non-zero if the reason the application is invoked is that the + * current connection has been idle for a while and should be + * polled. + * + * The polling event can be used for sending data without having to + * wait for the remote host to send data. + * + * \hideinitializer + */ +#define uip_poll() (uip_flags & UIP_POLL) + +/** + * Get the initial maxium segment size (MSS) of the current + * connection. + * + * \hideinitializer + */ +#define uip_initialmss() (uip_conn->initialmss) + +/** + * Get the current maxium segment size that can be sent on the current + * connection. + * + * The current maxiumum segment size that can be sent on the + * connection is computed from the receiver's window and the MSS of + * the connection (which also is available by calling + * uip_initialmss()). + * + * \hideinitializer + */ +#define uip_mss() (uip_conn->mss) + +/** + * Set up a new UDP connection. + * + * This function sets up a new UDP connection. The function will + * automatically allocate an unused local port for the new + * connection. However, another port can be chosen by using the + * uip_udp_bind() call, after the uip_udp_new() function has been + * called. + * + * Example: + \code + uip_ipaddr_t addr; + struct uip_udp_conn *c; + + uip_ipaddr(&addr, 192,168,2,1); + c = uip_udp_new(&addr, HTONS(12345)); + if(c != NULL) { + uip_udp_bind(c, HTONS(12344)); + } + \endcode + * \param ripaddr The IP address of the remote host. + * + * \param rport The remote port number in network byte order. + * + * \return The uip_udp_conn structure for the new connection or NULL + * if no connection could be allocated. + */ +struct uip_udp_conn *uip_udp_new(uip_ipaddr_t *ripaddr, u16_t rport); + +/** + * Removed a UDP connection. + * + * \param conn A pointer to the uip_udp_conn structure for the connection. + * + * \hideinitializer + */ +#define uip_udp_remove(conn) (conn)->lport = 0 + +/** + * Bind a UDP connection to a local port. + * + * \param conn A pointer to the uip_udp_conn structure for the + * connection. + * + * \param port The local port number, in network byte order. + * + * \hideinitializer + */ +#define uip_udp_bind(conn, port) (conn)->lport = port + +/** + * Send a UDP datagram of length len on the current connection. + * + * This function can only be called in response to a UDP event (poll + * or newdata). The data must be present in the uip_buf buffer, at the + * place pointed to by the uip_appdata pointer. + * + * \param len The length of the data in the uip_buf buffer. + * + * \hideinitializer + */ +#define uip_udp_send(len) uip_send((char *)uip_appdata, len) + +/** @} */ + +/* uIP convenience and converting functions. */ + +/** + * \defgroup uipconvfunc uIP conversion functions + * @{ + * + * These functions can be used for converting between different data + * formats used by uIP. + */ + +/** + * Construct an IP address from four bytes. + * + * This function constructs an IP address of the type that uIP handles + * internally from four bytes. The function is handy for specifying IP + * addresses to use with e.g. the uip_connect() function. + * + * Example: + \code + uip_ipaddr_t ipaddr; + struct uip_conn *c; + + uip_ipaddr(&ipaddr, 192,168,1,2); + c = uip_connect(&ipaddr, HTONS(80)); + \endcode + * + * \param addr A pointer to a uip_ipaddr_t variable that will be + * filled in with the IP address. + * + * \param addr0 The first octet of the IP address. + * \param addr1 The second octet of the IP address. + * \param addr2 The third octet of the IP address. + * \param addr3 The forth octet of the IP address. + * + * \hideinitializer + */ +#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \ + ((u16_t *)(addr))[0] = HTONS(((addr0) << 8) | (addr1)); \ + ((u16_t *)(addr))[1] = HTONS(((addr2) << 8) | (addr3)); \ + } while(0) + +/** + * Construct an IPv6 address from eight 16-bit words. + * + * This function constructs an IPv6 address. + * + * \hideinitializer + */ +#define uip_ip6addr(addr, addr0,addr1,addr2,addr3,addr4,addr5,addr6,addr7) do { \ + ((u16_t *)(addr))[0] = HTONS((addr0)); \ + ((u16_t *)(addr))[1] = HTONS((addr1)); \ + ((u16_t *)(addr))[2] = HTONS((addr2)); \ + ((u16_t *)(addr))[3] = HTONS((addr3)); \ + ((u16_t *)(addr))[4] = HTONS((addr4)); \ + ((u16_t *)(addr))[5] = HTONS((addr5)); \ + ((u16_t *)(addr))[6] = HTONS((addr6)); \ + ((u16_t *)(addr))[7] = HTONS((addr7)); \ + } while(0) + +/** + * Copy an IP address to another IP address. + * + * Copies an IP address from one place to another. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr_copy(&ipaddr2, &ipaddr1); + \endcode + * + * \param dest The destination for the copy. + * \param src The source from where to copy. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_copy(dest, src) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1]; \ + } while(0) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_copy(dest, src) memcpy(dest, src, sizeof(uip_ip6addr_t)) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses + * + * Compares two IP addresses. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + if(uip_ipaddr_cmp(&ipaddr2, &ipaddr1)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * + * \hideinitializer + */ +#if !UIP_CONF_IPV6 +#define uip_ipaddr_cmp(addr1, addr2) (((u16_t *)addr1)[0] == ((u16_t *)addr2)[0] && \ + ((u16_t *)addr1)[1] == ((u16_t *)addr2)[1]) +#else /* !UIP_CONF_IPV6 */ +#define uip_ipaddr_cmp(addr1, addr2) (memcmp(addr1, addr2, sizeof(uip_ip6addr_t)) == 0) +#endif /* !UIP_CONF_IPV6 */ + +/** + * Compare two IP addresses with netmasks + * + * Compares two IP addresses with netmasks. The masks are used to mask + * out the bits that are to be compared. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, mask; + + uip_ipaddr(&mask, 255,255,255,0); + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&ipaddr2, 192,16,1,3); + if(uip_ipaddr_maskcmp(&ipaddr1, &ipaddr2, &mask)) { + printf("They are the same"); + } + \endcode + * + * \param addr1 The first IP address. + * \param addr2 The second IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_maskcmp(addr1, addr2, mask) \ + (((((u16_t *)addr1)[0] & ((u16_t *)mask)[0]) == \ + (((u16_t *)addr2)[0] & ((u16_t *)mask)[0])) && \ + ((((u16_t *)addr1)[1] & ((u16_t *)mask)[1]) == \ + (((u16_t *)addr2)[1] & ((u16_t *)mask)[1]))) + + +/** + * Mask out the network part of an IP address. + * + * Masks out the network part of an IP address, given the address and + * the netmask. + * + * Example: + \code + uip_ipaddr_t ipaddr1, ipaddr2, netmask; + + uip_ipaddr(&ipaddr1, 192,16,1,2); + uip_ipaddr(&netmask, 255,255,255,0); + uip_ipaddr_mask(&ipaddr2, &ipaddr1, &netmask); + \endcode + * + * In the example above, the variable "ipaddr2" will contain the IP + * address 192.168.1.0. + * + * \param dest Where the result is to be placed. + * \param src The IP address. + * \param mask The netmask. + * + * \hideinitializer + */ +#define uip_ipaddr_mask(dest, src, mask) do { \ + ((u16_t *)dest)[0] = ((u16_t *)src)[0] & ((u16_t *)mask)[0]; \ + ((u16_t *)dest)[1] = ((u16_t *)src)[1] & ((u16_t *)mask)[1]; \ + } while(0) + +/** + * Pick the first octet of an IP address. + * + * Picks out the first octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr1(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 1. + * + * \hideinitializer + */ +#define uip_ipaddr1(addr) (htons(((u16_t *)(addr))[0]) >> 8) + +/** + * Pick the second octet of an IP address. + * + * Picks out the second octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr2(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 2. + * + * \hideinitializer + */ +#define uip_ipaddr2(addr) (htons(((u16_t *)(addr))[0]) & 0xff) + +/** + * Pick the third octet of an IP address. + * + * Picks out the third octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr3(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 3. + * + * \hideinitializer + */ +#define uip_ipaddr3(addr) (htons(((u16_t *)(addr))[1]) >> 8) + +/** + * Pick the fourth octet of an IP address. + * + * Picks out the fourth octet of an IP address. + * + * Example: + \code + uip_ipaddr_t ipaddr; + u8_t octet; + + uip_ipaddr(&ipaddr, 1,2,3,4); + octet = uip_ipaddr4(&ipaddr); + \endcode + * + * In the example above, the variable "octet" will contain the value 4. + * + * \hideinitializer + */ +#define uip_ipaddr4(addr) (htons(((u16_t *)(addr))[1]) & 0xff) + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This macro is primarily used for converting constants from host + * byte order to network byte order. For converting variables to + * network byte order, use the htons() function instead. + * + * \hideinitializer + */ +#ifndef HTONS +# if UIP_BYTE_ORDER == UIP_BIG_ENDIAN +# define HTONS(n) (n) +# else /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +# define HTONS(n) (u16_t)((((u16_t) (n)) << 8) | (((u16_t) (n)) >> 8)) +# endif /* UIP_BYTE_ORDER == UIP_BIG_ENDIAN */ +#else +#error "HTONS already defined!" +#endif /* HTONS */ + +/** + * Convert 16-bit quantity from host byte order to network byte order. + * + * This function is primarily used for converting variables from host + * byte order to network byte order. For converting constants to + * network byte order, use the HTONS() macro instead. + */ +#ifndef htons +u16_t htons(u16_t val); +#endif /* htons */ +#ifndef ntohs +#define ntohs htons +#endif + +/** @} */ + +/** + * Pointer to the application data in the packet buffer. + * + * This pointer points to the application data when the application is + * called. If the application wishes to send data, the application may + * use this space to write the data into before calling uip_send(). + */ +extern void *uip_appdata; + +#if UIP_URGDATA > 0 +/* u8_t *uip_urgdata: + * + * This pointer points to any urgent data that has been received. Only + * present if compiled with support for urgent data (UIP_URGDATA). + */ +extern void *uip_urgdata; +#endif /* UIP_URGDATA > 0 */ + + +/** + * \defgroup uipdrivervars Variables used in uIP device drivers + * @{ + * + * uIP has a few global variables that are used in device drivers for + * uIP. + */ + +/** + * The length of the packet in the uip_buf buffer. + * + * The global variable uip_len holds the length of the packet in the + * uip_buf buffer. + * + * When the network device driver calls the uIP input function, + * uip_len should be set to the length of the packet in the uip_buf + * buffer. + * + * When sending packets, the device driver should use the contents of + * the uip_len variable to determine the length of the outgoing + * packet. + * + */ +extern u16_t uip_len; + +/** @} */ + +#if UIP_URGDATA > 0 +extern u16_t uip_urglen, uip_surglen; +#endif /* UIP_URGDATA > 0 */ + + +/** + * Representation of a uIP TCP connection. + * + * The uip_conn structure is used for identifying a connection. All + * but one field in the structure are to be considered read-only by an + * application. The only exception is the appstate field whos purpose + * is to let the application store application-specific state (e.g., + * file pointers) for the connection. The type of this field is + * configured in the "uipopt.h" header file. + */ +struct uip_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */ + + u16_t lport; /**< The local TCP port, in network byte order. */ + u16_t rport; /**< The local remote TCP port, in network byte + order. */ + + u8_t rcv_nxt[4]; /**< The sequence number that we expect to + receive next. */ + u8_t snd_nxt[4]; /**< The sequence number that was last sent by + us. */ + u16_t len; /**< Length of the data that was previously sent. */ + u16_t mss; /**< Current maximum segment size for the + connection. */ + u16_t initialmss; /**< Initial maximum segment size for the + connection. */ + u8_t sa; /**< Retransmission time-out calculation state + variable. */ + u8_t sv; /**< Retransmission time-out calculation state + variable. */ + u8_t rto; /**< Retransmission time-out. */ + u8_t tcpstateflags; /**< TCP state and flags. */ + u8_t timer; /**< The retransmission timer. */ + u8_t nrtx; /**< The number of retransmissions for the last + segment sent. */ + + /** The application state. */ + uip_tcp_appstate_t appstate; +}; + + +/** + * Pointer to the current TCP connection. + * + * The uip_conn pointer can be used to access the current TCP + * connection. + */ +extern struct uip_conn *uip_conn; +/* The array containing all uIP connections. */ +extern struct uip_conn uip_conns[UIP_CONNS]; +/** + * \addtogroup uiparch + * @{ + */ + +/** + * 4-byte array used for the 32-bit sequence number calculations. + */ +extern u8_t uip_acc32[4]; + +/** @} */ + + +#if UIP_UDP +/** + * Representation of a uIP UDP connection. + */ +struct uip_udp_conn { + uip_ipaddr_t ripaddr; /**< The IP address of the remote peer. */ + u16_t lport; /**< The local port number in network byte order. */ + u16_t rport; /**< The remote port number in network byte order. */ + u8_t ttl; /**< Default time-to-live. */ + + /** The application state. */ + uip_udp_appstate_t appstate; +}; + +/** + * The current UDP connection. + */ +extern struct uip_udp_conn *uip_udp_conn; +extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS]; +#endif /* UIP_UDP */ + +/** + * The structure holding the TCP/IP statistics that are gathered if + * UIP_STATISTICS is set to 1. + * + */ +struct uip_stats { + struct { + uip_stats_t drop; /**< Number of dropped packets at the IP + layer. */ + uip_stats_t recv; /**< Number of received packets at the IP + layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP + layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong + IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong + IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong + IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they + were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP + checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they + were neither ICMP, UDP nor TCP. */ + } ip; /**< IP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped ICMP packets. */ + uip_stats_t recv; /**< Number of received ICMP packets. */ + uip_stats_t sent; /**< Number of sent ICMP packets. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong + type. */ + } icmp; /**< ICMP statistics. */ + struct { + uip_stats_t drop; /**< Number of dropped TCP segments. */ + uip_stats_t recv; /**< Number of recived TCP segments. */ + uip_stats_t sent; /**< Number of sent TCP segments. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad + checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK + number. */ + uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ + uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few + connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, + triggering a RST. */ + } tcp; /**< TCP statistics. */ +#if UIP_UDP + struct { + uip_stats_t drop; /**< Number of dropped UDP segments. */ + uip_stats_t recv; /**< Number of recived UDP segments. */ + uip_stats_t sent; /**< Number of sent UDP segments. */ + uip_stats_t chkerr; /**< Number of UDP segments with a bad + checksum. */ + } udp; /**< UDP statistics. */ +#endif /* UIP_UDP */ +}; + +/** + * The uIP TCP/IP statistics. + * + * This is the variable in which the uIP TCP/IP statistics are gathered. + */ +extern struct uip_stats uip_stat; + + +/*---------------------------------------------------------------------------*/ +/* All the stuff below this point is internal to uIP and should not be + * used directly by an application or by a device driver. + */ +/*---------------------------------------------------------------------------*/ +/* u8_t uip_flags: + * + * When the application is called, uip_flags will contain the flags + * that are defined in this file. Please read below for more + * infomation. + */ +extern u8_t uip_flags; + +/* The following flags may be set in the global variable uip_flags + before calling the application callback. The UIP_ACKDATA, + UIP_NEWDATA, and UIP_CLOSE flags may both be set at the same time, + whereas the others are mutualy exclusive. Note that these flags + should *NOT* be accessed directly, but only through the uIP + functions/macros. */ + +#define UIP_ACKDATA 1 /* Signifies that the outstanding data was + acked and the application should send + out new data instead of retransmitting + the last data. */ +#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent + us new data. */ +#define UIP_REXMIT 4 /* Tells the application to retransmit the + data that was last sent. */ +#define UIP_POLL 8 /* Used for polling the application, to + check if the application has data that + it wants to send. */ +#define UIP_CLOSE 16 /* The remote host has closed the + connection, thus the connection has + gone away. Or the application signals + that it wants to close the + connection. */ +#define UIP_ABORT 32 /* The remote host has aborted the + connection, thus the connection has + gone away. Or the application signals + that it wants to abort the + connection. */ +#define UIP_CONNECTED 64 /* We have got a connection from a remote + host and have set up a new connection + for it, or an active connection has + been successfully established. */ + +#define UIP_TIMEDOUT 128 /* The connection has been aborted due to + too many retransmissions. */ + +/* uip_process(flag): + * + * The actual uIP function which does all the work. + */ +void uip_process(u8_t flag); + +/* The following flags are passed as an argument to the uip_process() + function. They are used to distinguish between the two cases where + uip_process() is called. It can be called either because we have + incoming data that should be processed, or because the periodic + timer has fired. These values are never used directly, but only in + the macrose defined in this file. */ + +#define UIP_DATA 1 /* Tells uIP that there is incoming + data in the uip_buf buffer. The + length of the data is stored in the + global variable uip_len. */ +#define UIP_TIMER 2 /* Tells uIP that the periodic timer + has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells uIP that a connection should + be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells uIP that a UDP datagram + should be constructed in the + uip_buf buffer. */ +#if UIP_UDP +#define UIP_UDP_TIMER 5 +#endif /* UIP_UDP */ + +/* The TCP states used in the uip_conn->tcpstateflags. */ +#define UIP_CLOSED 0 +#define UIP_SYN_RCVD 1 +#define UIP_SYN_SENT 2 +#define UIP_ESTABLISHED 3 +#define UIP_FIN_WAIT_1 4 +#define UIP_FIN_WAIT_2 5 +#define UIP_CLOSING 6 +#define UIP_TIME_WAIT 7 +#define UIP_LAST_ACK 8 +#define UIP_TS_MASK 15 + +#define UIP_STOPPED 16 + +/* The TCP and IP headers. */ +struct uip_tcpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcflow; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* TCP header. */ + u16_t srcport, + destport; + u8_t seqno[4], + ackno[4], + tcpoffset, + flags, + wnd[2]; + u16_t tcpchksum; + u8_t urgp[2]; + u8_t optdata[4]; +}; + +/* The ICMP and IP headers. */ +struct uip_icmpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IPv4 header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* ICMP (echo) header. */ + u8_t type, icode; + u16_t icmpchksum; +#if !UIP_CONF_IPV6 + u16_t id, seqno; +#else /* !UIP_CONF_IPV6 */ + u8_t flags, reserved1, reserved2, reserved3; + u8_t icmp6data[16]; + u8_t options[1]; +#endif /* !UIP_CONF_IPV6 */ +}; + + +/* The UDP and IP headers. */ +struct uip_udpip_hdr { +#if UIP_CONF_IPV6 + /* IPv6 header. */ + u8_t vtc, + tcf; + u16_t flow; + u8_t len[2]; + u8_t proto, ttl; + uip_ip6addr_t srcipaddr, destipaddr; +#else /* UIP_CONF_IPV6 */ + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +#endif /* UIP_CONF_IPV6 */ + + /* UDP header. */ + u16_t srcport, + destport; + u16_t udplen; + u16_t udpchksum; +}; + + + +/** + * The buffer size available for user data in the \ref uip_buf buffer. + * + * This macro holds the available size for user data in the \ref + * uip_buf buffer. The macro is intended to be used for checking + * bounds of available user data. + * + * Example: + \code + snprintf(uip_appdata, UIP_APPDATA_SIZE, "%u\n", i); + \endcode + * + * \hideinitializer + */ +#define UIP_APPDATA_SIZE (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) + + +#define UIP_PROTO_ICMP 1 +#define UIP_PROTO_TCP 6 +#define UIP_PROTO_UDP 17 +#define UIP_PROTO_ICMP6 58 + +/* Header sizes. */ +#if UIP_CONF_IPV6 +#define UIP_IPH_LEN 40 +#else /* UIP_CONF_IPV6 */ +#define UIP_IPH_LEN 20 /* Size of IP header */ +#endif /* UIP_CONF_IPV6 */ +#define UIP_UDPH_LEN 8 /* Size of UDP header */ +#define UIP_TCPH_LEN 20 /* Size of TCP header */ +#define UIP_IPUDPH_LEN (UIP_UDPH_LEN + UIP_IPH_LEN) /* Size of IP + + UDP + header */ +#define UIP_IPTCPH_LEN (UIP_TCPH_LEN + UIP_IPH_LEN) /* Size of IP + + TCP + header */ +#define UIP_TCPIP_HLEN UIP_IPTCPH_LEN + + +#if UIP_FIXEDADDR +extern const uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#else /* UIP_FIXEDADDR */ +extern uip_ipaddr_t uip_hostaddr, uip_netmask, uip_draddr; +#endif /* UIP_FIXEDADDR */ + + + +/** + * Representation of a 48-bit Ethernet address. + */ +struct uip_eth_addr { + u8_t addr[6]; +}; + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +/** + * Calculate the UDP checksum of the packet in uip_buf and uip_appdata. + * + * The UDP checksum is the Internet checksum of data contents of the + * UDP segment, and a pseudo-header as defined in RFC768. + * + * \return The UDP checksum of the UDP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_udpchksum(void); + + +#endif /* __UIP_H__ */ + + +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_arch.h b/STM32F4/libraries/arduino_uip/utility/uip_arch.h new file mode 100644 index 0000000..71fd84b --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_arch.h @@ -0,0 +1,138 @@ +/** + * \addtogroup uip + * {@ + */ + +/** + * \defgroup uiparch Architecture specific uIP functions + * @{ + * + * The functions in the architecture specific module implement the IP + * check sum and 32-bit additions. + * + * The IP checksum calculation is the most computationally expensive + * operation in the TCP/IP stack and it therefore pays off to + * implement this in efficient assembler. The purpose of the uip-arch + * module is to let the checksum functions to be implemented in + * architecture specific assembler. + * + */ + +/** + * \file + * Declarations of architecture specific functions. + * \author Adam Dunkels + */ + +/* + * Copyright (c) 2001, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arch.h,v 1.2 2006/06/07 09:15:19 adam Exp $ + * + */ + +#ifndef __UIP_ARCH_H__ +#define __UIP_ARCH_H__ + +#include "uip.h" + +/** + * Carry out a 32-bit addition. + * + * Because not all architectures for which uIP is intended has native + * 32-bit arithmetic, uIP uses an external C function for doing the + * required 32-bit additions in the TCP protocol processing. This + * function should add the two arguments and place the result in the + * global variable uip_acc32. + * + * \note The 32-bit integer pointed to by the op32 parameter and the + * result in the uip_acc32 variable are in network byte order (big + * endian). + * + * \param op32 A pointer to a 4-byte array representing a 32-bit + * integer in network byte order (big endian). + * + * \param op16 A 16-bit integer in host byte order. + */ +void uip_add32(u8_t *op32, u16_t op16); + +/** + * Calculate the Internet checksum over a buffer. + * + * The Internet checksum is the one's complement of the one's + * complement sum of all 16-bit words in the buffer. + * + * See RFC1071. + * + * \note This function is not called in the current version of uIP, + * but future versions might make use of it. + * + * \param buf A pointer to the buffer over which the checksum is to be + * computed. + * + * \param len The length of the buffer over which the checksum is to + * be computed. + * + * \return The Internet checksum of the buffer. + */ +u16_t uip_chksum(u16_t *buf, u16_t len); + +/** + * Calculate the IP header checksum of the packet header in uip_buf. + * + * The IP header checksum is the Internet checksum of the 20 bytes of + * the IP header. + * + * \return The IP header checksum of the IP header in the uip_buf + * buffer. + */ +u16_t uip_ipchksum(void); + +/** + * Calculate the TCP checksum of the packet in uip_buf and uip_appdata. + * + * The TCP checksum is the Internet checksum of data contents of the + * TCP segment, and a pseudo-header as defined in RFC793. + * + * \note The uip_appdata pointer that points to the packet data may + * point anywhere in memory, so it is not possible to simply calculate + * the Internet checksum of the contents of the uip_buf buffer. + * + * \return The TCP checksum of the TCP segment in uip_buf and pointed + * to by uip_appdata. + */ +u16_t uip_tcpchksum(void); + +u16_t uip_udpchksum(void); + +/** @} */ +/** @} */ + +#endif /* __UIP_ARCH_H__ */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_arp.c b/STM32F4/libraries/arduino_uip/utility/uip_arp.c new file mode 100644 index 0000000..44ca7c4 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_arp.c @@ -0,0 +1,423 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \defgroup uiparp uIP Address Resolution Protocol + * @{ + * + * The Address Resolution Protocol ARP is used for mapping between IP + * addresses and link level addresses such as the Ethernet MAC + * addresses. ARP uses broadcast queries to ask for the link level + * address of a known IP address and the host which is configured with + * the IP address for which the query was meant, will respond with its + * link level address. + * + * \note This ARP implementation only supports Ethernet. + */ + +/** + * \file + * Implementation of the ARP Address Resolution Protocol. + * \author Adam Dunkels + * + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $ + * + */ + + +#include "uip_arp.h" + +#include + +struct arp_hdr { + struct uip_eth_hdr ethhdr; + u16_t hwtype; + u16_t protocol; + u8_t hwlen; + u8_t protolen; + u16_t opcode; + struct uip_eth_addr shwaddr; + u16_t sipaddr[2]; + struct uip_eth_addr dhwaddr; + u16_t dipaddr[2]; +}; + +struct ethip_hdr { + struct uip_eth_hdr ethhdr; + /* IP header. */ + u8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + u16_t ipchksum; + u16_t srcipaddr[2], + destipaddr[2]; +}; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +struct arp_entry { + u16_t ipaddr[2]; + struct uip_eth_addr ethaddr; + u8_t time; +}; + +static const struct uip_eth_addr broadcast_ethaddr = + {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff}; + +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; +static u16_t ipaddr[2]; +static u8_t i, c; + +static u8_t arptime; +static u8_t tmpage; + +#define BUF ((struct arp_hdr *)&uip_buf[0]) +#define IPBUF ((struct ethip_hdr *)&uip_buf[0]) +/*-----------------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_init(void) +{ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + memset(arp_table[i].ipaddr, 0, 4); + } +} +/*-----------------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_timer(void) +{ + struct arp_entry *tabptr; + + ++arptime; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 && + arptime - tabptr->time >= UIP_ARP_MAXAGE) { + memset(tabptr->ipaddr, 0, 4); + } + } + +} +/*-----------------------------------------------------------------------------------*/ +static void +uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr) +{ + register struct arp_entry *tabptr; + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + + tabptr = &arp_table[i]; + /* Only check those entries that are actually in use. */ + if(tabptr->ipaddr[0] != 0 && + tabptr->ipaddr[1] != 0) { + + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(ipaddr[0] == tabptr->ipaddr[0] && + ipaddr[1] == tabptr->ipaddr[1]) { + + /* An old entry found, update this and return. */ + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; + + return; + } + } + } + + /* If we get here, no existing ARP table entry was found, so we + create one. */ + + /* First, we try to find an unused entry in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(tabptr->ipaddr[0] == 0 && + tabptr->ipaddr[1] == 0) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == UIP_ARPTAB_SIZE) { + tmpage = 0; + c = 0; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(arptime - tabptr->time > tmpage) { + tmpage = arptime - tabptr->time; + c = i; + } + } + i = c; + tabptr = &arp_table[i]; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + memcpy(tabptr->ipaddr, ipaddr, 4); + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; +} +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming IP packets + * + * This function should be called by the device driver when an IP + * packet has been received. The function will check if the address is + * in the ARP cache, and if so the ARP cache entry will be + * refreshed. If no ARP cache entry was found, a new one is created. + * + * This function expects an IP packet with a prepended Ethernet header + * in the uip_buf[] buffer, and the length of the packet in the global + * variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +//#if 0 +void +uip_arp_ipin(void) +{ + uip_len -= sizeof(struct uip_eth_hdr); + + /* Only insert/update an entry if the source IP address of the + incoming IP packet comes from a host on the local network. */ + if((IPBUF->srcipaddr[0] & uip_netmask[0]) != + (uip_hostaddr[0] & uip_netmask[0])) { + return; + } + if((IPBUF->srcipaddr[1] & uip_netmask[1]) != + (uip_hostaddr[1] & uip_netmask[1])) { + return; + } + uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src)); + + return; +} +//#endif /* 0 */ +/*-----------------------------------------------------------------------------------*/ +/** + * ARP processing for incoming ARP packets. + * + * This function should be called by the device driver when an ARP + * packet has been received. The function will act differently + * depending on the ARP packet type: if it is a reply for a request + * that we previously sent out, the ARP cache will be filled in with + * the values from the ARP reply. If the incoming ARP packet is an ARP + * request for our IP address, an ARP reply packet is created and put + * into the uip_buf[] buffer. + * + * When the function returns, the value of the global variable uip_len + * indicates whether the device driver should send out a packet or + * not. If uip_len is zero, no packet should be sent. If uip_len is + * non-zero, it contains the length of the outbound packet that is + * present in the uip_buf[] buffer. + * + * This function expects an ARP packet with a prepended Ethernet + * header in the uip_buf[] buffer, and the length of the packet in the + * global variable uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_arpin(void) +{ + + if(uip_len < sizeof(struct arp_hdr)) { + uip_len = 0; + return; + } + uip_len = 0; + + switch(BUF->opcode) { + case HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + reply. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + /* First, we register the one who made the request in our ARP + table, since it is likely that we will do more communication + with this host in the future. */ + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + + /* The reply opcode is 2. */ + BUF->opcode = HTONS(2); + + memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); + + BUF->dipaddr[0] = BUF->sipaddr[0]; + BUF->dipaddr[1] = BUF->sipaddr[1]; + BUF->sipaddr[0] = uip_hostaddr[0]; + BUF->sipaddr[1] = uip_hostaddr[1]; + + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + uip_len = sizeof(struct arp_hdr); + } + break; + case HTONS(ARP_REPLY): + /* ARP reply. We insert or update the ARP table if it was meant + for us. */ + if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) { + uip_arp_update(BUF->sipaddr, &BUF->shwaddr); + } + break; + } + + return; +} +/*-----------------------------------------------------------------------------------*/ +/** + * Prepend Ethernet header to an outbound IP packet and see if we need + * to send out an ARP request. + * + * This function should be called before sending out an IP packet. The + * function checks the destination IP address of the IP packet to see + * what Ethernet MAC address that should be used as a destination MAC + * address on the Ethernet. + * + * If the destination IP address is in the local network (determined + * by logical ANDing of netmask and our IP address), the function + * checks the ARP cache to see if an entry for the destination IP + * address is found. If so, an Ethernet header is prepended and the + * function returns. If no ARP cache entry is found for the + * destination IP address, the packet in the uip_buf[] is replaced by + * an ARP request packet for the IP address. The IP packet is dropped + * and it is assumed that they higher level protocols (e.g., TCP) + * eventually will retransmit the dropped packet. + * + * If the destination IP address is not on the local network, the IP + * address of the default router is used instead. + * + * When the function returns, a packet is present in the uip_buf[] + * buffer, and the length of the packet is in the global variable + * uip_len. + */ +/*-----------------------------------------------------------------------------------*/ +void +uip_arp_out(void) +{ + struct arp_entry *tabptr; + + /* Find the destination IP address in the ARP table and construct + the Ethernet header. If the destination IP addres isn't on the + local network, we use the default router's IP address instead. + + If not ARP table entry is found, we overwrite the original IP + packet with an ARP request for the IP address. */ + + /* First check if destination is a local broadcast. */ + if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) { + memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6); + } else { + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ipaddr_copy(ipaddr, uip_draddr); + } else { + /* Else, we use the destination IP address. */ + uip_ipaddr_copy(ipaddr, IPBUF->destipaddr); + } + + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) { + break; + } + } + + if(i == UIP_ARPTAB_SIZE) { + /* The destination address was not in our ARP table, so we + overwrite the IP packet with an ARP request. */ + + memset(BUF->ethhdr.dest.addr, 0xff, 6); + memset(BUF->dhwaddr.addr, 0x00, 6); + memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + + uip_ipaddr_copy(BUF->dipaddr, ipaddr); + uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr); + BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */ + BUF->hwtype = HTONS(ARP_HWTYPE_ETH); + BUF->protocol = HTONS(UIP_ETHTYPE_IP); + BUF->hwlen = 6; + BUF->protolen = 4; + BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP); + + uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; + + uip_len = sizeof(struct arp_hdr); + return; + } + + /* Build an ethernet header. */ + memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); + } + memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + + IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP); + + uip_len += sizeof(struct uip_eth_hdr); +} +/*-----------------------------------------------------------------------------------*/ + +/** @} */ +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_arp.h b/STM32F4/libraries/arduino_uip/utility/uip_arp.h new file mode 100644 index 0000000..ef93054 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_arp.h @@ -0,0 +1,144 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \addtogroup uiparp + * @{ + */ + +/** + * \file + * Macros and definitions for the ARP module. + * \author Adam Dunkels + */ + + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.h,v 1.5 2006/06/11 21:46:39 adam Exp $ + * + */ + +#ifndef __UIP_ARP_H__ +#define __UIP_ARP_H__ + +#include "uip.h" + + +extern struct uip_eth_addr uip_ethaddr; + +/** + * The Ethernet header. + */ +struct uip_eth_hdr { + struct uip_eth_addr dest; + struct uip_eth_addr src; + u16_t type; +}; + +#define UIP_ETHTYPE_ARP 0x0806 +#define UIP_ETHTYPE_IP 0x0800 +#define UIP_ETHTYPE_IP6 0x86dd + + +/* The uip_arp_init() function must be called before any of the other + ARP functions. */ +void uip_arp_init(void); + +/* The uip_arp_ipin() function should be called whenever an IP packet + arrives from the Ethernet. This function refreshes the ARP table or + inserts a new mapping if none exists. The function assumes that an + IP packet with an Ethernet header is present in the uip_buf buffer + and that the length of the packet is in the uip_len variable. */ +void uip_arp_ipin(void); +//#define uip_arp_ipin() + +/* The uip_arp_arpin() should be called when an ARP packet is received + by the Ethernet driver. This function also assumes that the + Ethernet frame is present in the uip_buf buffer. When the + uip_arp_arpin() function returns, the contents of the uip_buf + buffer should be sent out on the Ethernet if the uip_len variable + is > 0. */ +void uip_arp_arpin(void); + +/* The uip_arp_out() function should be called when an IP packet + should be sent out on the Ethernet. This function creates an + Ethernet header before the IP header in the uip_buf buffer. The + Ethernet header will have the correct Ethernet MAC destination + address filled in if an ARP table entry for the destination IP + address (or the IP address of the default router) is present. If no + such table entry is found, the IP packet is overwritten with an ARP + request and we rely on TCP to retransmit the packet that was + overwritten. In any case, the uip_len variable holds the length of + the Ethernet frame that should be transmitted. */ +void uip_arp_out(void); + +/* The uip_arp_timer() function should be called every ten seconds. It + is responsible for flushing old entries in the ARP table. */ +void uip_arp_timer(void); + +/** @} */ + +/** + * \addtogroup uipconffunc + * @{ + */ + + +/** + * Specifiy the Ethernet MAC address. + * + * The ARP code needs to know the MAC address of the Ethernet card in + * order to be able to respond to ARP queries and to generate working + * Ethernet headers. + * + * \note This macro only specifies the Ethernet MAC address to the ARP + * code. It cannot be used to change the MAC address of the Ethernet + * card. + * + * \param eaddr A pointer to a struct uip_eth_addr containing the + * Ethernet MAC address of the Ethernet card. + * + * \hideinitializer + */ +#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \ + uip_ethaddr.addr[1] = eaddr.addr[1];\ + uip_ethaddr.addr[2] = eaddr.addr[2];\ + uip_ethaddr.addr[3] = eaddr.addr[3];\ + uip_ethaddr.addr[4] = eaddr.addr[4];\ + uip_ethaddr.addr[5] = eaddr.addr[5];} while(0) + +/** @} */ +/** @} */ + +#endif /* __UIP_ARP_H__ */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_clock.h b/STM32F4/libraries/arduino_uip/utility/uip_clock.h new file mode 100644 index 0000000..6dd72be --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_clock.h @@ -0,0 +1,88 @@ +/** + * \defgroup clock Clock interface + * + * The clock interface is the interface between the \ref timer "timer library" + * and the platform specific clock functionality. The clock + * interface must be implemented for each platform that uses the \ref + * timer "timer library". + * + * The clock interface does only one this: it measures time. The clock + * interface provides a macro, CLOCK_SECOND, which corresponds to one + * second of system time. + * + * \sa \ref timer "Timer library" + * + * @{ + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: clock.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __UIP_CLOCK_H__ +#define __UIP_CLOCK_H__ + +#include "clock-arch.h" + +/** + * Initialize the clock library. + * + * This function initializes the clock library and should be called + * from the main() function of the system. + * + */ +void uip_clock_init(void); + +/** + * Get the current clock time. + * + * This function returns the current system clock time. + * + * \return The current clock time, measured in system ticks. + */ +clock_time_t clock_time(void); + +/** + * A second, measured in system clock time. + * + * \hideinitializer + */ +#ifdef CLOCK_CONF_SECOND +#define CLOCK_SECOND CLOCK_CONF_SECOND +#else +#define CLOCK_SECOND (clock_time_t)32 +#endif + +#endif /* __CLOCK_H__ */ + +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_debug.cpp b/STM32F4/libraries/arduino_uip/utility/uip_debug.cpp new file mode 100644 index 0000000..444bd0e --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_debug.cpp @@ -0,0 +1,170 @@ +#include +#include +#include +#include +extern "C" { + #import "utility/uip.h" +} + +struct uip_conn con[UIP_CONNS]; + +void +UIPDebug::uip_debug_printconns() +{ + for(uint8_t i=0;iripaddr,rhs->ripaddr)) + { + Serial.print(" ripaddr: "); + uip_debug_printbytes((const uint8_t *)lhs->ripaddr,4); + Serial.print(" -> "); + uip_debug_printbytes((const uint8_t *)rhs->ripaddr,4); + Serial.println(); + uip_ipaddr_copy(lhs->ripaddr,rhs->ripaddr); + changed = true; + } + if (lhs->lport != rhs->lport) + { + Serial.print(" lport: "); + Serial.print(htons(lhs->lport)); + Serial.print(" -> "); + Serial.println(htons(rhs->lport)); + lhs->lport = rhs->lport; + changed = true; + } + if (lhs->rport != rhs->rport) + { + Serial.print(" rport: "); + Serial.print(htons(lhs->rport)); + Serial.print(" -> "); + Serial.println(htons(rhs->rport)); + lhs->rport = rhs->rport; + changed = true; + } + if ((uint32_t)lhs->rcv_nxt[0] != (uint32_t)rhs->rcv_nxt[0]) + { + Serial.print(" rcv_nxt: "); + uip_debug_printbytes(lhs->rcv_nxt,4); + Serial.print(" -> "); + uip_debug_printbytes(rhs->rcv_nxt,4); + *((uint32_t *)&lhs->rcv_nxt[0]) = (uint32_t)rhs->rcv_nxt[0]; + Serial.println(); + changed = true; + } + if ((uint32_t)lhs->snd_nxt[0] != (uint32_t)rhs->snd_nxt[0]) + { + Serial.print(" snd_nxt: "); + uip_debug_printbytes(lhs->snd_nxt,4); + Serial.print(" -> "); + uip_debug_printbytes(rhs->snd_nxt,4); + *((uint32_t *)&lhs->snd_nxt[0]) = (uint32_t)rhs->snd_nxt[0]; + Serial.println(); + changed = true; + } + if (lhs->len != rhs->len) + { + Serial.print(" len: "); + Serial.print(lhs->len); + Serial.print(" -> "); + Serial.println(rhs->len); + lhs->len = rhs->len; + changed = true; + } + if (lhs->mss != rhs->mss) + { + Serial.print(" mss: "); + Serial.print(lhs->mss); + Serial.print(" -> "); + Serial.println(rhs->mss); + lhs->mss = rhs->mss; + changed = true; + } + if (lhs->initialmss != rhs->initialmss) + { + Serial.print(" initialmss: "); + Serial.print(lhs->initialmss); + Serial.print(" -> "); + Serial.println(rhs->initialmss); + lhs->initialmss = rhs->initialmss; + changed = true; + } + if (lhs->sa != rhs->sa) + { + Serial.print(" sa: "); + Serial.print(lhs->sa); + Serial.print(" -> "); + Serial.println(rhs->sa); + lhs->sa = rhs->sa; + changed = true; + } + if (lhs->sv != rhs->sv) + { + Serial.print(" sv: "); + Serial.print(lhs->sv); + Serial.print(" -> "); + Serial.println(rhs->sv); + lhs->sv = rhs->sv; + changed = true; + } + if (lhs->rto != rhs->rto) + { + Serial.print(" rto: "); + Serial.print(lhs->rto); + Serial.print(" -> "); + Serial.println(rhs->rto); + lhs->rto = rhs->rto; + changed = true; + } + if (lhs->tcpstateflags != rhs->tcpstateflags) + { + Serial.print(" tcpstateflags: "); + Serial.print(lhs->tcpstateflags); + Serial.print(" -> "); + Serial.println(rhs->tcpstateflags); + lhs->tcpstateflags = rhs->tcpstateflags; + changed = true; + } + if (lhs->timer != rhs->timer) + { + Serial.print(" timer: "); + Serial.print(lhs->timer); + Serial.print(" -> "); + Serial.println(rhs->timer); + lhs->timer = rhs->timer; + changed = true; + } + if (lhs->nrtx != rhs->nrtx) + { + Serial.print(" nrtx: "); + Serial.print(lhs->nrtx); + Serial.print(" -> "); + Serial.println(rhs->nrtx); + lhs->nrtx = rhs->nrtx; + changed = true; + } + return changed; +} + +void +UIPDebug::uip_debug_printbytes(const uint8_t *data, uint8_t len) +{ + for(uint8_t i=0;i + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.c,v 1.2 2006/06/12 08:00:30 adam Exp $ + */ + +#include "uip_clock.h" +#include "uip_timer.h" + +/*---------------------------------------------------------------------------*/ +/** + * Set a timer. + * + * This function is used to set a timer for a time sometime in the + * future. The function timer_expired() will evaluate to true after + * the timer has expired. + * + * \param t A pointer to the timer + * \param interval The interval before the timer expires. + * + */ +void +uip_timer_set(struct uip_timer *t, clock_time_t interval) +{ + t->interval = interval; + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Reset the timer with the same interval. + * + * This function resets the timer with the same interval that was + * given to the timer_set() function. The start point of the interval + * is the exact time that the timer last expired. Therefore, this + * function will cause the timer to be stable over time, unlike the + * timer_rester() function. + * + * \param t A pointer to the timer. + * + * \sa timer_restart() + */ +void +uip_timer_reset(struct uip_timer *t) +{ + t->start += t->interval; +} +/*---------------------------------------------------------------------------*/ +/** + * Restart the timer from the current point in time + * + * This function restarts a timer with the same interval that was + * given to the timer_set() function. The timer will start at the + * current time. + * + * \note A periodic timer will drift if this function is used to reset + * it. For preioric timers, use the timer_reset() function instead. + * + * \param t A pointer to the timer. + * + * \sa timer_reset() + */ +void +uip_timer_restart(struct uip_timer *t) +{ + t->start = clock_time(); +} +/*---------------------------------------------------------------------------*/ +/** + * Check if a timer has expired. + * + * This function tests if a timer has expired and returns true or + * false depending on its status. + * + * \param t A pointer to the timer + * + * \return Non-zero if the timer has expired, zero otherwise. + * + */ +int +uip_timer_expired(struct uip_timer *t) +{ + return (clock_time_t)(clock_time() - t->start) >= (clock_time_t)t->interval; +} +/*---------------------------------------------------------------------------*/ + +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uip_timer.h b/STM32F4/libraries/arduino_uip/utility/uip_timer.h new file mode 100644 index 0000000..f260349 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uip_timer.h @@ -0,0 +1,86 @@ +/** + * \defgroup timer Timer library + * + * The timer library provides functions for setting, resetting and + * restarting timers, and for checking if a timer has expired. An + * application must "manually" check if its timers have expired; this + * is not done automatically. + * + * A timer is declared as a \c struct \c timer and all access to the + * timer is made by a pointer to the declared timer. + * + * \note The timer library uses the \ref clock "Clock library" to + * measure time. Intervals should be specified in the format used by + * the clock library. + * + * @{ + */ + + +/** + * \file + * Timer library header file. + * \author + * Adam Dunkels + */ + +/* + * Copyright (c) 2004, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack + * + * Author: Adam Dunkels + * + * $Id: timer.h,v 1.3 2006/06/11 21:46:39 adam Exp $ + */ +#ifndef __UIP_TIMER_H__ +#define __UIP_TIMER_H__ + +#include "uip_clock.h" + +/** + * A timer. + * + * This structure is used for declaring a timer. The timer must be set + * with timer_set() before it can be used. + * + * \hideinitializer + */ +struct uip_timer { + clock_time_t start; + clock_time_t interval; +}; + +void uip_timer_set(struct uip_timer *t, clock_time_t interval); +void uip_timer_reset(struct uip_timer *t); +void uip_timer_restart(struct uip_timer *t); +int uip_timer_expired(struct uip_timer *t); + +#endif /* __UIP_TIMER_H__ */ + +/** @} */ diff --git a/STM32F4/libraries/arduino_uip/utility/uipethernet-conf.h b/STM32F4/libraries/arduino_uip/utility/uipethernet-conf.h new file mode 100644 index 0000000..9dd8b27 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uipethernet-conf.h @@ -0,0 +1,29 @@ +#ifndef UIPETHERNET_CONF_H +#define UIPETHERNET_CONF_H + +/* for TCP */ +#define UIP_SOCKET_NUMPACKETS 5 +#define UIP_CONF_MAX_CONNECTIONS 4 + +/* for UDP + * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */ +#define UIP_CONF_UDP 1 +#define UIP_CONF_BROADCAST 1 +#define UIP_CONF_UDP_CONNS 4 + +/* number of attempts on write before returning number of bytes sent so far + * set to -1 to block until connection is closed by timeout */ +#define UIP_ATTEMPTS_ON_WRITE -1 + +/* timeout after which UIPClient::connect gives up. The timeout is specified in seconds. + * if set to a number <= 0 connect will timeout when uIP does (which might be longer than you expect...) */ +#define UIP_CONNECT_TIMEOUT -1 + +/* periodic timer for uip (in ms) */ +#define UIP_PERIODIC_TIMER 250 + +/* timer to poll client for data after last write (in ms) + * set to -1 to disable fast polling and rely on periodic only (saves 100 bytes flash) */ +#define UIP_CLIENT_TIMER 10 + +#endif diff --git a/STM32F4/libraries/arduino_uip/utility/uipopt.h b/STM32F4/libraries/arduino_uip/utility/uipopt.h new file mode 100644 index 0000000..42badf8 --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/uipopt.h @@ -0,0 +1,543 @@ +/** + * \defgroup uipopt Configuration options for uIP + * @{ + * + * uIP is configured using the per-project configuration file + * uipopt.h. This file contains all compile-time options for uIP and + * should be tweaked to match each specific project. The uIP + * distribution contains a documented example "uipopt.h" that can be + * copied and modified for each project. + * + * \note Most of the configuration options in the uipopt.h should not + * be changed, but rather the per-project uip-conf.h file. + */ + +/** + * \file + * Configuration options for uIP. + * \author Adam Dunkels + * + * This file is used for tweaking various configuration options for + * uIP. You should make a copy of this file into one of your project's + * directories instead of editing this example "uipopt.h" file that + * comes with the uIP distribution. + */ + +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uipopt.h,v 1.4 2006/06/12 08:00:31 adam Exp $ + * + */ + +#ifndef __UIPOPT_H__ +#define __UIPOPT_H__ + +#ifndef UIP_LITTLE_ENDIAN +#define UIP_LITTLE_ENDIAN 3412 +#endif /* UIP_LITTLE_ENDIAN */ +#ifndef UIP_BIG_ENDIAN +#define UIP_BIG_ENDIAN 1234 +#endif /* UIP_BIG_ENDIAN */ + +#include "uip-conf.h" + +/*------------------------------------------------------------------------------*/ + +/** + * \name Static configuration options + * @{ + * + * These configuration options can be used for setting the IP address + * settings statically, but only if UIP_FIXEDADDR is set to 1. The + * configuration options for a specific node includes IP address, + * netmask and default router as well as the Ethernet address. The + * netmask, default router and Ethernet address are appliciable only + * if uIP should be run over Ethernet. + * + * All of these should be changed to suit your project. +*/ + +/** + * Determines if uIP should use a fixed IP address or not. + * + * If uIP should use a fixed IP address, the settings are set in the + * uipopt.h file. If not, the macros uip_sethostaddr(), + * uip_setdraddr() and uip_setnetmask() should be used instead. + * + * \hideinitializer + */ +#define UIP_FIXEDADDR 0 + +/** + * Ping IP address asignment. + * + * uIP uses a "ping" packets for setting its own IP address if this + * option is set. If so, uIP will start with an empty IP address and + * the destination IP address of the first incoming "ping" (ICMP echo) + * packet will be used for setting the hosts IP address. + * + * \note This works only if UIP_FIXEDADDR is 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_PINGADDRCONF +#define UIP_PINGADDRCONF UIP_CONF_PINGADDRCONF +#else /* UIP_CONF_PINGADDRCONF */ +#define UIP_PINGADDRCONF 0 +#endif /* UIP_CONF_PINGADDRCONF */ + + +/** + * Specifies if the uIP ARP module should be compiled with a fixed + * Ethernet MAC address or not. + * + * If this configuration option is 0, the macro uip_setethaddr() can + * be used to specify the Ethernet address at run-time. + * + * \hideinitializer + */ +#define UIP_FIXEDETHADDR 0 + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name IP configuration options + * @{ + * + */ +/** + * The IP TTL (time to live) of IP packets sent by uIP. + * + * This should normally not be changed. + */ +#define UIP_TTL 64 + +/** + * Turn on support for IP packet reassembly. + * + * uIP supports reassembly of fragmented IP packets. This features + * requires an additonal amount of RAM to hold the reassembly buffer + * and the reassembly code size is approximately 700 bytes. The + * reassembly buffer is of the same size as the uip_buf buffer + * (configured by UIP_BUFSIZE). + * + * \note IP packet reassembly is not heavily tested. + * + * \hideinitializer + */ +#define UIP_REASSEMBLY 0 + +/** + * The maximum time an IP fragment should wait in the reassembly + * buffer before it is dropped. + * + */ +#define UIP_REASS_MAXAGE 40 + +/** @} */ + +/*------------------------------------------------------------------------------*/ +/** + * \name UDP configuration options + * @{ + */ + +/** + * Toggles wether UDP support should be compiled in or not. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP +#define UIP_UDP UIP_CONF_UDP +#else /* UIP_CONF_UDP */ +#define UIP_UDP 0 +#endif /* UIP_CONF_UDP */ + +/** + * Toggles if UDP checksums should be used or not. + * + * \note Support for UDP checksums is currently not included in uIP, + * so this option has no function. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CHECKSUMS +#define UIP_UDP_CHECKSUMS UIP_CONF_UDP_CHECKSUMS +#else +#define UIP_UDP_CHECKSUMS 0 +#endif + +/** + * The maximum amount of concurrent UDP connections. + * + * \hideinitializer + */ +#ifdef UIP_CONF_UDP_CONNS +#define UIP_UDP_CONNS UIP_CONF_UDP_CONNS +#else /* UIP_CONF_UDP_CONNS */ +#define UIP_UDP_CONNS 10 +#endif /* UIP_CONF_UDP_CONNS */ + +/** + * The name of the function that should be called when UDP datagrams arrive. + * + * \hideinitializer + */ + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name TCP configuration options + * @{ + */ + +/** + * Determines if support for opening connections from uIP should be + * compiled in. + * + * If the applications that are running on top of uIP for this project + * do not need to open outgoing TCP connections, this configration + * option can be turned off to reduce the code size of uIP. + * + * \hideinitializer + */ +#define UIP_ACTIVE_OPEN 1 + +/** + * The maximum number of simultaneously open TCP connections. + * + * Since the TCP connections are statically allocated, turning this + * configuration knob down results in less RAM used. Each TCP + * connection requires approximatly 30 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_CONNECTIONS +#define UIP_CONNS 10 +#else /* UIP_CONF_MAX_CONNECTIONS */ +#define UIP_CONNS UIP_CONF_MAX_CONNECTIONS +#endif /* UIP_CONF_MAX_CONNECTIONS */ + + +/** + * The maximum number of simultaneously listening TCP ports. + * + * Each listening TCP port requires 2 bytes of memory. + * + * \hideinitializer + */ +#ifndef UIP_CONF_MAX_LISTENPORTS +#define UIP_LISTENPORTS 20 +#else /* UIP_CONF_MAX_LISTENPORTS */ +#define UIP_LISTENPORTS UIP_CONF_MAX_LISTENPORTS +#endif /* UIP_CONF_MAX_LISTENPORTS */ + +/** + * Determines if support for TCP urgent data notification should be + * compiled in. + * + * Urgent data (out-of-band data) is a rarely used TCP feature that + * very seldom would be required. + * + * \hideinitializer + */ +#define UIP_URGDATA 0 + +/** + * The initial retransmission timeout counted in timer pulses. + * + * This should not be changed. + */ +#define UIP_RTO 3 + +/** + * The maximum number of times a segment should be retransmitted + * before the connection should be aborted. + * + * This should not be changed. + */ +#define UIP_MAXRTX 8 + +/** + * The maximum number of times a SYN segment should be retransmitted + * before a connection request should be deemed to have been + * unsuccessful. + * + * This should not need to be changed. + */ +#define UIP_MAXSYNRTX 5 + +/** + * The TCP maximum segment size. + * + * This is should not be to set to more than + * UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN. + */ +#ifndef UIP_CONF_TCP_MSS +#define UIP_TCP_MSS (UIP_BUFSIZE - UIP_LLH_LEN - UIP_TCPIP_HLEN) +#else +#define UIP_TCP_MSS UIP_CONF_TCP_MSS +#endif + +/** + * The size of the advertised receiver's window. + * + * Should be set low (i.e., to the size of the uip_buf buffer) is the + * application is slow to process incoming data, or high (32768 bytes) + * if the application processes data quickly. + * + * \hideinitializer + */ +#ifndef UIP_CONF_RECEIVE_WINDOW +#define UIP_RECEIVE_WINDOW UIP_TCP_MSS +#else +#define UIP_RECEIVE_WINDOW UIP_CONF_RECEIVE_WINDOW +#endif + +/** + * How long a connection should stay in the TIME_WAIT state. + * + * This configiration option has no real implication, and it should be + * left untouched. + */ +#define UIP_TIME_WAIT_TIMEOUT 120 + + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name ARP configuration options + * @{ + */ + +/** + * The size of the ARP table. + * + * This option should be set to a larger value if this uIP node will + * have many connections from the local network. + * + * \hideinitializer + */ +#ifdef UIP_CONF_ARPTAB_SIZE +#define UIP_ARPTAB_SIZE UIP_CONF_ARPTAB_SIZE +#else +#define UIP_ARPTAB_SIZE 8 +#endif + +/** + * The maxium age of ARP table entries measured in 10ths of seconds. + * + * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD + * default). + */ +#define UIP_ARP_MAXAGE 120 + +/** @} */ + +/*------------------------------------------------------------------------------*/ + +/** + * \name General configuration options + * @{ + */ + +/** + * The size of the uIP packet buffer. + * + * The uIP packet buffer should not be smaller than 60 bytes, and does + * not need to be larger than 1500 bytes. Lower size results in lower + * TCP throughput, larger size results in higher TCP throughput. + * + * \hideinitializer + */ +#ifndef UIP_CONF_BUFFER_SIZE +#define UIP_BUFSIZE 400 +#else /* UIP_CONF_BUFFER_SIZE */ +#define UIP_BUFSIZE UIP_CONF_BUFFER_SIZE +#endif /* UIP_CONF_BUFFER_SIZE */ + + +/** + * Determines if statistics support should be compiled in. + * + * The statistics is useful for debugging and to show the user. + * + * \hideinitializer + */ +#ifndef UIP_CONF_STATISTICS +#define UIP_STATISTICS 0 +#else /* UIP_CONF_STATISTICS */ +#define UIP_STATISTICS UIP_CONF_STATISTICS +#endif /* UIP_CONF_STATISTICS */ + +/** + * Determines if logging of certain events should be compiled in. + * + * This is useful mostly for debugging. The function uip_log() + * must be implemented to suit the architecture of the project, if + * logging is turned on. + * + * \hideinitializer + */ +#ifndef UIP_CONF_LOGGING +#define UIP_LOGGING 0 +#else /* UIP_CONF_LOGGING */ +#define UIP_LOGGING UIP_CONF_LOGGING +#endif /* UIP_CONF_LOGGING */ + +/** + * Broadcast support. + * + * This flag configures IP broadcast support. This is useful only + * together with UDP. + * + * \hideinitializer + * + */ +#if UIP_UDP && UIP_CONF_BROADCAST +#define UIP_BROADCAST UIP_CONF_BROADCAST +#else /* UIP_CONF_BROADCAST */ +#define UIP_BROADCAST 0 +#endif /* UIP_CONF_BROADCAST */ + +/** + * Print out a uIP log message. + * + * This function must be implemented by the module that uses uIP, and + * is called by uIP whenever a log message is generated. + */ +void uip_log(char *msg); + +/** + * The link level header length. + * + * This is the offset into the uip_buf where the IP header can be + * found. For Ethernet, this should be set to 14. For SLIP, this + * should be set to 0. + * + * \hideinitializer + */ +#ifdef UIP_CONF_LLH_LEN +#define UIP_LLH_LEN UIP_CONF_LLH_LEN +#else /* UIP_CONF_LLH_LEN */ +#define UIP_LLH_LEN 14 +#endif /* UIP_CONF_LLH_LEN */ + +/** @} */ +/*------------------------------------------------------------------------------*/ +/** + * \name CPU architecture configuration + * @{ + * + * The CPU architecture configuration is where the endianess of the + * CPU on which uIP is to be run is specified. Most CPUs today are + * little endian, and the most notable exception are the Motorolas + * which are big endian. The BYTE_ORDER macro should be changed to + * reflect the CPU architecture on which uIP is to be run. + */ + +/** + * The byte order of the CPU architecture on which uIP is to be run. + * + * This option can be either BIG_ENDIAN (Motorola byte order) or + * LITTLE_ENDIAN (Intel byte order). + * + * \hideinitializer + */ +#ifdef UIP_CONF_BYTE_ORDER +#define UIP_BYTE_ORDER UIP_CONF_BYTE_ORDER +#else /* UIP_CONF_BYTE_ORDER */ +#define UIP_BYTE_ORDER UIP_LITTLE_ENDIAN +#endif /* UIP_CONF_BYTE_ORDER */ + +/** @} */ +/*------------------------------------------------------------------------------*/ + +/** + * \name Appication specific configurations + * @{ + * + * An uIP application is implemented using a single application + * function that is called by uIP whenever a TCP/IP event occurs. The + * name of this function must be registered with uIP at compile time + * using the UIP_APPCALL definition. + * + * uIP applications can store the application state within the + * uip_conn structure by specifying the type of the application + * structure by typedef:ing the type uip_tcp_appstate_t and uip_udp_appstate_t. + * + * The file containing the definitions must be included in the + * uipopt.h file. + * + * The following example illustrates how this can look. + \code + +void httpd_appcall(void); +#define UIP_APPCALL httpd_appcall + +struct httpd_state { + u8_t state; + u16_t count; + char *dataptr; + char *script; +}; +typedef struct httpd_state uip_tcp_appstate_t + \endcode + */ + +/** + * \var #define UIP_APPCALL + * + * The name of the application function that uIP should call in + * response to TCP/IP events. + * + */ + +/** + * \var typedef uip_tcp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ + +/** + * \var typedef uip_udp_appstate_t + * + * The type of the application state that is to be stored in the + * uip_conn structure. This usually is typedef:ed to a struct holding + * application state information. + */ +/** @} */ +/** @} */ + +#endif /* __UIPOPT_H__ */ diff --git a/STM32F4/libraries/arduino_uip/utility/util.h b/STM32F4/libraries/arduino_uip/utility/util.h new file mode 100644 index 0000000..06f3cee --- /dev/null +++ b/STM32F4/libraries/arduino_uip/utility/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( ((x)<< 8 & 0xFF00) | ((x)>> 8 & 0x00FF) ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ + ((x)<< 8 & 0x00FF0000UL) | \ + ((x)>> 8 & 0x0000FF00UL) | \ + ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif diff --git a/STM32F4/variants/discovery_f407/discovery_f4.cpp b/STM32F4/variants/discovery_f407/discovery_f4.cpp index c508fa3..6f1b453 100644 --- a/STM32F4/variants/discovery_f407/discovery_f4.cpp +++ b/STM32F4/variants/discovery_f407/discovery_f4.cpp @@ -61,9 +61,19 @@ void boardInit(void) { gpio_set_af_mode(GPIOB, 0, 2); gpio_set_af_mode(GPIOB, 1, 2); - //gpio_set_af_mode(GPIOA, 2, 7); //gpio_set_af_mode(GPIOA, 3, 7); + +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS + // PA8 Output the Master Clock MCO1 + gpio_set_af_mode(GPIOA, 8, 0); + // PB4 as alternate MISO Input + gpio_set_af_mode(GPIOB, 4, 5); + // PA5 as alternate SCK Output + gpio_set_af_mode(GPIOA, 5, 5); + // PA7 as alternate MOSI Output + gpio_set_af_mode(GPIOA, 7, 5); +#endif return; } diff --git a/STM32F4/variants/discovery_f407/discovery_f4.h b/STM32F4/variants/discovery_f407/discovery_f4.h index c1f2384..d7bb679 100644 --- a/STM32F4/variants/discovery_f407/discovery_f4.h +++ b/STM32F4/variants/discovery_f407/discovery_f4.h @@ -63,9 +63,17 @@ #define BOARD_UART5_RX_PIN Port2Pin('D', 2) #define BOARD_NR_SPI 3 +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS +#define BOARD_SPI1_NSS_PIN Port2Pin('C', 8) +#else #define BOARD_SPI1_NSS_PIN Port2Pin('A', 4) +#endif #define BOARD_SPI1_MOSI_PIN Port2Pin('A', 7) +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS +#define BOARD_SPI1_MISO_PIN Port2Pin('B', 4) +#else #define BOARD_SPI1_MISO_PIN Port2Pin('A', 6) +#endif #define BOARD_SPI1_SCK_PIN Port2Pin('A', 5) #define BOARD_SPI2_NSS_PIN Port2Pin('B',12) #define BOARD_SPI2_MOSI_PIN Port2Pin('B',15) @@ -76,7 +84,11 @@ #define BOARD_SPI3_MISO_PIN Port2Pin('B', 4) #define BOARD_SPI3_SCK_PIN Port2Pin('B', 3) +#ifdef ARDUINO_STM32F4_NETDUINO2PLUS +#define BOARD_SPI3B_NSS_PIN Port2Pin('B', 0) +#else #define BOARD_SPI3B_NSS_PIN Port2Pin('B', 8) +#endif #define BOARD_SPI3B_MOSI_PIN Port2Pin('C',12) #define BOARD_SPI3B_MISO_PIN Port2Pin('C',11) #define BOARD_SPI3B_SCK_PIN Port2Pin('C',10) diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/WdfCoInstaller01011.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/WdfCoInstaller01011.dll new file mode 100644 index 0000000..d49d291 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/WdfCoInstaller01011.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/install-filter.exe b/drivers/win/win_xp_legacy/maple-dfu/amd64/install-filter.exe new file mode 100644 index 0000000..e1ca7ad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/install-filter.exe differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.dll new file mode 100644 index 0000000..f916b08 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.sys b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.sys new file mode 100644 index 0000000..0718dfb Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0.sys differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0_x86.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0_x86.dll new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusb0_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.dll new file mode 100644 index 0000000..d8112b9 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.sys b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.sys new file mode 100644 index 0000000..e09ee12 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK.sys differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK_x86.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK_x86.dll new file mode 100644 index 0000000..0d41062 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/libusbK_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/amd64/winusbcoinstaller2.dll b/drivers/win/win_xp_legacy/maple-dfu/amd64/winusbcoinstaller2.dll new file mode 100644 index 0000000..30e5502 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/amd64/winusbcoinstaller2.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/installer_x64.exe b/drivers/win/win_xp_legacy/maple-dfu/installer_x64.exe new file mode 100644 index 0000000..221426f Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/installer_x64.exe differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/installer_x86.exe b/drivers/win/win_xp_legacy/maple-dfu/installer_x86.exe new file mode 100644 index 0000000..5a0ca9b Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/installer_x86.exe differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/license/libusb0/installer_license.txt b/drivers/win/win_xp_legacy/maple-dfu/license/libusb0/installer_license.txt new file mode 100644 index 0000000..6128be6 --- /dev/null +++ b/drivers/win/win_xp_legacy/maple-dfu/license/libusb0/installer_license.txt @@ -0,0 +1,851 @@ +Copyright (c) 2002-2004 Stephan Meyer, +Copyright (c) 2000-2004 Johannes Erdfelt, +Copyright (c) 2000-2004 Thomas Sailer, +Copyright (c) 2010 Travis Robinson, + +This software is distributed under the following licenses: +Driver: GNU General Public License (GPL) +Library, Test Files, Installer: GNU Lesser General Public License (LGPL) + +*********************************************************************** + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/drivers/win/win_xp_legacy/maple-dfu/usb_device.cat b/drivers/win/win_xp_legacy/maple-dfu/usb_device.cat new file mode 100644 index 0000000..919fa2b Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/usb_device.cat differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/usb_device.inf b/drivers/win/win_xp_legacy/maple-dfu/usb_device.inf new file mode 100644 index 0000000..e2a2a21 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/usb_device.inf differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/WdfCoInstaller01011.dll b/drivers/win/win_xp_legacy/maple-dfu/x86/WdfCoInstaller01011.dll new file mode 100644 index 0000000..e943ea4 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/WdfCoInstaller01011.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/install-filter.exe b/drivers/win/win_xp_legacy/maple-dfu/x86/install-filter.exe new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/install-filter.exe differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.dll b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.dll new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.sys b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.sys new file mode 100644 index 0000000..5322e5b Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0.sys differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0_x86.dll b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0_x86.dll new file mode 100644 index 0000000..6e475b9 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/libusb0_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.dll b/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.dll new file mode 100644 index 0000000..0d41062 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.dll differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.sys b/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.sys new file mode 100644 index 0000000..67b8ff4 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/libusbK.sys differ diff --git a/drivers/win/win_xp_legacy/maple-dfu/x86/winusbcoinstaller2.dll b/drivers/win/win_xp_legacy/maple-dfu/x86/winusbcoinstaller2.dll new file mode 100644 index 0000000..fc450d2 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-dfu/x86/winusbcoinstaller2.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/WdfCoInstaller01011.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/WdfCoInstaller01011.dll new file mode 100644 index 0000000..d49d291 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/WdfCoInstaller01011.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/install-filter.exe b/drivers/win/win_xp_legacy/maple-serial/amd64/install-filter.exe new file mode 100644 index 0000000..e1ca7ad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/install-filter.exe differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.dll new file mode 100644 index 0000000..f916b08 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.sys b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.sys new file mode 100644 index 0000000..0718dfb Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0.sys differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0_x86.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0_x86.dll new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusb0_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.dll new file mode 100644 index 0000000..d8112b9 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.sys b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.sys new file mode 100644 index 0000000..e09ee12 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK.sys differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK_x86.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK_x86.dll new file mode 100644 index 0000000..0d41062 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/libusbK_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/amd64/winusbcoinstaller2.dll b/drivers/win/win_xp_legacy/maple-serial/amd64/winusbcoinstaller2.dll new file mode 100644 index 0000000..30e5502 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/amd64/winusbcoinstaller2.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/installer_x64.exe b/drivers/win/win_xp_legacy/maple-serial/installer_x64.exe new file mode 100644 index 0000000..221426f Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/installer_x64.exe differ diff --git a/drivers/win/win_xp_legacy/maple-serial/installer_x86.exe b/drivers/win/win_xp_legacy/maple-serial/installer_x86.exe new file mode 100644 index 0000000..5a0ca9b Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/installer_x86.exe differ diff --git a/drivers/win/win_xp_legacy/maple-serial/license/libusb0/installer_license.txt b/drivers/win/win_xp_legacy/maple-serial/license/libusb0/installer_license.txt new file mode 100644 index 0000000..6128be6 --- /dev/null +++ b/drivers/win/win_xp_legacy/maple-serial/license/libusb0/installer_license.txt @@ -0,0 +1,851 @@ +Copyright (c) 2002-2004 Stephan Meyer, +Copyright (c) 2000-2004 Johannes Erdfelt, +Copyright (c) 2000-2004 Thomas Sailer, +Copyright (c) 2010 Travis Robinson, + +This software is distributed under the following licenses: +Driver: GNU General Public License (GPL) +Library, Test Files, Installer: GNU Lesser General Public License (LGPL) + +*********************************************************************** + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/drivers/win/win_xp_legacy/maple-serial/usb_device.cat b/drivers/win/win_xp_legacy/maple-serial/usb_device.cat new file mode 100644 index 0000000..3246883 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/usb_device.cat differ diff --git a/drivers/win/win_xp_legacy/maple-serial/usb_device.inf b/drivers/win/win_xp_legacy/maple-serial/usb_device.inf new file mode 100644 index 0000000..6c21238 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/usb_device.inf differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/WdfCoInstaller01011.dll b/drivers/win/win_xp_legacy/maple-serial/x86/WdfCoInstaller01011.dll new file mode 100644 index 0000000..e943ea4 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/WdfCoInstaller01011.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/install-filter.exe b/drivers/win/win_xp_legacy/maple-serial/x86/install-filter.exe new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/install-filter.exe differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.dll b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.dll new file mode 100644 index 0000000..5badbad Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.sys b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.sys new file mode 100644 index 0000000..5322e5b Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0.sys differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/libusb0_x86.dll b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0_x86.dll new file mode 100644 index 0000000..6e475b9 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/libusb0_x86.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.dll b/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.dll new file mode 100644 index 0000000..0d41062 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.dll differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.sys b/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.sys new file mode 100644 index 0000000..67b8ff4 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/libusbK.sys differ diff --git a/drivers/win/win_xp_legacy/maple-serial/x86/winusbcoinstaller2.dll b/drivers/win/win_xp_legacy/maple-serial/x86/winusbcoinstaller2.dll new file mode 100644 index 0000000..fc450d2 Binary files /dev/null and b/drivers/win/win_xp_legacy/maple-serial/x86/winusbcoinstaller2.dll differ diff --git a/tools/linux/install-udev-rules.sh b/tools/linux/install.sh similarity index 75% rename from tools/linux/install-udev-rules.sh rename to tools/linux/install.sh index df4a06d..32870a1 100755 --- a/tools/linux/install-udev-rules.sh +++ b/tools/linux/install.sh @@ -5,6 +5,11 @@ if sudo [ -w /etc/udev/rules.d ]; then sudo cp -v 45-maple.rules /etc/udev/rules.d/45-maple.rules sudo chown root:root /etc/udev/rules.d/45-maple.rules sudo chmod 644 /etc/udev/rules.d/45-maple.rules + echo "Reloading udev rules" + sudo udevadm control --reload-rules + echo "Adding current user to dialout group" + sudo adduser $USER dialout else echo "Couldn't copy to /etc/udev/rules.d/; you probably have to run this script as root? Or your distribution of Linux doesn't include udev; try running the IDE itself as root." fi + diff --git a/tools/linux/maple_upload b/tools/linux/maple_upload index 598c981..67acdaf 100755 --- a/tools/linux/maple_upload +++ b/tools/linux/maple_upload @@ -1,20 +1,37 @@ #!/bin/bash -set -e +#set -e + + if [ $# -lt 4 ]; then echo "Usage: $0 $# " >&2 exit 1 fi -dummy_port=$1; altID=$2; usbID=$3; binfile=$4; +dummy_port=$1; altID=$2; usbID=$3; binfile=$4; dummy_port_fullpath="/dev/$1" if [ $# -eq 5 ]; then dfuse_addr="--dfuse-address $5" else dfuse_addr="" fi + +# Get the directory where the script is running. +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# ----------------- IMPORTANT ----------------- +# The 2nd parameter to upload-reset is the delay after resetting before it exits +# This value is in milliseonds +# You may need to tune this to your system +# 750ms to 1500ms seems to work on my Mac + + +${DIR}/upload-reset ${dummy_port_fullpath} 750 + + #DFU_UTIL=$(dirname $0)/dfu-util/dfu-util DFU_UTIL=/usr/bin/dfu-util +DFU_UTIL=${DIR}/dfu-util/dfu-util if [ ! -x ${DFU_UTIL} ]; then echo "$0: error: cannot find ${DFU_UTIL}" >&2 exit 2 diff --git a/tools/linux/stm32flash/stm32flash b/tools/linux/stm32flash/stm32flash index 5370150..16872bb 100755 Binary files a/tools/linux/stm32flash/stm32flash and b/tools/linux/stm32flash/stm32flash differ diff --git a/tools/linux/upload-reset b/tools/linux/upload-reset new file mode 100755 index 0000000..26985b8 Binary files /dev/null and b/tools/linux/upload-reset differ diff --git a/tools/macosx/dfu-util/dfu-prefix b/tools/macosx/dfu-util/dfu-prefix new file mode 100755 index 0000000..5cbb235 Binary files /dev/null and b/tools/macosx/dfu-util/dfu-prefix differ diff --git a/tools/macosx/dfu-util/dfu-suffix b/tools/macosx/dfu-util/dfu-suffix new file mode 100755 index 0000000..d10eb10 Binary files /dev/null and b/tools/macosx/dfu-util/dfu-suffix differ diff --git a/tools/macosx/dfu-util/dfu-util b/tools/macosx/dfu-util/dfu-util new file mode 100755 index 0000000..04c12e3 Binary files /dev/null and b/tools/macosx/dfu-util/dfu-util differ diff --git a/tools/macosx/maple_upload b/tools/macosx/maple_upload index 50d849d..e198adb 100755 --- a/tools/macosx/maple_upload +++ b/tools/macosx/maple_upload @@ -39,7 +39,8 @@ else dfuse_addr="" fi -DFU_UTIL=/usr/local/bin/dfu-util +#DFU_UTIL=/usr/local/bin/dfu-util +DFU_UTIL=${DIR}/dfu-util/dfu-util if [ ! -x ${DFU_UTIL} ]; then DFU_UTIL=/opt/local/bin/dfu-util fi diff --git a/tools/macosx/stm32flash/stm32flash b/tools/macosx/stm32flash/stm32flash index 92fb6ba..ac8636e 100755 Binary files a/tools/macosx/stm32flash/stm32flash and b/tools/macosx/stm32flash/stm32flash differ diff --git a/tools/src/dfu-util b/tools/src/dfu-util deleted file mode 160000 index 604de4b..0000000 --- a/tools/src/dfu-util +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 604de4b1b39a16dbd57da5786d85ebd734cec339 diff --git a/tools/src/dfu-util/AUTHORS b/tools/src/dfu-util/AUTHORS new file mode 100755 index 0000000..bc16c9c --- /dev/null +++ b/tools/src/dfu-util/AUTHORS @@ -0,0 +1,30 @@ +Authors ordered by first contribution. + +Harald Welte +Werner Almesberger +Michael Lauer +Jim Huang +Stefan Schmidt +Daniel Willmann +Mike Frysinger +Uwe Hermann +C. Scott Ananian +Bernard Blackham +Holger Freyther +Marc Singer +James Perkins +Tommi Keisala +Pascal Schweizer +Bradley Scott +Uwe Bonnes +Andrey Smirnov +Jussi Timperi +Hans Petter Selasky +Bo Shen +Henrique de Almeida Mendonca +Bernd Krumboeck +Dennis Meier +Veli-Pekka Peltola +Dave Hylands +Michael Grzeschik +Paul Fertser diff --git a/tools/src/dfu-util/COPYING b/tools/src/dfu-util/COPYING new file mode 100755 index 0000000..fbdd65f --- /dev/null +++ b/tools/src/dfu-util/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/tools/src/dfu-util/ChangeLog b/tools/src/dfu-util/ChangeLog new file mode 100755 index 0000000..35a1da7 --- /dev/null +++ b/tools/src/dfu-util/ChangeLog @@ -0,0 +1,93 @@ +0.8: + o New, separate dfu-prefix tool (Uwe Bonnes) + o Allow filtering on serial number (Uwe Bonnes) + o Improved VID/PID/serial filtering (Bradley Scott) + o Support reading firmware from stdin (Tormod Volden) + o Warn if missing DFU suffix (Tormod Volden) + o Improved progress bar (Hans Petter Selasky) + o Fix dfuse leave option (Uwe Bonnes) + o Major code rework (Hans Petter Selasky) + o MS Visual Studio build support (Henrique Mendonca) + o dfuse-pack.py tool for .dfu files (Antonio Galeo) + o Many other fixes from many people + +2014-09-13: Tormod Volden + +0.7: + o Support for TI Stellaris devices (Tommi Keisala) + o Fix libusb detection on MacOSX (Marc Singer) + o Fix libusb detection on FreeBSD (Tormod Volden) + o Improved DfuSe support (Tormod Volden) + o Support all special commands (leave, unprotect, mass-erase) + o Arbitrary upload lengths + o "force" option for various possible (dangerous) overrides + +2012-10-07: Tormod Volden + +0.6: + o Add detach mode (Stefan Schmidt) + o Check return value on all libusb calls (Tormod Volden) + o Fix segmentation fault with -s option (Tormod Volden) + o Add DFU suffix manipulation tool (Stefan Schmidt) + o Port to Windows: (Tormod Volden, some parts based on work from Satz + Klauer) + o Port file handling to stdio streams + o Sleep() macros + o C99 types + o Pack structs + o Detect DfuSe device correctly on big-endian architectures (Tormod + Volden) + o Add dfuse progress indication on download (Tormod Volden) + o Cleanup: gcc pedantic, gcc extension, ... (Tormod Volden) + o Rely on page size from functional descriptor. Please report if you get + an error about it. (Tormod Volden) + o Add quirk for Maple since it reports wrong DFU version (Tormod Volden) + +2012-04-22: Stefan Schmidt + +0.5: + o DfuSe extension support for ST devices (Tormod Volden) + o Add initial support for bitWillDetach flag from DFU 1.1 (Tormod + Volden) + o Internal cleanup and some manual page fixes (Tormod Volden) + +2011-11-02: Stefan Schmidt + +0.4: + o Rework to use libusb-1.0 (Stefan Schmidt) + o DFU suffix support (Tormod Volden, Stefan Schmidt) + o Sspeed up DFU downloads directly into memory (Bernard Blackham) + o More flexible -d vid:pid parsing (Tormod Volden) + o Many bug fixes and cleanups + +2011-07-20: Stefan Schmidt + +0.3: + o quirks: Add OpenOCD to the poll timeout quirk table. + +2010-12-22: Stefan Schmidt + +0.2: + o Fix some typos on the website and the README (Antonio Ospite, Uwe + Hermann) + o Remove build rule for a static binary. We can use autotools for this. + (Mike Frysinger) + o Fix infinite loop in download error path (C. Scott Ananian) + o Break out to show the 'finished' in upload (C. Scott Ananian) + o Add GPLv2+ headers (Harald Welte) + o Remove dead code (commands.[ch]) remnescent of dfu-programmer (Harald + Welte) + o Simple quirk system with Openmoko quirk for missing bwPollTimeout (Tormod Volden) + o New default (1024) and clamping of transfer size (Tormod Volden) + o Verify sending of completion packet (Tormod Volden) + o Look for DFU functional descriptor among all descriptors (Tormod + Volden) + o Print out in which direction we are transferring data + o Abort in upload if the file already exists + +2010-11-17 Stefan Schmidt + +0.1: + Initial release + +2010-05-23 Stefan Schmidt diff --git a/tools/src/dfu-util/DEVICES.txt b/tools/src/dfu-util/DEVICES.txt new file mode 100755 index 0000000..682e62c --- /dev/null +++ b/tools/src/dfu-util/DEVICES.txt @@ -0,0 +1,20 @@ +List of supported software and hardware products: + +Software user (bootloader, etc) +------------------------------- +- Sam7DFU: http://www.openpcd.org/Sam7dfu +- U-boot: DFU patches +- Barebox: http://www.barebox.org/ +- Leaflabs: http://code.google.com/p/leaflabs/ +- Blackmagic DFU + +Products using DFU +------------------ +- OpenPCD (sam7dfu) +- Openmoko Neo 1973 and Freerunner (u-boot with DFU patches) +- Leaflabs Maple +- ATUSB from Qi Hardware +- STM32F105/7, STM32F2/F3/F4 in System Bootloader +- Blackmagic debug probe +- NXP LPC31xx/LPC43XX, e.g. LPC-Link and LPC-Link2, need binaries + with LPC prefix and encoding (LPC-Link) diff --git a/tools/src/dfu-util/Makefile.am b/tools/src/dfu-util/Makefile.am new file mode 100755 index 0000000..7318dd8 --- /dev/null +++ b/tools/src/dfu-util/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src doc + +EXTRA_DIST = autogen.sh TODO DEVICES.txt dfuse-pack.py diff --git a/tools/src/dfu-util/README b/tools/src/dfu-util/README new file mode 100755 index 0000000..acda06a --- /dev/null +++ b/tools/src/dfu-util/README @@ -0,0 +1,20 @@ +Dfu-util - Device Firmware Upgrade Utilities + +Dfu-util is the host side implementation of the DFU 1.0 [1] and DFU 1.1 [2] +specification of the USB forum. + +DFU is intended to download and upload firmware to devices connected over +USB. It ranges from small devices like micro-controller boards up to mobile +phones. With dfu-util you are able to download firmware to your device or +upload firmware from it. + +dfu-util has been tested with Openmoko Neo1973 and Freerunner and many +other devices. + +[1] DFU 1.0 spec: http://www.usb.org/developers/devclass_docs/usbdfu10.pdf +[2] DFU 1.1 spec: http://www.usb.org/developers/devclass_docs/DFU_1.1.pdf + +The official website is: + + http://dfu-util.gnumonks.org/ + diff --git a/tools/src/dfu-util/TODO b/tools/src/dfu-util/TODO new file mode 100755 index 0000000..7574512 --- /dev/null +++ b/tools/src/dfu-util/TODO @@ -0,0 +1,14 @@ +DfuSe: +- Do erase and write in two separate passes when downloading +- Skip "Set Address" command when downloading contiguous blocks +- Implement "Get Commands" command + +Devices: +- Research iPhone/iPod/iPad support + Heavily modified dfu-util fork here: + https://github.com/planetbeing/xpwn/tree/master/dfu-util +- Test against Niftylights + +Non-Code: +- Logo +- Re-License as LGPL for usage as library? diff --git a/tools/src/dfu-util/autogen.sh b/tools/src/dfu-util/autogen.sh new file mode 100755 index 0000000..5959508 --- /dev/null +++ b/tools/src/dfu-util/autogen.sh @@ -0,0 +1,2 @@ +#! /bin/sh +autoreconf -v -i diff --git a/tools/src/dfu-util/configure.ac b/tools/src/dfu-util/configure.ac new file mode 100755 index 0000000..8810f56 --- /dev/null +++ b/tools/src/dfu-util/configure.ac @@ -0,0 +1,41 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_PREREQ(2.59) +AC_INIT([dfu-util],[0.8],[dfu-util@lists.gnumonks.org],,[http://dfu-util.gnumonks.org]) +AC_CONFIG_AUX_DIR(m4) +AM_INIT_AUTOMAKE([foreign]) +AC_CONFIG_HEADERS([config.h]) + +# Test for new silent rules and enable only if they are available +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# Checks for programs. +AC_PROG_CC + +# Checks for libraries. +# On FreeBSD the libusb-1.0 is called libusb and resides in system location +AC_CHECK_LIB([usb], [libusb_init],, [native_libusb=no],) +AS_IF([test x$native_libusb = xno], [ + PKG_CHECK_MODULES([USB], [libusb-1.0 >= 1.0.0],, + AC_MSG_ERROR([*** Required libusb-1.0 >= 1.0.0 not installed ***])) +]) +AC_CHECK_LIB([usbpath],[usb_path2devnum],,,-lusb) + +LIBS="$LIBS $USB_LIBS" +CFLAGS="$CFLAGS $USB_CFLAGS" + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([usbpath.h windows.h sysexits.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T + +# Checks for library functions. +AC_FUNC_MEMCMP +AC_CHECK_FUNCS([ftruncate getpagesize nanosleep err]) + +AC_CONFIG_FILES(Makefile src/Makefile doc/Makefile) +AC_OUTPUT diff --git a/tools/src/dfu-util/device-logs/README b/tools/src/dfu-util/device-logs/README new file mode 100755 index 0000000..c1de3e7 --- /dev/null +++ b/tools/src/dfu-util/device-logs/README @@ -0,0 +1,77 @@ +Device: +------- +qi-hardware-atusb: +- Qi Hardware ben-wpan +- DFU implementation: + http://projects.qi-hardware.com/index.php/p/ben-wpan/source/tree/master/atusb/fw/usb +- Tester: Stefan Schmidt + +openpcd: +- OpenPCD RFID reader +- DFU implementation: SAM7DFU + http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git +- Tester: Stefan Schmidt + +simtrace: +- Sysmocom SimTrace +- DFU implementation: SAM7DFU + http://www.openpcd.org/Sam7dfu, git://git.gnumonks.org/openpcd.git +- Tester: Stefan Schmidt + +openmoko-freerunner: +- Openmoko Freerunner +- DFU implementation: Old U-Boot + http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches +- Tester: Stefan Schmidt + +openmoko-neo1973: +- Openmoko Neo1073 +- DFU implementation: Old U-Boot + http://git.openmoko.org/?p=u-boot.git;a=shortlog;h=refs/heads/mokopatches +- Tester: Stefan Schmidt + +tdk-bluetooth: +- TDK Corp. Bluetooth Adapter +- DFU implementation: closed soure +- Only upload has been tested +- Tester: Stefan Schmidt + +stm32f107: +- STM32 microcontrollers with built-in (ROM) DFU loader +- DFU implementation: Closed source but probably similar to the one + in their USB device libraries. Some relevant application notes: + http://www.st.com -> AN3156 and AN2606 +- Tested by Uwe Bonnes + +stm32f4discovery: +- STM32 microcontroller board with built-in (ROM) DFU loader +- DFU implementation: Closed source, probably similar to stm32f107. +- Tested by Joe Rothweiler + +dso-nano: +- DSO Nano pocket oscilloscope +- DFU implementation: Based on ST Microelectronics USB FS Library 1.0 + http://dsonano.googlecode.com/files/DS0201_OpenSource.rar +- Tester: Tormod Volden + +opc-20: +- Custom devices based on STM32F1xx +- DFU implementation: ST Microelectronics USB FS Device Library 3.1.0 + http://www.st.com -> um0424.zip +- Tester: Tormod Volden + +lpc-link, lpclink2: +- NXP LPCXpresso debug adapters +- Proprietary DFU implementation, uses special download files with + LPC prefix and encoding of the target firmware code +- Tested by Uwe Bonnes + +Adding the lsusb output and a download log of your device here helps +us to avoid regressions for hardware we cannot test while working on +the code. To extract the lsusb output use this command: +sudo lsusb -v -d $USBID > $DEVICE.lsusb +Prepare a description snippet as above, and send it to us. A log +(copy-paste of the command window) of a firmware download is also +nice, please use the double verbose option -v -v and include the +command line in the log file. + diff --git a/tools/src/dfu-util/device-logs/dsonano.lsusb b/tools/src/dfu-util/device-logs/dsonano.lsusb new file mode 100755 index 0000000..44a5d28 --- /dev/null +++ b/tools/src/dfu-util/device-logs/dsonano.lsusb @@ -0,0 +1,60 @@ + +Bus 002 Device 004: ID 0483:df11 SGS Thomson Microelectronics +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 SGS Thomson Microelectronics + idProduct 0xdf11 + bcdDevice 1.1a + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 DFU + iSerial 3 001 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 36 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 64mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 0 + iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 0 + iInterface 5 @SPI Flash : M25P64/0x00000000/64*064Kg,64*064Kg + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 11 + Will Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 255 milliseconds + wTransferSize 1024 bytes + bcdDFUVersion 1.1a +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/lpclink.log b/tools/src/dfu-util/device-logs/lpclink.log new file mode 100755 index 0000000..f2a04f7 --- /dev/null +++ b/tools/src/dfu-util/device-logs/lpclink.log @@ -0,0 +1,59 @@ +(The on-board LPC3154 has some encryption key set and LPCXpressoWIN.enc +is encrypted.) + +$ lsusb | grep NXP +Bus 003 Device 011: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link + +$ dfu-util -v -v -v -R -D /opt/lpc/lpcxpresso/bin/LPCXpressoWIN.enc + +dfu-util 0.7 + +Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. +Copyright 2010-2012 Tormod Volden and Stefan Schmidt +This program is Free Software and has ABSOLUTELY NO WARRANTY +Please report bugs to dfu-util@lists.gnumonks.org + +dfu-util: Invalid DFU suffix signature +dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! +Deducing device DFU version from functional descriptor length +Opening DFU capable USB device... +ID 0471:df55 +Run-time device DFU version 0100 +Claiming USB DFU Runtime Interface... +Determining device status: +state = dfuIDLE, status = 0 +dfu-util: WARNING: Runtime device already in DFU state ?!? +Claiming USB DFU Interface... +Setting Alternate Setting #0 ... +Determining device status: +state = dfuIDLE, status = 0 +dfuIDLE, continuing +DFU mode device DFU version 0100 +Device returned transfer size 2048 +Copying data from PC to DFU device +Download [ ] 0% 0 bytes +Download [= ] 6% 2048 bytes +Download [=== ] 13% 4096 bytes +Download [==== ] 19% 6144 bytes +Download [====== ] 26% 8192 bytes +Download [======== ] 32% 10240 bytes +Download [========= ] 39% 12288 bytes +Download [=========== ] 45% 14336 bytes +Download [============= ] 52% 16384 bytes +Download [============== ] 59% 18432 bytes +Download [================ ] 65% 20480 bytes +Download [================== ] 72% 22528 bytes +Download [=================== ] 78% 24576 bytes +Download [===================== ] 85% 26624 bytes +Download [====================== ] 91% 28672 bytes +Download [======================== ] 98% 29192 bytes +Download [=========================] 100% 29192 bytes +Download done. +Sent a total of 29192 bytes +state(8) = dfuMANIFEST-WAIT-RESET, status(0) = No error condition is present +Done! +dfu-util: can't detach +Resetting USB to switch back to runtime mode + +$ lsusb | grep NXP +Bus 003 Device 012: ID 1fc9:0009 NXP Semiconductors diff --git a/tools/src/dfu-util/device-logs/lpclink.lsusb b/tools/src/dfu-util/device-logs/lpclink.lsusb new file mode 100755 index 0000000..c80d2b7 --- /dev/null +++ b/tools/src/dfu-util/device-logs/lpclink.lsusb @@ -0,0 +1,58 @@ + +Bus 003 Device 008: ID 0471:df55 Philips (or NXP) LPCXpresso LPC-Link +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0471 Philips (or NXP) + idProduct 0xdf55 LPCXpresso LPC-Link + bcdDevice 0.01 + iManufacturer 0 + iProduct 0 + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 25 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 0 + iInterface 0 + Device Firmware Upgrade Interface Descriptor: + bLength 7 + bDescriptorType 33 + bmAttributes 1 + Will Not Detach + Manifestation Intolerant + Upload Unsupported + Download Supported + wDetachTimeout 65535 milliseconds + wTransferSize 2048 bytes +Device Qualifier (for other device speed): + bLength 10 + bDescriptorType 6 + bcdUSB 2.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + bNumConfigurations 1 +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/lpclink2.log b/tools/src/dfu-util/device-logs/lpclink2.log new file mode 100755 index 0000000..f33e671 --- /dev/null +++ b/tools/src/dfu-util/device-logs/lpclink2.log @@ -0,0 +1,59 @@ +$ lsusb | grep NXP +Bus 003 Device 013: ID 1fc9:000c NXP Semiconductors + +$ dfu-util -D ~/devel/dfu-util/firmware.bin.qthdr + +dfu-util 0.7 + +Copyright 2005-2008 Weston Schmidt, Harald Welte and OpenMoko Inc. +Copyright 2010-2012 Tormod Volden and Stefan Schmidt +This program is Free Software and has ABSOLUTELY NO WARRANTY +Please report bugs to dfu-util@lists.gnumonks.org + +dfu-util: Invalid DFU suffix signature +dfu-util: A valid DFU suffix will be required in a future dfu-util release!!! +Possible unencryptes NXP LPC DFU prefix with the following properties +Payload length: 39 kiByte +Opening DFU capable USB device... +ID 1fc9:000c +Run-time device DFU version 0100 +Claiming USB DFU Runtime Interface... +Determining device status: +state = dfuIDLE, status = 0 +dfu-util: WARNING: Runtime device already in DFU state ?!? +Claiming USB DFU Interface... +Setting Alternate Setting #0 ... +Determining device status: +state = dfuIDLE, status = 0 +dfuIDLE, continuing +DFU mode device DFU version 0100 +Device returned transfer size 2048 +Copying data from PC to DFU device +Download [ ] 0% 0 bytes +Download [= ] 4% 2048 bytes +Download [== ] 9% 4096 bytes +Download [=== ] 14% 6144 bytes +Download [==== ] 19% 8192 bytes +Download [====== ] 24% 10240 bytes +Download [======= ] 28% 12288 bytes +Download [======== ] 33% 14336 bytes +Download [========= ] 38% 16384 bytes +Download [========== ] 43% 18432 bytes +Download [============ ] 48% 20480 bytes +Download [============= ] 53% 22528 bytes +Download [============== ] 57% 24576 bytes +Download [=============== ] 62% 26624 bytes +Download [================ ] 67% 28672 bytes +Download [================== ] 72% 30720 bytes +Download [=================== ] 77% 32768 bytes +Download [==================== ] 82% 34816 bytes +Download [===================== ] 86% 36864 bytes +Download [====================== ] 91% 38912 bytes +Download [======================== ] 96% 40356 bytes +Download [=========================] 100% 40356 bytes +Download done. +Sent a total of 40356 bytes +dfu-util: unable to read DFU status + +$ lsusb | grep NXP +Bus 003 Device 014: ID 1fc9:0018 NXP Semiconductors diff --git a/tools/src/dfu-util/device-logs/lpclink2.lsusb b/tools/src/dfu-util/device-logs/lpclink2.lsusb new file mode 100755 index 0000000..d8d6e0c --- /dev/null +++ b/tools/src/dfu-util/device-logs/lpclink2.lsusb @@ -0,0 +1,203 @@ + +Bus 003 Device 007: ID 0c72:000c PEAK System PCAN-USB +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 16 + idVendor 0x0c72 PEAK System + idProduct 0x000c PCAN-USB + bcdDevice 1c.ff + iManufacturer 0 + iProduct 3 VER1:PEAK +VER2:02.8.01 +DAT :06.05.2004 +TIME:09:35:37 + ... + iSerial 0 + bNumConfigurations 3 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 46 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 200mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 4 + bInterfaceClass 0 (Defined at Interface level) + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 20 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 20 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 46 + bNumInterfaces 1 + bConfigurationValue 2 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 394mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 4 + bInterfaceClass 0 (Defined at Interface level) + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 20 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 20 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 46 + bNumInterfaces 1 + bConfigurationValue 3 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 200mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 4 + bInterfaceClass 0 (Defined at Interface level) + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x01 EP 1 OUT + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 +Device Status: 0x0001 + Self Powered diff --git a/tools/src/dfu-util/device-logs/opc-20.lsusb b/tools/src/dfu-util/device-logs/opc-20.lsusb new file mode 100755 index 0000000..25ad12f --- /dev/null +++ b/tools/src/dfu-util/device-logs/opc-20.lsusb @@ -0,0 +1,60 @@ + +Bus 001 Device 004: ID 0483:df11 SGS Thomson Microelectronics +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 SGS Thomson Microelectronics + idProduct 0xdf11 + bcdDevice 2.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 DFU + iSerial 3 ÿÿÿÿÿÿÿÿÿÿÿÿ + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 36 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 4 @Internal Flash /0x08000000/12*001Ka,116*001Kg + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 5 @SPI Flash : M25P64/0x00000000/128*64Kg + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 11 + Will Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 255 milliseconds + wTransferSize 1024 bytes + bcdDFUVersion 1a.01 +Device Status: 0x0001 + Self Powered diff --git a/tools/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb b/tools/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb new file mode 100755 index 0000000..64bd018 --- /dev/null +++ b/tools/src/dfu-util/device-logs/openmoko-freerunner-dfumode.lsusb @@ -0,0 +1,109 @@ +Bus 003 Device 017: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 16 + idVendor 0x1d50 OpenMoko, Inc. + idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader + bcdDevice 0.00 + iManufacturer 1 OpenMoko, Inc + iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 + iSerial 3 0000000 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 81 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 7 USB Device Firmware Upgrade + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 8 RAM 0x32000000 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 9 u-boot + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 2 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 10 u-boot_env + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 3 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 11 kernel + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 4 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 12 splash + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 5 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 13 factory + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 6 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 14 rootfs + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 7 + Will Not Detach + Manifestation Tolerant + Upload Supported + Download Supported + wDetachTimeout 65280 milliseconds + wTransferSize 4096 bytes + bcdDFUVersion 1.00 +Device Status: 0x0a00 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/openmoko-freerunner.lsusb b/tools/src/dfu-util/device-logs/openmoko-freerunner.lsusb new file mode 100755 index 0000000..cf148e5 --- /dev/null +++ b/tools/src/dfu-util/device-logs/openmoko-freerunner.lsusb @@ -0,0 +1,179 @@ +Bus 005 Device 033: ID 1d50:5119 OpenMoko, Inc. GTA01/GTA02 U-Boot Bootloader +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 2 Communications + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 16 + idVendor 0x1d50 OpenMoko, Inc. + idProduct 0x5119 GTA01/GTA02 U-Boot Bootloader + bcdDevice 0.00 + iManufacturer 1 OpenMoko, Inc + iProduct 2 Neo1973 Bootloader U-Boot 1.3.2-moko12 + iSerial 3 0000000 + bNumConfigurations 2 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 85 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 4 TTY via USB + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 Control Interface + CDC Header: + bcdCDC 0.6e + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 5 Bulk Data Interface + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 1 + iInterface 7 USB Device Firmware Upgrade + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 7 + Will Not Detach + Manifestation Tolerant + Upload Supported + Download Supported + wDetachTimeout 65280 milliseconds + wTransferSize 4096 bytes + bcdDFUVersion 1.00 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 67 + bNumInterfaces 2 + bConfigurationValue 2 + iConfiguration 4 TTY via USB + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 Control Interface + CDC Header: + bcdCDC 0.6e + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 5 Bulk Data Interface + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 +Device Status: 0x9a00 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/openmoko-neo1973.lsusb b/tools/src/dfu-util/device-logs/openmoko-neo1973.lsusb new file mode 100755 index 0000000..dc1fe7c --- /dev/null +++ b/tools/src/dfu-util/device-logs/openmoko-neo1973.lsusb @@ -0,0 +1,182 @@ + +Bus 006 Device 020: ID 1457:5119 First International Computer, Inc. OpenMoko Neo1973 u-boot cdc_acm serial port +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.10 + bDeviceClass 2 Communications + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 16 + idVendor 0x1457 First International Computer, Inc. + idProduct 0x5119 OpenMoko Neo1973 u-boot cdc_acm serial port + bcdDevice 0.00 + iManufacturer 1 + iProduct 2 + iSerial 3 + bNumConfigurations 2 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 85 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 4 + bmAttributes 0x80 + (Bus Powered) + MaxPower 500mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 + CDC Header: + bcdCDC 0.6e + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 1 + iInterface 7 + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 7 + Will Not Detach + Manifestation Tolerant + Upload Supported + Download Supported + wDetachTimeout 65280 milliseconds + wTransferSize 4096 bytes + bcdDFUVersion 1.00 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 67 + bNumInterfaces 2 + bConfigurationValue 2 + iConfiguration 4 + bmAttributes 0x80 + (Bus Powered) + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 2 Communications + bInterfaceSubClass 2 Abstract (modem) + bInterfaceProtocol 1 AT-commands (v.25ter) + iInterface 6 + CDC Header: + bcdCDC 0.6e + CDC Call Management: + bmCapabilities 0x00 + bDataInterface 1 + CDC ACM: + bmCapabilities 0x00 + CDC Union: + bMasterInterface 0 + bSlaveInterface 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 10 CDC Data + bInterfaceSubClass 0 Unused + bInterfaceProtocol 0 + iInterface 5 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 255 +Device Status: 0x0006 + (Bus Powered) + Remote Wakeup Enabled + Test Mode diff --git a/tools/src/dfu-util/device-logs/openpcd.lsusb b/tools/src/dfu-util/device-logs/openpcd.lsusb new file mode 100755 index 0000000..8618647 --- /dev/null +++ b/tools/src/dfu-util/device-logs/openpcd.lsusb @@ -0,0 +1,60 @@ + +Bus 006 Device 016: ID 16c0:076b VOTI OpenPCD 13.56MHz RFID Reader +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x16c0 VOTI + idProduct 0x076b OpenPCD 13.56MHz RFID Reader + bcdDevice 0.00 + iManufacturer 1 + iProduct 2 OpenPCD RFID Simulator - DFU Mode + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 36 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 200mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 0 + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 3 + Will Not Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 65280 milliseconds + wTransferSize 256 bytes + bcdDFUVersion 1.00 +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/qi-hardware-atusb.lsusb b/tools/src/dfu-util/device-logs/qi-hardware-atusb.lsusb new file mode 100755 index 0000000..d1da57a --- /dev/null +++ b/tools/src/dfu-util/device-logs/qi-hardware-atusb.lsusb @@ -0,0 +1,59 @@ + +Bus 006 Device 013: ID 20b7:1540 Qi Hardware ben-wpan, AT86RF230-based +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 255 Vendor Specific Class + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x20b7 Qi Hardware + idProduct 0x1540 ben-wpan, AT86RF230-based + bcdDevice 0.01 + iManufacturer 0 + iProduct 0 + iSerial 1 4630333438371508231a + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 34 + bNumInterfaces 2 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 40mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 1 + bInterfaceClass 255 Vendor Specific Class + bInterfaceSubClass 0 + bInterfaceProtocol 0 + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 0 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 1 + iInterface 0 +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/simtrace.lsusb b/tools/src/dfu-util/device-logs/simtrace.lsusb new file mode 100755 index 0000000..fd51539 --- /dev/null +++ b/tools/src/dfu-util/device-logs/simtrace.lsusb @@ -0,0 +1,70 @@ + +Bus 006 Device 017: ID 16c0:0762 VOTI +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 8 + idVendor 0x16c0 VOTI + idProduct 0x0762 + bcdDevice 0.00 + iManufacturer 1 sysmocom - systems for mobile communications GmbH + iProduct 2 SimTrace SIM Sniffer - DFU Mode + iSerial 0 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 45 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 3 SimTrace DFU Configuration + bmAttributes 0x80 + (Bus Powered) + MaxPower 200mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 4 SimTrace DFU Interface - Application Partition + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 5 SimTrace DFU Interface - Bootloader Partition + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 2 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 6 SimTrace DFU Interface - RAM + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 3 + Will Not Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 65280 milliseconds + wTransferSize 256 bytes + bcdDFUVersion 1.00 +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/sparkcore.lsusb b/tools/src/dfu-util/device-logs/sparkcore.lsusb new file mode 100755 index 0000000..79c529b --- /dev/null +++ b/tools/src/dfu-util/device-logs/sparkcore.lsusb @@ -0,0 +1,60 @@ + +Bus 001 Device 008: ID 1d50:607f OpenMoko, Inc. +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x1d50 OpenMoko, Inc. + idProduct 0x607f + bcdDevice 2.00 + iManufacturer 1 Spark Devices + iProduct 2 CORE DFU + iSerial 3 8D80527B5055 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 36 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 4 @Internal Flash /0x08000000/20*001Ka,108*001Kg + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 5 @SPI Flash : SST25x/0x00000000/512*04Kg + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 11 + Will Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 255 milliseconds + wTransferSize 1024 bytes + bcdDFUVersion 1.1a +Device Status: 0x0001 + Self Powered diff --git a/tools/src/dfu-util/device-logs/stm32f107.bin-download b/tools/src/dfu-util/device-logs/stm32f107.bin-download new file mode 100755 index 0000000..4d803fb --- /dev/null +++ b/tools/src/dfu-util/device-logs/stm32f107.bin-download @@ -0,0 +1,48 @@ +> src/dfu-util --intf 0 --alt 0 -v -v -v -s 0x8000000 -D test3 +dfu-util 0.4 + +(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. +(C) 2010-2011 Tormod Volden (DfuSe support) +This program is Free Software and has ABSOLUTELY NO WARRANTY + +dfu-util does currently only support DFU version 1.0 + +Opening DFU USB device... ID 0483:df11 +Run-time device DFU version 011a +Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/128*002Kg" +Claiming USB DFU Interface... +Setting Alternate Setting #0 ... +Determining device status: state = dfuIDLE, status = 0 +dfuIDLE, continuing +DFU mode device DFU version 011a +Device returned transfer size 2048 +No valid DFU suffix signature +Warning: File has no DFU suffix +DfuSe interface name: "Internal Flash " +Memory segment at 0x08000000 128 x 2048 = 262144 (rew) +Uploading to address = 0x08000000, size = 16384 +Erasing page size 2048 at address 0x08000000, page starting at 0x08000000 + Download from image offset 00000000 to memory 08000000-080007ff, size 2048 + Setting address pointer to 0x08000000 +Erasing page size 2048 at address 0x08000800, page starting at 0x08000800 + Download from image offset 00000800 to memory 08000800-08000fff, size 2048 + Setting address pointer to 0x08000800 +Erasing page size 2048 at address 0x08001000, page starting at 0x08001000 + Download from image offset 00001000 to memory 08001000-080017ff, size 2048 + Setting address pointer to 0x08001000 +Erasing page size 2048 at address 0x08001800, page starting at 0x08001800 + Download from image offset 00001800 to memory 08001800-08001fff, size 2048 + Setting address pointer to 0x08001800 +Erasing page size 2048 at address 0x08002000, page starting at 0x08002000 + Download from image offset 00002000 to memory 08002000-080027ff, size 2048 + Setting address pointer to 0x08002000 +Erasing page size 2048 at address 0x08002800, page starting at 0x08002800 + Download from image offset 00002800 to memory 08002800-08002fff, size 2048 + Setting address pointer to 0x08002800 +Erasing page size 2048 at address 0x08003000, page starting at 0x08003000 + Download from image offset 00003000 to memory 08003000-080037ff, size 2048 + Setting address pointer to 0x08003000 +Erasing page size 2048 at address 0x08003800, page starting at 0x08003800 + Download from image offset 00003800 to memory 08003800-08003fff, size 2048 + Setting address pointer to 0x08003800 + diff --git a/tools/src/dfu-util/device-logs/stm32f107.lsusb b/tools/src/dfu-util/device-logs/stm32f107.lsusb new file mode 100755 index 0000000..89d8d38 --- /dev/null +++ b/tools/src/dfu-util/device-logs/stm32f107.lsusb @@ -0,0 +1,60 @@ + +Bus 001 Device 028: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 SGS Thomson Microelectronics + idProduct 0xdf11 STM Device in DFU Mode + bcdDevice 20.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 0x418 DFU Bootloader + iSerial 3 STM32 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 36 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 4 @Internal Flash /0x08000000/128*002Kg + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 5 @Option Bytes /0x1FFFF800/01*016 g + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 11 + Will Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 255 milliseconds + wTransferSize 2048 bytes + bcdDFUVersion 1.1a +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/device-logs/stm32f4discovery.bin-download b/tools/src/dfu-util/device-logs/stm32f4discovery.bin-download new file mode 100755 index 0000000..d5a2679 --- /dev/null +++ b/tools/src/dfu-util/device-logs/stm32f4discovery.bin-download @@ -0,0 +1,36 @@ +dfu-util --device 0483:df11 --alt 0 \ + --dfuse-address 0x08000000 \ + -v -v -v \ + --download arm/iotoggle.bin +No valid DFU suffix signature +Warning: File has no DFU suffix +dfu-util 0.5 + +(C) 2005-2008 by Weston Schmidt, Harald Welte and OpenMoko Inc. +(C) 2010-2011 Tormod Volden (DfuSe support) +This program is Free Software and has ABSOLUTELY NO WARRANTY + +dfu-util does currently only support DFU version 1.0 + +Filter on vendor = 0x0483 product = 0xdf11 +Opening DFU capable USB device... ID 0483:df11 +Run-time device DFU version 011a +Found DFU: [0483:df11] devnum=0, cfg=1, intf=0, alt=0, name="@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg" +Claiming USB DFU Interface... +Setting Alternate Setting #0 ... +Determining device status: state = dfuERROR, status = 10 +dfuERROR, clearing status +Determining device status: state = dfuIDLE, status = 0 +dfuIDLE, continuing +DFU mode device DFU version 011a +Device returned transfer size 2048 +DfuSe interface name: "Internal Flash " +Memory segment at 0x08000000 4 x 16384 = 65536 (rew) +Memory segment at 0x08010000 1 x 65536 = 65536 (rew) +Memory segment at 0x08020000 7 x 131072 = 917504 (rew) +Uploading to address = 0x08000000, size = 2308 +Erasing page size 16384 at address 0x08000000, page starting at 0x08000000 + Download from image offset 00000000 to memory 08000000-080007ff, size 2048 + Setting address pointer to 0x08000000 + Download from image offset 00000800 to memory 08000800-08000903, size 260 + Setting address pointer to 0x08000800 diff --git a/tools/src/dfu-util/device-logs/stm32f4discovery.lsusb b/tools/src/dfu-util/device-logs/stm32f4discovery.lsusb new file mode 100755 index 0000000..c78530c --- /dev/null +++ b/tools/src/dfu-util/device-logs/stm32f4discovery.lsusb @@ -0,0 +1,80 @@ + +Bus 001 Device 010: ID 0483:df11 SGS Thomson Microelectronics STM Device in DFU Mode +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 1.00 + bDeviceClass 0 (Defined at Interface level) + bDeviceSubClass 0 + bDeviceProtocol 0 + bMaxPacketSize0 64 + idVendor 0x0483 SGS Thomson Microelectronics + idProduct 0xdf11 STM Device in DFU Mode + bcdDevice 21.00 + iManufacturer 1 STMicroelectronics + iProduct 2 STM32 BOOTLOADER + iSerial 3 315A28A0B956 + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 54 + bNumInterfaces 1 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0xc0 + Self Powered + MaxPower 100mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 4 @Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 1 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 5 @Option Bytes /0x1FFFC000/01*016 g + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 2 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 6 @OTP Memory /0x1FFF7800/01*512 g,01*016 g + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 3 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 2 + iInterface 7 @Device Feature/0xFFFF0000/01*004 g + Device Firmware Upgrade Interface Descriptor: + bLength 9 + bDescriptorType 33 + bmAttributes 11 + Will Detach + Manifestation Intolerant + Upload Supported + Download Supported + wDetachTimeout 255 milliseconds + wTransferSize 2048 bytes + bcdDFUVersion 1.1a +Device Status: 0x0001 + Self Powered diff --git a/tools/src/dfu-util/device-logs/tdk-bluetooth.lsusb b/tools/src/dfu-util/device-logs/tdk-bluetooth.lsusb new file mode 100755 index 0000000..ac07bb7 --- /dev/null +++ b/tools/src/dfu-util/device-logs/tdk-bluetooth.lsusb @@ -0,0 +1,269 @@ + +Bus 006 Device 014: ID 04bf:0320 TDK Corp. Bluetooth Adapter +Device Descriptor: + bLength 18 + bDescriptorType 1 + bcdUSB 2.00 + bDeviceClass 224 Wireless + bDeviceSubClass 1 Radio Frequency + bDeviceProtocol 1 Bluetooth + bMaxPacketSize0 64 + idVendor 0x04bf TDK Corp. + idProduct 0x0320 Bluetooth Adapter + bcdDevice 26.52 + iManufacturer 1 Ezurio + iProduct 2 Turbo Bluetooth Adapter + iSerial 3 008098D4FFBD + bNumConfigurations 1 + Configuration Descriptor: + bLength 9 + bDescriptorType 2 + wTotalLength 193 + bNumInterfaces 3 + bConfigurationValue 1 + iConfiguration 0 + bmAttributes 0x80 + (Bus Powered) + MaxPower 64mA + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 0 + bAlternateSetting 0 + bNumEndpoints 3 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x81 EP 1 IN + bmAttributes 3 + Transfer Type Interrupt + Synch Type None + Usage Type Data + wMaxPacketSize 0x0010 1x 16 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x02 EP 2 OUT + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x82 EP 2 IN + bmAttributes 2 + Transfer Type Bulk + Synch Type None + Usage Type Data + wMaxPacketSize 0x0040 1x 64 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 0 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0000 1x 0 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0000 1x 0 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 1 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0009 1x 9 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0009 1x 9 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 2 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0011 1x 17 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0011 1x 17 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 3 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0019 1x 25 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0019 1x 25 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 4 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0021 1x 33 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0021 1x 33 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 1 + bAlternateSetting 5 + bNumEndpoints 2 + bInterfaceClass 224 Wireless + bInterfaceSubClass 1 Radio Frequency + bInterfaceProtocol 1 Bluetooth + iInterface 0 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x03 EP 3 OUT + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0031 1x 49 bytes + bInterval 1 + Endpoint Descriptor: + bLength 7 + bDescriptorType 5 + bEndpointAddress 0x83 EP 3 IN + bmAttributes 1 + Transfer Type Isochronous + Synch Type None + Usage Type Data + wMaxPacketSize 0x0031 1x 49 bytes + bInterval 1 + Interface Descriptor: + bLength 9 + bDescriptorType 4 + bInterfaceNumber 2 + bAlternateSetting 0 + bNumEndpoints 0 + bInterfaceClass 254 Application Specific Interface + bInterfaceSubClass 1 Device Firmware Update + bInterfaceProtocol 0 + iInterface 0 + Device Firmware Upgrade Interface Descriptor: + bLength 7 + bDescriptorType 33 + bmAttributes 7 + Will Not Detach + Manifestation Tolerant + Upload Supported + Download Supported + wDetachTimeout 5000 milliseconds + wTransferSize 1023 bytes +Device Status: 0x0000 + (Bus Powered) diff --git a/tools/src/dfu-util/dfuse-pack.py b/tools/src/dfu-util/dfuse-pack.py new file mode 100755 index 0000000..022df6a --- /dev/null +++ b/tools/src/dfu-util/dfuse-pack.py @@ -0,0 +1,121 @@ +#!/usr/bin/python + +# Written by Antonio Galea - 2010/11/18 +# Distributed under Gnu LGPL 3.0 +# see http://www.gnu.org/licenses/lgpl-3.0.txt + +import sys,struct,zlib,os +from optparse import OptionParser + +DEFAULT_DEVICE="0x0483:0xdf11" + +def named(tuple,names): + return dict(zip(names.split(),tuple)) +def consume(fmt,data,names): + n = struct.calcsize(fmt) + return named(struct.unpack(fmt,data[:n]),names),data[n:] +def cstring(string): + return string.split('\0',1)[0] +def compute_crc(data): + return 0xFFFFFFFF & -zlib.crc32(data) -1 + +def parse(file,dump_images=False): + print 'File: "%s"' % file + data = open(file,'rb').read() + crc = compute_crc(data[:-4]) + prefix, data = consume('<5sBIB',data,'signature version size targets') + print '%(signature)s v%(version)d, image size: %(size)d, targets: %(targets)d' % prefix + for t in range(prefix['targets']): + tprefix, data = consume('<6sBI255s2I',data,'signature altsetting named name size elements') + tprefix['num'] = t + if tprefix['named']: + tprefix['name'] = cstring(tprefix['name']) + else: + tprefix['name'] = '' + print '%(signature)s %(num)d, alt setting: %(altsetting)s, name: "%(name)s", size: %(size)d, elements: %(elements)d' % tprefix + tsize = tprefix['size'] + target, data = data[:tsize], data[tsize:] + for e in range(tprefix['elements']): + eprefix, target = consume('<2I',target,'address size') + eprefix['num'] = e + print ' %(num)d, address: 0x%(address)08x, size: %(size)d' % eprefix + esize = eprefix['size'] + image, target = target[:esize], target[esize:] + if dump_images: + out = '%s.target%d.image%d.bin' % (file,t,e) + open(out,'wb').write(image) + print ' DUMPED IMAGE TO "%s"' % out + if len(target): + print "target %d: PARSE ERROR" % t + suffix = named(struct.unpack('<4H3sBI',data[:16]),'device product vendor dfu ufd len crc') + print 'usb: %(vendor)04x:%(product)04x, device: 0x%(device)04x, dfu: 0x%(dfu)04x, %(ufd)s, %(len)d, 0x%(crc)08x' % suffix + if crc != suffix['crc']: + print "CRC ERROR: computed crc32 is 0x%08x" % crc + data = data[16:] + if data: + print "PARSE ERROR" + +def build(file,targets,device=DEFAULT_DEVICE): + data = '' + for t,target in enumerate(targets): + tdata = '' + for image in target: + tdata += struct.pack('<2I',image['address'],len(image['data']))+image['data'] + tdata = struct.pack('<6sBI255s2I','Target',0,1,'ST...',len(tdata),len(target)) + tdata + data += tdata + data = struct.pack('<5sBIB','DfuSe',1,len(data)+11,len(targets)) + data + v,d=map(lambda x: int(x,0) & 0xFFFF, device.split(':',1)) + data += struct.pack('<4H3sB',0,d,v,0x011a,'UFD',16) + crc = compute_crc(data) + data += struct.pack(' and +Harald Welte . Over time, nearly complete +support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. +.SH LICENCE +.B dfu-util +is covered by the GNU General Public License (GPL), version 2 or later. +.SH COPYRIGHT +This manual page was originally written by Uwe Hermann , +and is now part of the dfu-util project. diff --git a/tools/src/dfu-util/msvc/README_msvc.txt b/tools/src/dfu-util/msvc/README_msvc.txt new file mode 100755 index 0000000..25aeeed --- /dev/null +++ b/tools/src/dfu-util/msvc/README_msvc.txt @@ -0,0 +1,10 @@ +# (C) Roger Meier +# (C) Pascal Schweizer +# msvc folder is GPL-2.0+, LGPL-2.1+, BSD-3-Clause or MIT license(SPDX) + +Building dfu-util native on Windows with Visual Studio + +3rd party dependencies: +- libusbx ( git clone https://github.com/libusbx/libusbx.git ) + - getopt (part of libusbx: libusbx/examples/getopt) + diff --git a/tools/src/dfu-util/msvc/dfu-suffix_2010.vcxproj b/tools/src/dfu-util/msvc/dfu-suffix_2010.vcxproj new file mode 100755 index 0000000..87b7ead --- /dev/null +++ b/tools/src/dfu-util/msvc/dfu-suffix_2010.vcxproj @@ -0,0 +1,100 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA} + dfusuffix + dfu-suffix + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) + $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib + $(ExecutablePath) + + + $(ExecutablePath) + $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\dll;$(LibraryPath) + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + + + + Level3 + Disabled + HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + true + + + + + Level3 + MaxSpeed + true + true + HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + + + + + + + + + + + {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + + + + + + \ No newline at end of file diff --git a/tools/src/dfu-util/msvc/dfu-util_2010.sln b/tools/src/dfu-util/msvc/dfu-util_2010.sln new file mode 100755 index 0000000..e6c932c --- /dev/null +++ b/tools/src/dfu-util/msvc/dfu-util_2010.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-util", "dfu-util_2010.vcxproj", "{0E071A60-7EF2-4427-BAA8-9143CACB5BCB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C4F8746D-B27E-4806-95E5-2052174E923B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dfu-suffix", "dfu-suffix_2010.vcxproj", "{8F7600A2-3B37-4956-B39B-A1D43EF29EDA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "getopt_2010", "..\..\libusbx\msvc\getopt_2010.vcxproj", "{AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libusb-1.0 (static)", "..\..\libusbx\msvc\libusb_static_2010.vcxproj", "{349EE8F9-7D25-4909-AAF5-FF3FADE72187}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.ActiveCfg = Debug|Win32 + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|Win32.Build.0 = Debug|Win32 + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Debug|x64.ActiveCfg = Debug|Win32 + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.ActiveCfg = Release|Win32 + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|Win32.Build.0 = Release|Win32 + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB}.Release|x64.ActiveCfg = Release|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.ActiveCfg = Debug|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|Win32.Build.0 = Debug|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Debug|x64.ActiveCfg = Debug|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.ActiveCfg = Release|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|Win32.Build.0 = Release|Win32 + {8F7600A2-3B37-4956-B39B-A1D43EF29EDA}.Release|x64.ActiveCfg = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.ActiveCfg = Debug|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|Win32.Build.0 = Debug|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.ActiveCfg = Debug|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Debug|x64.Build.0 = Debug|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.ActiveCfg = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|Win32.Build.0 = Release|Win32 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.ActiveCfg = Release|x64 + {AE83E1B4-CE06-47EE-B7A3-C3A1D7C2D71E}.Release|x64.Build.0 = Release|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.ActiveCfg = Debug|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|Win32.Build.0 = Debug|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.ActiveCfg = Debug|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Debug|x64.Build.0 = Debug|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.ActiveCfg = Release|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|Win32.Build.0 = Release|Win32 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.ActiveCfg = Release|x64 + {349EE8F9-7D25-4909-AAF5-FF3FADE72187}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/tools/src/dfu-util/msvc/dfu-util_2010.vcxproj b/tools/src/dfu-util/msvc/dfu-util_2010.vcxproj new file mode 100755 index 0000000..cb07b64 --- /dev/null +++ b/tools/src/dfu-util/msvc/dfu-util_2010.vcxproj @@ -0,0 +1,120 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {0E071A60-7EF2-4427-BAA8-9143CACB5BCB} + dfuutil + dfu-util + + + + Application + true + MultiByte + + + Application + false + true + MultiByte + + + + + + + + + + + + + $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) + $(VCInstallDir)atlmfc\lib;$(VCInstallDir)lib + $(ExecutablePath) + + + $(ExecutablePath) + $(SolutionDir)..\..\libusbx\examples\getopt;$(SolutionDir)..\..\libusbx\libusb;$(IncludePath) + $(SolutionDir)..\$(Platform)\getopt\$(Configuration);$(LibraryPath) + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + + + + Level3 + Disabled + HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreadedDebug + + + true + + + + + + + + + Level3 + MaxSpeed + true + true + HAVE_WINDOWS_H;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + MultiThreaded + + + true + true + true + + + copy $(SolutionDir)..\$(Platform)\$(Configuration)\dll\libusb-1.0.dll $(SolutionDir)..\$(Platform)\$(ProjectName)\$(Configuration)\ + + + + + + + + + + + + + + + + + + + + + + + + + + {a2169bc8-cf99-40bf-83f3-b0e38f7067bd} + + + {349ee8f9-7d25-4909-aaf5-ff3fade72187} + + + + + + \ No newline at end of file diff --git a/tools/src/dfu-util/src/Makefile.am b/tools/src/dfu-util/src/Makefile.am new file mode 100755 index 0000000..b1f810a --- /dev/null +++ b/tools/src/dfu-util/src/Makefile.am @@ -0,0 +1,28 @@ +AM_CFLAGS = -Wall -Wextra + +bin_PROGRAMS = dfu-util dfu-suffix dfu-prefix +dfu_util_SOURCES = main.c \ + portable.h \ + dfu_load.c \ + dfu_load.h \ + dfu_util.c \ + dfu_util.h \ + dfuse.c \ + dfuse.h \ + dfuse_mem.c \ + dfuse_mem.h \ + dfu.c \ + dfu.h \ + usb_dfu.h \ + dfu_file.c \ + dfu_file.h \ + quirks.c \ + quirks.h + +dfu_suffix_SOURCES = suffix.c \ + dfu_file.h \ + dfu_file.c + +dfu_prefix_SOURCES = prefix.c \ + dfu_file.h \ + dfu_file.c diff --git a/tools/src/dfu-util/src/dfu.c b/tools/src/dfu-util/src/dfu.c new file mode 100755 index 0000000..050ad50 --- /dev/null +++ b/tools/src/dfu-util/src/dfu.c @@ -0,0 +1,357 @@ +/* + * Low-level DFU communication routines, originally taken from + * $Id: dfu.c,v 1.3 2006/06/20 06:28:04 schmidtw Exp $ + * (part of dfu-programmer). + * + * Copyright 2005-2006 Weston Schmidt + * Copyright 2011-2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +#include + +#include "portable.h" +#include "dfu.h" +#include "quirks.h" + +static int dfu_timeout = 5000; /* 5 seconds - default */ + +/* + * DFU_DETACH Request (DFU Spec 1.0, Section 5.1) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * timeout - the timeout in ms the USB device should wait for a pending + * USB reset before giving up and terminating the operation + * + * returns 0 or < 0 on error + */ +int dfu_detach( libusb_device_handle *device, + const unsigned short interface, + const unsigned short timeout ) +{ + return libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_DETACH, + /* wValue */ timeout, + /* wIndex */ interface, + /* Data */ NULL, + /* wLength */ 0, + dfu_timeout ); +} + + +/* + * DFU_DNLOAD Request (DFU Spec 1.0, Section 6.1.1) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * length - the total number of bytes to transfer to the USB + * device - must be less than wTransferSize + * data - the data to transfer + * + * returns the number of bytes written or < 0 on error + */ +int dfu_download( libusb_device_handle *device, + const unsigned short interface, + const unsigned short length, + const unsigned short transaction, + unsigned char* data ) +{ + int status; + + status = libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_DNLOAD, + /* wValue */ transaction, + /* wIndex */ interface, + /* Data */ data, + /* wLength */ length, + dfu_timeout ); + return status; +} + + +/* + * DFU_UPLOAD Request (DFU Spec 1.0, Section 6.2) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * length - the maximum number of bytes to receive from the USB + * device - must be less than wTransferSize + * data - the buffer to put the received data in + * + * returns the number of bytes received or < 0 on error + */ +int dfu_upload( libusb_device_handle *device, + const unsigned short interface, + const unsigned short length, + const unsigned short transaction, + unsigned char* data ) +{ + int status; + + status = libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_UPLOAD, + /* wValue */ transaction, + /* wIndex */ interface, + /* Data */ data, + /* wLength */ length, + dfu_timeout ); + return status; +} + + +/* + * DFU_GETSTATUS Request (DFU Spec 1.0, Section 6.1.2) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * status - the data structure to be populated with the results + * + * return the number of bytes read in or < 0 on an error + */ +int dfu_get_status( struct dfu_if *dif, struct dfu_status *status ) +{ + unsigned char buffer[6]; + int result; + + /* Initialize the status data structure */ + status->bStatus = DFU_STATUS_ERROR_UNKNOWN; + status->bwPollTimeout = 0; + status->bState = STATE_DFU_ERROR; + status->iString = 0; + + result = libusb_control_transfer( dif->dev_handle, + /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_GETSTATUS, + /* wValue */ 0, + /* wIndex */ dif->interface, + /* Data */ buffer, + /* wLength */ 6, + dfu_timeout ); + + if( 6 == result ) { + status->bStatus = buffer[0]; + if (dif->quirks & QUIRK_POLLTIMEOUT) + status->bwPollTimeout = DEFAULT_POLLTIMEOUT; + else + status->bwPollTimeout = ((0xff & buffer[3]) << 16) | + ((0xff & buffer[2]) << 8) | + (0xff & buffer[1]); + status->bState = buffer[4]; + status->iString = buffer[5]; + } + + return result; +} + + +/* + * DFU_CLRSTATUS Request (DFU Spec 1.0, Section 6.1.3) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * + * return 0 or < 0 on an error + */ +int dfu_clear_status( libusb_device_handle *device, + const unsigned short interface ) +{ + return libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_OUT| LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_CLRSTATUS, + /* wValue */ 0, + /* wIndex */ interface, + /* Data */ NULL, + /* wLength */ 0, + dfu_timeout ); +} + + +/* + * DFU_GETSTATE Request (DFU Spec 1.0, Section 6.1.5) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * length - the maximum number of bytes to receive from the USB + * device - must be less than wTransferSize + * data - the buffer to put the received data in + * + * returns the state or < 0 on error + */ +int dfu_get_state( libusb_device_handle *device, + const unsigned short interface ) +{ + int result; + unsigned char buffer[1]; + + result = libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_GETSTATE, + /* wValue */ 0, + /* wIndex */ interface, + /* Data */ buffer, + /* wLength */ 1, + dfu_timeout ); + + /* Return the error if there is one. */ + if (result < 1) + return -1; + + /* Return the state. */ + return buffer[0]; +} + + +/* + * DFU_ABORT Request (DFU Spec 1.0, Section 6.1.4) + * + * device - the usb_dev_handle to communicate with + * interface - the interface to communicate with + * + * returns 0 or < 0 on an error + */ +int dfu_abort( libusb_device_handle *device, + const unsigned short interface ) +{ + return libusb_control_transfer( device, + /* bmRequestType */ LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_ABORT, + /* wValue */ 0, + /* wIndex */ interface, + /* Data */ NULL, + /* wLength */ 0, + dfu_timeout ); +} + + +const char* dfu_state_to_string( int state ) +{ + const char *message; + + switch (state) { + case STATE_APP_IDLE: + message = "appIDLE"; + break; + case STATE_APP_DETACH: + message = "appDETACH"; + break; + case STATE_DFU_IDLE: + message = "dfuIDLE"; + break; + case STATE_DFU_DOWNLOAD_SYNC: + message = "dfuDNLOAD-SYNC"; + break; + case STATE_DFU_DOWNLOAD_BUSY: + message = "dfuDNBUSY"; + break; + case STATE_DFU_DOWNLOAD_IDLE: + message = "dfuDNLOAD-IDLE"; + break; + case STATE_DFU_MANIFEST_SYNC: + message = "dfuMANIFEST-SYNC"; + break; + case STATE_DFU_MANIFEST: + message = "dfuMANIFEST"; + break; + case STATE_DFU_MANIFEST_WAIT_RESET: + message = "dfuMANIFEST-WAIT-RESET"; + break; + case STATE_DFU_UPLOAD_IDLE: + message = "dfuUPLOAD-IDLE"; + break; + case STATE_DFU_ERROR: + message = "dfuERROR"; + break; + default: + message = NULL; + break; + } + + return message; +} + +/* Chapter 6.1.2 */ +static const char *dfu_status_names[] = { + /* DFU_STATUS_OK */ + "No error condition is present", + /* DFU_STATUS_errTARGET */ + "File is not targeted for use by this device", + /* DFU_STATUS_errFILE */ + "File is for this device but fails some vendor-specific test", + /* DFU_STATUS_errWRITE */ + "Device is unable to write memory", + /* DFU_STATUS_errERASE */ + "Memory erase function failed", + /* DFU_STATUS_errCHECK_ERASED */ + "Memory erase check failed", + /* DFU_STATUS_errPROG */ + "Program memory function failed", + /* DFU_STATUS_errVERIFY */ + "Programmed memory failed verification", + /* DFU_STATUS_errADDRESS */ + "Cannot program memory due to received address that is out of range", + /* DFU_STATUS_errNOTDONE */ + "Received DFU_DNLOAD with wLength = 0, but device does not think that it has all data yet", + /* DFU_STATUS_errFIRMWARE */ + "Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations", + /* DFU_STATUS_errVENDOR */ + "iString indicates a vendor specific error", + /* DFU_STATUS_errUSBR */ + "Device detected unexpected USB reset signalling", + /* DFU_STATUS_errPOR */ + "Device detected unexpected power on reset", + /* DFU_STATUS_errUNKNOWN */ + "Something went wrong, but the device does not know what it was", + /* DFU_STATUS_errSTALLEDPKT */ + "Device stalled an unexpected request" +}; + + +const char *dfu_status_to_string(int status) +{ + if (status > DFU_STATUS_errSTALLEDPKT) + return "INVALID"; + return dfu_status_names[status]; +} + +int dfu_abort_to_idle(struct dfu_if *dif) +{ + int ret; + struct dfu_status dst; + + ret = dfu_abort(dif->dev_handle, dif->interface); + if (ret < 0) { + errx(EX_IOERR, "Error sending dfu abort request"); + exit(1); + } + ret = dfu_get_status(dif, &dst); + if (ret < 0) { + errx(EX_IOERR, "Error during abort get_status"); + exit(1); + } + if (dst.bState != DFU_STATE_dfuIDLE) { + errx(EX_IOERR, "Failed to enter idle state on abort"); + exit(1); + } + milli_sleep(dst.bwPollTimeout); + return ret; +} diff --git a/tools/src/dfu-util/src/dfu.h b/tools/src/dfu-util/src/dfu.h new file mode 100755 index 0000000..39f18c3 --- /dev/null +++ b/tools/src/dfu-util/src/dfu.h @@ -0,0 +1,133 @@ +/* + * dfu-programmer + * + * $Id: dfu.h,v 1.2 2005/09/25 01:27:42 schmidtw Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DFU_H +#define DFU_H + +#include +#include "usb_dfu.h" + +/* DFU states */ +#define STATE_APP_IDLE 0x00 +#define STATE_APP_DETACH 0x01 +#define STATE_DFU_IDLE 0x02 +#define STATE_DFU_DOWNLOAD_SYNC 0x03 +#define STATE_DFU_DOWNLOAD_BUSY 0x04 +#define STATE_DFU_DOWNLOAD_IDLE 0x05 +#define STATE_DFU_MANIFEST_SYNC 0x06 +#define STATE_DFU_MANIFEST 0x07 +#define STATE_DFU_MANIFEST_WAIT_RESET 0x08 +#define STATE_DFU_UPLOAD_IDLE 0x09 +#define STATE_DFU_ERROR 0x0a + + +/* DFU status */ +#define DFU_STATUS_OK 0x00 +#define DFU_STATUS_ERROR_TARGET 0x01 +#define DFU_STATUS_ERROR_FILE 0x02 +#define DFU_STATUS_ERROR_WRITE 0x03 +#define DFU_STATUS_ERROR_ERASE 0x04 +#define DFU_STATUS_ERROR_CHECK_ERASED 0x05 +#define DFU_STATUS_ERROR_PROG 0x06 +#define DFU_STATUS_ERROR_VERIFY 0x07 +#define DFU_STATUS_ERROR_ADDRESS 0x08 +#define DFU_STATUS_ERROR_NOTDONE 0x09 +#define DFU_STATUS_ERROR_FIRMWARE 0x0a +#define DFU_STATUS_ERROR_VENDOR 0x0b +#define DFU_STATUS_ERROR_USBR 0x0c +#define DFU_STATUS_ERROR_POR 0x0d +#define DFU_STATUS_ERROR_UNKNOWN 0x0e +#define DFU_STATUS_ERROR_STALLEDPKT 0x0f + +/* DFU commands */ +#define DFU_DETACH 0 +#define DFU_DNLOAD 1 +#define DFU_UPLOAD 2 +#define DFU_GETSTATUS 3 +#define DFU_CLRSTATUS 4 +#define DFU_GETSTATE 5 +#define DFU_ABORT 6 + +/* DFU interface */ +#define DFU_IFF_DFU 0x0001 /* DFU Mode, (not Runtime) */ + +/* This is based off of DFU_GETSTATUS + * + * 1 unsigned byte bStatus + * 3 unsigned byte bwPollTimeout + * 1 unsigned byte bState + * 1 unsigned byte iString +*/ + +struct dfu_status { + unsigned char bStatus; + unsigned int bwPollTimeout; + unsigned char bState; + unsigned char iString; +}; + +struct dfu_if { + struct usb_dfu_func_descriptor func_dfu; + uint16_t quirks; + uint16_t busnum; + uint16_t devnum; + uint16_t vendor; + uint16_t product; + uint16_t bcdDevice; + uint8_t configuration; + uint8_t interface; + uint8_t altsetting; + uint8_t flags; + uint8_t bMaxPacketSize0; + char *alt_name; + char *serial_name; + libusb_device *dev; + libusb_device_handle *dev_handle; + struct dfu_if *next; +}; + +int dfu_detach( libusb_device_handle *device, + const unsigned short interface, + const unsigned short timeout ); +int dfu_download( libusb_device_handle *device, + const unsigned short interface, + const unsigned short length, + const unsigned short transaction, + unsigned char* data ); +int dfu_upload( libusb_device_handle *device, + const unsigned short interface, + const unsigned short length, + const unsigned short transaction, + unsigned char* data ); +int dfu_get_status( struct dfu_if *dif, + struct dfu_status *status ); +int dfu_clear_status( libusb_device_handle *device, + const unsigned short interface ); +int dfu_get_state( libusb_device_handle *device, + const unsigned short interface ); +int dfu_abort( libusb_device_handle *device, + const unsigned short interface ); +int dfu_abort_to_idle( struct dfu_if *dif); + +const char *dfu_state_to_string( int state ); + +const char *dfu_status_to_string( int status ); + +#endif /* DFU_H */ diff --git a/tools/src/dfu-util/src/dfu_file.c b/tools/src/dfu-util/src/dfu_file.c new file mode 100755 index 0000000..2f5a585 --- /dev/null +++ b/tools/src/dfu-util/src/dfu_file.c @@ -0,0 +1,444 @@ +/* + * Load or store DFU files including suffix and prefix + * + * Copyright 2014 Tormod Volden + * Copyright 2012 Stefan Schmidt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "portable.h" +#include "dfu_file.h" + +#define DFU_SUFFIX_LENGTH 16 +#define LMDFU_PREFIX_LENGTH 8 +#define LPCDFU_PREFIX_LENGTH 16 +#define PROGRESS_BAR_WIDTH 25 +#define STDIN_CHUNK_SIZE 65536 + +static const unsigned long crc32_table[] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; + +static uint32_t crc32_byte(uint32_t accum, uint8_t delta) +{ + return crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8); +} + +static int probe_prefix(struct dfu_file *file) +{ + uint8_t *prefix = file->firmware; + + if (file->size.total < LMDFU_PREFIX_LENGTH) + return 1; + if ((prefix[0] == 0x01) && (prefix[1] == 0x00)) { + file->prefix_type = LMDFU_PREFIX; + file->size.prefix = LMDFU_PREFIX_LENGTH; + file->lmdfu_address = 1024 * ((prefix[3] << 8) | prefix[2]); + } + else if (((prefix[0] & 0x3f) == 0x1a) && ((prefix[1] & 0x3f)== 0x3f)) { + file->prefix_type = LPCDFU_UNENCRYPTED_PREFIX; + file->size.prefix = LPCDFU_PREFIX_LENGTH; + } + + if (file->size.prefix + file->size.suffix > file->size.total) + return 1; + return 0; +} + +void dfu_progress_bar(const char *desc, unsigned long long curr, + unsigned long long max) +{ + static char buf[PROGRESS_BAR_WIDTH + 1]; + static unsigned long long last_progress = -1; + static time_t last_time; + time_t curr_time = time(NULL); + unsigned long long progress; + unsigned long long x; + + /* check for not known maximum */ + if (max < curr) + max = curr + 1; + /* make none out of none give zero */ + if (max == 0 && curr == 0) + max = 1; + + /* compute completion */ + progress = (PROGRESS_BAR_WIDTH * curr) / max; + if (progress > PROGRESS_BAR_WIDTH) + progress = PROGRESS_BAR_WIDTH; + if (progress == last_progress && + curr_time == last_time) + return; + last_progress = progress; + last_time = curr_time; + + for (x = 0; x != PROGRESS_BAR_WIDTH; x++) { + if (x < progress) + buf[x] = '='; + else + buf[x] = ' '; + } + buf[x] = 0; + + printf("\r%s\t[%s] %3lld%% %12lld bytes", desc, buf, + (100ULL * curr) / max, curr); + + if (progress == PROGRESS_BAR_WIDTH) + printf("\n%s done.\n", desc); +} + +void *dfu_malloc(size_t size) +{ + void *ptr = malloc(size); + if (ptr == NULL) + errx(EX_SOFTWARE, "Cannot allocate memory of size %d bytes", (int)size); + return (ptr); +} + +uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size) +{ + int x; + + /* compute CRC */ + for (x = 0; x != size; x++) + crc = crc32_byte(crc, ((uint8_t *)buf)[x]); + + /* write data */ + if (write(f, buf, size) != size) + err(EX_IOERR, "Could not write %d bytes to file %d", size, f); + + return (crc); +} + +void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix) +{ + off_t offset; + int f; + int i; + int res; + + file->size.prefix = 0; + file->size.suffix = 0; + + /* default values, if no valid suffix is found */ + file->bcdDFU = 0; + file->idVendor = 0xffff; /* wildcard value */ + file->idProduct = 0xffff; /* wildcard value */ + file->bcdDevice = 0xffff; /* wildcard value */ + + /* default values, if no valid prefix is found */ + file->lmdfu_address = 0; + + free(file->firmware); + + if (!strcmp(file->name, "-")) { + int read_bytes; + +#ifdef WIN32 + _setmode( _fileno( stdin ), _O_BINARY ); +#endif + file->firmware = (uint8_t*) dfu_malloc(STDIN_CHUNK_SIZE); + read_bytes = fread(file->firmware, 1, STDIN_CHUNK_SIZE, stdin); + file->size.total = read_bytes; + while (read_bytes == STDIN_CHUNK_SIZE) { + file->firmware = (uint8_t*) realloc(file->firmware, file->size.total + STDIN_CHUNK_SIZE); + if (!file->firmware) + err(EX_IOERR, "Could not allocate firmware buffer"); + read_bytes = fread(file->firmware + file->size.total, 1, STDIN_CHUNK_SIZE, stdin); + file->size.total += read_bytes; + } + if (verbose) + printf("Read %i bytes from stdin\n", file->size.total); + /* Never require suffix when reading from stdin */ + check_suffix = MAYBE_SUFFIX; + } else { + f = open(file->name, O_RDONLY | O_BINARY); + if (f < 0) + err(EX_IOERR, "Could not open file %s for reading", file->name); + + offset = lseek(f, 0, SEEK_END); + + if ((int)offset < 0 || (int)offset != offset) + err(EX_IOERR, "File size is too big"); + + if (lseek(f, 0, SEEK_SET) != 0) + err(EX_IOERR, "Could not seek to beginning"); + + file->size.total = offset; + file->firmware = dfu_malloc(file->size.total); + + if (read(f, file->firmware, file->size.total) != file->size.total) { + err(EX_IOERR, "Could not read %d bytes from %s", + file->size.total, file->name); + } + close(f); + } + + /* Check for possible DFU file suffix by trying to parse one */ + { + uint32_t crc = 0xffffffff; + const uint8_t *dfusuffix; + int missing_suffix = 0; + const char *reason; + + if (file->size.total < DFU_SUFFIX_LENGTH) { + reason = "File too short for DFU suffix"; + missing_suffix = 1; + goto checked; + } + + dfusuffix = file->firmware + file->size.total - + DFU_SUFFIX_LENGTH; + + for (i = 0; i < file->size.total - 4; i++) + crc = crc32_byte(crc, file->firmware[i]); + + if (dfusuffix[10] != 'D' || + dfusuffix[9] != 'F' || + dfusuffix[8] != 'U') { + reason = "Invalid DFU suffix signature"; + missing_suffix = 1; + goto checked; + } + + file->dwCRC = (dfusuffix[15] << 24) + + (dfusuffix[14] << 16) + + (dfusuffix[13] << 8) + + dfusuffix[12]; + + if (file->dwCRC != crc) { + reason = "DFU suffix CRC does not match"; + missing_suffix = 1; + goto checked; + } + + /* At this point we believe we have a DFU suffix + so we require further checks to succeed */ + + file->bcdDFU = (dfusuffix[7] << 8) + dfusuffix[6]; + + if (verbose) + printf("DFU suffix version %x\n", file->bcdDFU); + + file->size.suffix = dfusuffix[11]; + + if (file->size.suffix < DFU_SUFFIX_LENGTH) { + errx(EX_IOERR, "Unsupported DFU suffix length %d", + file->size.suffix); + } + + if (file->size.suffix > file->size.total) { + errx(EX_IOERR, "Invalid DFU suffix length %d", + file->size.suffix); + } + + file->idVendor = (dfusuffix[5] << 8) + dfusuffix[4]; + file->idProduct = (dfusuffix[3] << 8) + dfusuffix[2]; + file->bcdDevice = (dfusuffix[1] << 8) + dfusuffix[0]; + +checked: + if (missing_suffix) { + if (check_suffix == NEEDS_SUFFIX) { + warnx("%s", reason); + errx(EX_IOERR, "Valid DFU suffix needed"); + } else if (check_suffix == MAYBE_SUFFIX) { + warnx("%s", reason); + warnx("A valid DFU suffix will be required in " + "a future dfu-util release!!!"); + } + } else { + if (check_suffix == NO_SUFFIX) { + errx(EX_SOFTWARE, "Please remove existing DFU suffix before adding a new one.\n"); + } + } + } + res = probe_prefix(file); + if ((res || file->size.prefix == 0) && check_prefix == NEEDS_PREFIX) + errx(EX_IOERR, "Valid DFU prefix needed"); + if (file->size.prefix && check_prefix == NO_PREFIX) + errx(EX_IOERR, "A prefix already exists, please delete it first"); + if (file->size.prefix && verbose) { + uint8_t *data = file->firmware; + if (file->prefix_type == LMDFU_PREFIX) + printf("Possible TI Stellaris DFU prefix with " + "the following properties\n" + "Address: 0x%08x\n" + "Payload length: %d\n", + file->lmdfu_address, + data[4] | (data[5] << 8) | + (data[6] << 16) | (data[7] << 14)); + else if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) + printf("Possible unencrypted NXP LPC DFU prefix with " + "the following properties\n" + "Payload length: %d kiByte\n", + data[2] >>1 | (data[3] << 7) ); + else + errx(EX_IOERR, "Unknown DFU prefix type"); + } +} + +void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix) +{ + uint32_t crc = 0xffffffff; + int f; + + f = open(file->name, O_WRONLY | O_BINARY | O_TRUNC | O_CREAT, 0666); + if (f < 0) + err(EX_IOERR, "Could not open file %s for writing", file->name); + + /* write prefix, if any */ + if (write_prefix) { + if (file->prefix_type == LMDFU_PREFIX) { + uint8_t lmdfu_prefix[LMDFU_PREFIX_LENGTH]; + uint32_t addr = file->lmdfu_address / 1024; + + /* lmdfu_dfu_prefix payload length excludes prefix and suffix */ + uint32_t len = file->size.total - + file->size.prefix - file->size.suffix; + + lmdfu_prefix[0] = 0x01; /* STELLARIS_DFU_PROG */ + lmdfu_prefix[1] = 0x00; /* Reserved */ + lmdfu_prefix[2] = (uint8_t)(addr & 0xff); + lmdfu_prefix[3] = (uint8_t)(addr >> 8); + lmdfu_prefix[4] = (uint8_t)(len & 0xff); + lmdfu_prefix[5] = (uint8_t)(len >> 8) & 0xff; + lmdfu_prefix[6] = (uint8_t)(len >> 16) & 0xff; + lmdfu_prefix[7] = (uint8_t)(len >> 24); + + crc = dfu_file_write_crc(f, crc, lmdfu_prefix, LMDFU_PREFIX_LENGTH); + } + if (file->prefix_type == LPCDFU_UNENCRYPTED_PREFIX) { + uint8_t lpcdfu_prefix[LPCDFU_PREFIX_LENGTH] = {0}; + int i; + + /* Payload is firmware and prefix rounded to 512 bytes */ + uint32_t len = (file->size.total - file->size.suffix + 511) /512; + + lpcdfu_prefix[0] = 0x1a; /* Unencypted*/ + lpcdfu_prefix[1] = 0x3f; /* Reserved */ + lpcdfu_prefix[2] = (uint8_t)(len & 0xff); + lpcdfu_prefix[3] = (uint8_t)((len >> 8) & 0xff); + for (i = 12; i < LPCDFU_PREFIX_LENGTH; i++) + lpcdfu_prefix[i] = 0xff; + + crc = dfu_file_write_crc(f, crc, lpcdfu_prefix, LPCDFU_PREFIX_LENGTH); + } + } + /* write firmware binary */ + crc = dfu_file_write_crc(f, crc, file->firmware + file->size.prefix, + file->size.total - file->size.prefix - file->size.suffix); + + /* write suffix, if any */ + if (write_suffix) { + uint8_t dfusuffix[DFU_SUFFIX_LENGTH]; + + dfusuffix[0] = file->bcdDevice & 0xff; + dfusuffix[1] = file->bcdDevice >> 8; + dfusuffix[2] = file->idProduct & 0xff; + dfusuffix[3] = file->idProduct >> 8; + dfusuffix[4] = file->idVendor & 0xff; + dfusuffix[5] = file->idVendor >> 8; + dfusuffix[6] = file->bcdDFU & 0xff; + dfusuffix[7] = file->bcdDFU >> 8; + dfusuffix[8] = 'U'; + dfusuffix[9] = 'F'; + dfusuffix[10] = 'D'; + dfusuffix[11] = DFU_SUFFIX_LENGTH; + + crc = dfu_file_write_crc(f, crc, dfusuffix, + DFU_SUFFIX_LENGTH - 4); + + dfusuffix[12] = crc; + dfusuffix[13] = crc >> 8; + dfusuffix[14] = crc >> 16; + dfusuffix[15] = crc >> 24; + + crc = dfu_file_write_crc(f, crc, dfusuffix + 12, 4); + } + close(f); +} + +void show_suffix_and_prefix(struct dfu_file *file) +{ + if (file->size.prefix == LMDFU_PREFIX_LENGTH) { + printf("The file %s contains a TI Stellaris DFU prefix with the following properties:\n", file->name); + printf("Address:\t0x%08x\n", file->lmdfu_address); + } else if (file->size.prefix == LPCDFU_PREFIX_LENGTH) { + uint8_t * prefix = file->firmware; + printf("The file %s contains a NXP unencrypted LPC DFU prefix with the following properties:\n", file->name); + printf("Size:\t%5d kiB\n", prefix[2]>>1|prefix[3]<<7); + } else if (file->size.prefix != 0) { + printf("The file %s contains an unknown prefix\n", file->name); + } + if (file->size.suffix > 0) { + printf("The file %s contains a DFU suffix with the following properties:\n", file->name); + printf("BCD device:\t0x%04X\n", file->bcdDevice); + printf("Product ID:\t0x%04X\n",file->idProduct); + printf("Vendor ID:\t0x%04X\n", file->idVendor); + printf("BCD DFU:\t0x%04X\n", file->bcdDFU); + printf("Length:\t\t%i\n", file->size.suffix); + printf("CRC:\t\t0x%08X\n", file->dwCRC); + } +} diff --git a/tools/src/dfu-util/src/dfu_file.h b/tools/src/dfu-util/src/dfu_file.h new file mode 100755 index 0000000..31c90b8 --- /dev/null +++ b/tools/src/dfu-util/src/dfu_file.h @@ -0,0 +1,60 @@ + +#ifndef DFU_FILE_H +#define DFU_FILE_H + +#include + +struct dfu_file { + /* File name */ + const char *name; + /* Pointer to file loaded into memory */ + uint8_t *firmware; + /* Different sizes */ + struct { + int total; + int prefix; + int suffix; + } size; + /* From prefix fields */ + uint32_t lmdfu_address; + /* From prefix fields */ + uint32_t prefix_type; + + /* From DFU suffix fields */ + uint32_t dwCRC; + uint16_t bcdDFU; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; +}; + +enum suffix_req { + NO_SUFFIX, + NEEDS_SUFFIX, + MAYBE_SUFFIX +}; + +enum prefix_req { + NO_PREFIX, + NEEDS_PREFIX, + MAYBE_PREFIX +}; + +enum prefix_type { + ZERO_PREFIX, + LMDFU_PREFIX, + LPCDFU_UNENCRYPTED_PREFIX +}; + +extern int verbose; + +void dfu_load_file(struct dfu_file *file, enum suffix_req check_suffix, enum prefix_req check_prefix); +void dfu_store_file(struct dfu_file *file, int write_suffix, int write_prefix); + +void dfu_progress_bar(const char *desc, unsigned long long curr, + unsigned long long max); +void *dfu_malloc(size_t size); +uint32_t dfu_file_write_crc(int f, uint32_t crc, const void *buf, int size); +void show_suffix_and_prefix(struct dfu_file *file); + +#endif /* DFU_FILE_H */ diff --git a/tools/src/dfu-util/src/dfu_load.c b/tools/src/dfu-util/src/dfu_load.c new file mode 100755 index 0000000..d4ff51c --- /dev/null +++ b/tools/src/dfu-util/src/dfu_load.c @@ -0,0 +1,196 @@ +/* + * DFU transfer routines + * + * This is supposed to be a general DFU implementation, as specified in the + * USB DFU 1.0 and 1.1 specification. + * + * The code was originally intended to interface with a USB device running the + * "sam7dfu" firmware (see http://www.openpcd.org/) on an AT91SAM7 processor. + * + * Copyright 2007-2008 Harald Welte + * Copyright 2013 Hans Petter Selasky + * Copyright 2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include + +#include "portable.h" +#include "dfu.h" +#include "usb_dfu.h" +#include "dfu_file.h" +#include "dfu_load.h" +#include "quirks.h" + +int dfuload_do_upload(struct dfu_if *dif, int xfer_size, + int expected_size, int fd) +{ + int total_bytes = 0; + unsigned short transaction = 0; + unsigned char *buf; + int ret; + + buf = dfu_malloc(xfer_size); + + printf("Copying data from DFU device to PC\n"); + dfu_progress_bar("Upload", 0, 1); + + while (1) { + int rc; + rc = dfu_upload(dif->dev_handle, dif->interface, + xfer_size, transaction++, buf); + if (rc < 0) { + warnx("Error during upload"); + ret = rc; + goto out_free; + } + + dfu_file_write_crc(fd, 0, buf, rc); + total_bytes += rc; + + if (total_bytes < 0) + errx(EX_SOFTWARE, "Received too many bytes (wraparound)"); + + if (rc < xfer_size) { + /* last block, return */ + ret = total_bytes; + break; + } + dfu_progress_bar("Upload", total_bytes, expected_size); + } + ret = 0; + +out_free: + dfu_progress_bar("Upload", total_bytes, total_bytes); + if (total_bytes == 0) + printf("\nFailed.\n"); + free(buf); + if (verbose) + printf("Received a total of %i bytes\n", total_bytes); + if (expected_size != 0 && total_bytes != expected_size) + errx(EX_SOFTWARE, "Unexpected number of bytes uploaded from device"); + return ret; +} + +int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file) +{ + int bytes_sent; + int expected_size; + unsigned char *buf; + unsigned short transaction = 0; + struct dfu_status dst; + int ret; + + printf("Copying data from PC to DFU device\n"); + + buf = file->firmware; + expected_size = file->size.total - file->size.suffix; + bytes_sent = 0; + + dfu_progress_bar("Download", 0, 1); + while (bytes_sent < expected_size) { + int bytes_left; + int chunk_size; + + bytes_left = expected_size - bytes_sent; + if (bytes_left < xfer_size) + chunk_size = bytes_left; + else + chunk_size = xfer_size; + + ret = dfu_download(dif->dev_handle, dif->interface, + chunk_size, transaction++, chunk_size ? buf : NULL); + if (ret < 0) { + warnx("Error during download"); + goto out; + } + bytes_sent += chunk_size; + buf += chunk_size; + + do { + ret = dfu_get_status(dif, &dst); + if (ret < 0) { + errx(EX_IOERR, "Error during download get_status"); + goto out; + } + + if (dst.bState == DFU_STATE_dfuDNLOAD_IDLE || + dst.bState == DFU_STATE_dfuERROR) + break; + + /* Wait while device executes flashing */ + milli_sleep(dst.bwPollTimeout); + + } while (1); + if (dst.bStatus != DFU_STATUS_OK) { + printf(" failed!\n"); + printf("state(%u) = %s, status(%u) = %s\n", dst.bState, + dfu_state_to_string(dst.bState), dst.bStatus, + dfu_status_to_string(dst.bStatus)); + ret = -1; + goto out; + } + dfu_progress_bar("Download", bytes_sent, bytes_sent + bytes_left); + } + + /* send one zero sized download request to signalize end */ + ret = dfu_download(dif->dev_handle, dif->interface, + 0, transaction, NULL); + if (ret < 0) { + errx(EX_IOERR, "Error sending completion packet"); + goto out; + } + + dfu_progress_bar("Download", bytes_sent, bytes_sent); + + if (verbose) + printf("Sent a total of %i bytes\n", bytes_sent); + +get_status: + /* Transition to MANIFEST_SYNC state */ + ret = dfu_get_status(dif, &dst); + if (ret < 0) { + warnx("unable to read DFU status after completion"); + goto out; + } + printf("state(%u) = %s, status(%u) = %s\n", dst.bState, + dfu_state_to_string(dst.bState), dst.bStatus, + dfu_status_to_string(dst.bStatus)); + + milli_sleep(dst.bwPollTimeout); + + /* FIXME: deal correctly with ManifestationTolerant=0 / WillDetach bits */ + switch (dst.bState) { + case DFU_STATE_dfuMANIFEST_SYNC: + case DFU_STATE_dfuMANIFEST: + /* some devices (e.g. TAS1020b) need some time before we + * can obtain the status */ + milli_sleep(1000); + goto get_status; + break; + case DFU_STATE_dfuIDLE: + break; + } + printf("Done!\n"); + +out: + return bytes_sent; +} diff --git a/tools/src/dfu-util/src/dfu_load.h b/tools/src/dfu-util/src/dfu_load.h new file mode 100755 index 0000000..fe363aa --- /dev/null +++ b/tools/src/dfu-util/src/dfu_load.h @@ -0,0 +1,7 @@ +#ifndef DFU_LOAD_H +#define DFU_LOAD_H + +int dfuload_do_upload(struct dfu_if *dif, int xfer_size, int expected_size, int fd); +int dfuload_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file); + +#endif /* DFU_LOAD_H */ diff --git a/tools/src/dfu-util/src/dfu_util.c b/tools/src/dfu-util/src/dfu_util.c new file mode 100755 index 0000000..d9ad2d0 --- /dev/null +++ b/tools/src/dfu-util/src/dfu_util.c @@ -0,0 +1,346 @@ +/* + * Functions for detecting DFU USB entities + * + * Written by Harald Welte + * Copyright 2007-2008 by OpenMoko, Inc. + * Copyright 2013 Hans Petter Selasky + * + * Based on existing code of dfu-programmer-0.4 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "portable.h" +#include "dfu.h" +#include "usb_dfu.h" +#include "dfu_file.h" +#include "dfu_load.h" +#include "dfu_util.h" +#include "dfuse.h" +#include "quirks.h" + +#ifdef HAVE_USBPATH_H +#include +#endif + +/* + * Look for a descriptor in a concatenated descriptor list. Will + * return upon the first match of the given descriptor type. Returns length of + * found descriptor, limited to res_size + */ +static int find_descriptor(const uint8_t *desc_list, int list_len, + uint8_t desc_type, void *res_buf, int res_size) +{ + int p = 0; + + if (list_len < 2) + return (-1); + + while (p + 1 < list_len) { + int desclen; + + desclen = (int) desc_list[p]; + if (desclen == 0) { + warnx("Invalid descriptor list"); + return -1; + } + if (desc_list[p + 1] == desc_type) { + if (desclen > res_size) + desclen = res_size; + if (p + desclen > list_len) + desclen = list_len - p; + memcpy(res_buf, &desc_list[p], desclen); + return desclen; + } + p += (int) desc_list[p]; + } + return -1; +} + +static void probe_configuration(libusb_device *dev, struct libusb_device_descriptor *desc) +{ + struct usb_dfu_func_descriptor func_dfu; + libusb_device_handle *devh; + struct dfu_if *pdfu; + struct libusb_config_descriptor *cfg; + const struct libusb_interface_descriptor *intf; + const struct libusb_interface *uif; + char alt_name[MAX_DESC_STR_LEN + 1]; + char serial_name[MAX_DESC_STR_LEN + 1]; + int cfg_idx; + int intf_idx; + int alt_idx; + int ret; + int has_dfu; + + for (cfg_idx = 0; cfg_idx != desc->bNumConfigurations; cfg_idx++) { + memset(&func_dfu, 0, sizeof(func_dfu)); + has_dfu = 0; + + ret = libusb_get_config_descriptor(dev, cfg_idx, &cfg); + if (ret != 0) + return; + if (match_config_index > -1 && match_config_index != cfg->bConfigurationValue) { + libusb_free_config_descriptor(cfg); + continue; + } + + /* + * In some cases, noticably FreeBSD if uid != 0, + * the configuration descriptors are empty + */ + if (!cfg) + return; + + ret = find_descriptor(cfg->extra, cfg->extra_length, + USB_DT_DFU, &func_dfu, sizeof(func_dfu)); + if (ret > -1) + goto found_dfu; + + for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; + intf_idx++) { + uif = &cfg->interface[intf_idx]; + if (!uif) + break; + + for (alt_idx = 0; alt_idx < cfg->interface[intf_idx].num_altsetting; + alt_idx++) { + intf = &uif->altsetting[alt_idx]; + + ret = find_descriptor(intf->extra, intf->extra_length, USB_DT_DFU, + &func_dfu, sizeof(func_dfu)); + if (ret > -1) + goto found_dfu; + + if (intf->bInterfaceClass != 0xfe || + intf->bInterfaceSubClass != 1) + continue; + + has_dfu = 1; + } + } + if (has_dfu) { + /* + * Finally try to retrieve it requesting the + * device directly This is not supported on + * all devices for non-standard types + */ + if (libusb_open(dev, &devh) == 0) { + ret = libusb_get_descriptor(devh, USB_DT_DFU, 0, + (void *)&func_dfu, sizeof(func_dfu)); + libusb_close(devh); + if (ret > -1) + goto found_dfu; + } + warnx("Device has DFU interface, " + "but has no DFU functional descriptor"); + + /* fake version 1.0 */ + func_dfu.bLength = 7; + func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); + goto found_dfu; + } + libusb_free_config_descriptor(cfg); + continue; + +found_dfu: + if (func_dfu.bLength == 7) { + printf("Deducing device DFU version from functional descriptor " + "length\n"); + func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); + } else if (func_dfu.bLength < 9) { + printf("Error obtaining DFU functional descriptor\n"); + printf("Please report this as a bug!\n"); + printf("Warning: Assuming DFU version 1.0\n"); + func_dfu.bcdDFUVersion = libusb_cpu_to_le16(0x0100); + printf("Warning: Transfer size can not be detected\n"); + func_dfu.wTransferSize = 0; + } + + for (intf_idx = 0; intf_idx < cfg->bNumInterfaces; + intf_idx++) { + if (match_iface_index > -1 && match_iface_index != intf_idx) + continue; + + uif = &cfg->interface[intf_idx]; + if (!uif) + break; + + for (alt_idx = 0; + alt_idx < uif->num_altsetting; alt_idx++) { + int dfu_mode; + + intf = &uif->altsetting[alt_idx]; + + if (intf->bInterfaceClass != 0xfe || + intf->bInterfaceSubClass != 1) + continue; + + dfu_mode = (intf->bInterfaceProtocol == 2); + /* e.g. DSO Nano has bInterfaceProtocol 0 instead of 2 */ + if (func_dfu.bcdDFUVersion == 0x011a && intf->bInterfaceProtocol == 0) + dfu_mode = 1; + + if (dfu_mode && + match_iface_alt_index > -1 && match_iface_alt_index != alt_idx) + continue; + + if (dfu_mode) { + if ((match_vendor_dfu >= 0 && match_vendor_dfu != desc->idVendor) || + (match_product_dfu >= 0 && match_product_dfu != desc->idProduct)) { + continue; + } + } else { + if ((match_vendor >= 0 && match_vendor != desc->idVendor) || + (match_product >= 0 && match_product != desc->idProduct)) { + continue; + } + } + + if (libusb_open(dev, &devh)) { + warnx("Cannot open DFU device %04x:%04x", desc->idVendor, desc->idProduct); + break; + } + if (intf->iInterface != 0) + ret = libusb_get_string_descriptor_ascii(devh, + intf->iInterface, (void *)alt_name, MAX_DESC_STR_LEN); + else + ret = -1; + if (ret < 1) + strcpy(alt_name, "UNKNOWN"); + if (desc->iSerialNumber != 0) + ret = libusb_get_string_descriptor_ascii(devh, + desc->iSerialNumber, (void *)serial_name, MAX_DESC_STR_LEN); + else + ret = -1; + if (ret < 1) + strcpy(serial_name, "UNKNOWN"); + libusb_close(devh); + + if (dfu_mode && + match_iface_alt_name != NULL && strcmp(alt_name, match_iface_alt_name)) + continue; + + if (dfu_mode) { + if (match_serial_dfu != NULL && strcmp(match_serial_dfu, serial_name)) + continue; + } else { + if (match_serial != NULL && strcmp(match_serial, serial_name)) + continue; + } + + pdfu = dfu_malloc(sizeof(*pdfu)); + + memset(pdfu, 0, sizeof(*pdfu)); + + pdfu->func_dfu = func_dfu; + pdfu->dev = libusb_ref_device(dev); + pdfu->quirks = get_quirks(desc->idVendor, + desc->idProduct, desc->bcdDevice); + pdfu->vendor = desc->idVendor; + pdfu->product = desc->idProduct; + pdfu->bcdDevice = desc->bcdDevice; + pdfu->configuration = cfg->bConfigurationValue; + pdfu->interface = intf->bInterfaceNumber; + pdfu->altsetting = intf->bAlternateSetting; + pdfu->devnum = libusb_get_device_address(dev); + pdfu->busnum = libusb_get_bus_number(dev); + pdfu->alt_name = strdup(alt_name); + if (pdfu->alt_name == NULL) + errx(EX_SOFTWARE, "Out of memory"); + pdfu->serial_name = strdup(serial_name); + if (pdfu->serial_name == NULL) + errx(EX_SOFTWARE, "Out of memory"); + if (dfu_mode) + pdfu->flags |= DFU_IFF_DFU; + if (pdfu->quirks & QUIRK_FORCE_DFU11) { + pdfu->func_dfu.bcdDFUVersion = + libusb_cpu_to_le16(0x0110); + } + pdfu->bMaxPacketSize0 = desc->bMaxPacketSize0; + + /* queue into list */ + pdfu->next = dfu_root; + dfu_root = pdfu; + } + } + libusb_free_config_descriptor(cfg); + } +} + +void probe_devices(libusb_context *ctx) +{ + libusb_device **list; + ssize_t num_devs; + ssize_t i; + + num_devs = libusb_get_device_list(ctx, &list); + for (i = 0; i < num_devs; ++i) { + struct libusb_device_descriptor desc; + struct libusb_device *dev = list[i]; + + if (match_bus > -1 && match_bus != libusb_get_bus_number(dev)) + continue; + if (match_device > -1 && match_device != libusb_get_device_address(dev)) + continue; + if (libusb_get_device_descriptor(dev, &desc)) + continue; + probe_configuration(dev, &desc); + } + libusb_free_device_list(list, 0); +} + +void disconnect_devices(void) +{ + struct dfu_if *pdfu; + struct dfu_if *prev = NULL; + + for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) { + free(prev); + libusb_unref_device(pdfu->dev); + free(pdfu->alt_name); + free(pdfu->serial_name); + prev = pdfu; + } + free(prev); + dfu_root = NULL; +} + +void print_dfu_if(struct dfu_if *dfu_if) +{ + printf("Found %s: [%04x:%04x] ver=%04x, devnum=%u, cfg=%u, intf=%u, " + "alt=%u, name=\"%s\", serial=\"%s\"\n", + dfu_if->flags & DFU_IFF_DFU ? "DFU" : "Runtime", + dfu_if->vendor, dfu_if->product, + dfu_if->bcdDevice, dfu_if->devnum, + dfu_if->configuration, dfu_if->interface, + dfu_if->altsetting, dfu_if->alt_name, + dfu_if->serial_name); +} + +/* Walk the device tree and print out DFU devices */ +void list_dfu_interfaces(void) +{ + struct dfu_if *pdfu; + + for (pdfu = dfu_root; pdfu != NULL; pdfu = pdfu->next) + print_dfu_if(pdfu); +} diff --git a/tools/src/dfu-util/src/dfu_util.h b/tools/src/dfu-util/src/dfu_util.h new file mode 100755 index 0000000..24e50c1 --- /dev/null +++ b/tools/src/dfu-util/src/dfu_util.h @@ -0,0 +1,36 @@ +#ifndef DFU_UTIL_H +#define DFU_UTIL_H + +/* USB string descriptor should contain max 126 UTF-16 characters + * but 253 would even accomodate any UTF-8 encoding */ +#define MAX_DESC_STR_LEN 253 + +enum mode { + MODE_NONE, + MODE_VERSION, + MODE_LIST, + MODE_DETACH, + MODE_UPLOAD, + MODE_DOWNLOAD +}; + +extern struct dfu_if *dfu_root; +extern int match_bus; +extern int match_device; +extern int match_vendor; +extern int match_product; +extern int match_vendor_dfu; +extern int match_product_dfu; +extern int match_config_index; +extern int match_iface_index; +extern int match_iface_alt_index; +extern const char *match_iface_alt_name; +extern const char *match_serial; +extern const char *match_serial_dfu; + +void probe_devices(libusb_context *); +void disconnect_devices(void); +void print_dfu_if(struct dfu_if *); +void list_dfu_interfaces(void); + +#endif /* DFU_UTIL_H */ diff --git a/tools/src/dfu-util/src/dfuse.c b/tools/src/dfu-util/src/dfuse.c new file mode 100755 index 0000000..39bc72d --- /dev/null +++ b/tools/src/dfu-util/src/dfuse.c @@ -0,0 +1,652 @@ +/* + * DfuSe specific functions + * + * This implements the ST Microsystems DFU extensions (DfuSe) + * as per the DfuSe 1.1a specification (ST documents AN3156, AN2606) + * The DfuSe file format is described in ST document UM0391. + * + * Copyright 2010-2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "portable.h" +#include "dfu.h" +#include "usb_dfu.h" +#include "dfu_file.h" +#include "dfuse.h" +#include "dfuse_mem.h" + +#define DFU_TIMEOUT 5000 + +extern int verbose; +static unsigned int last_erased_page = 1; /* non-aligned value, won't match */ +static struct memsegment *mem_layout; +static unsigned int dfuse_address = 0; +static unsigned int dfuse_length = 0; +static int dfuse_force = 0; +static int dfuse_leave = 0; +static int dfuse_unprotect = 0; +static int dfuse_mass_erase = 0; + +unsigned int quad2uint(unsigned char *p) +{ + return (*p + (*(p + 1) << 8) + (*(p + 2) << 16) + (*(p + 3) << 24)); +} + +void dfuse_parse_options(const char *options) +{ + char *end; + const char *endword; + unsigned int number; + + /* address, possibly empty, must be first */ + if (*options != ':') { + endword = strchr(options, ':'); + if (!endword) + endword = options + strlen(options); /* GNU strchrnul */ + + number = strtoul(options, &end, 0); + if (end == endword) { + dfuse_address = number; + } else { + errx(EX_IOERR, "Invalid dfuse address: %s", options); + } + options = endword; + } + + while (*options) { + if (*options == ':') { + options++; + continue; + } + endword = strchr(options, ':'); + if (!endword) + endword = options + strlen(options); + + if (!strncmp(options, "force", endword - options)) { + dfuse_force++; + options += 5; + continue; + } + if (!strncmp(options, "leave", endword - options)) { + dfuse_leave = 1; + options += 5; + continue; + } + if (!strncmp(options, "unprotect", endword - options)) { + dfuse_unprotect = 1; + options += 9; + continue; + } + if (!strncmp(options, "mass-erase", endword - options)) { + dfuse_mass_erase = 1; + options += 10; + continue; + } + + /* any valid number is interpreted as upload length */ + number = strtoul(options, &end, 0); + if (end == endword) { + dfuse_length = number; + } else { + errx(EX_IOERR, "Invalid dfuse modifier: %s", options); + } + options = endword; + } +} + +/* DFU_UPLOAD request for DfuSe 1.1a */ +int dfuse_upload(struct dfu_if *dif, const unsigned short length, + unsigned char *data, unsigned short transaction) +{ + int status; + + status = libusb_control_transfer(dif->dev_handle, + /* bmRequestType */ LIBUSB_ENDPOINT_IN | + LIBUSB_REQUEST_TYPE_CLASS | + LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_UPLOAD, + /* wValue */ transaction, + /* wIndex */ dif->interface, + /* Data */ data, + /* wLength */ length, + DFU_TIMEOUT); + if (status < 0) { + errx(EX_IOERR, "%s: libusb_control_msg returned %d", + __FUNCTION__, status); + } + return status; +} + +/* DFU_DNLOAD request for DfuSe 1.1a */ +int dfuse_download(struct dfu_if *dif, const unsigned short length, + unsigned char *data, unsigned short transaction) +{ + int status; + + status = libusb_control_transfer(dif->dev_handle, + /* bmRequestType */ LIBUSB_ENDPOINT_OUT | + LIBUSB_REQUEST_TYPE_CLASS | + LIBUSB_RECIPIENT_INTERFACE, + /* bRequest */ DFU_DNLOAD, + /* wValue */ transaction, + /* wIndex */ dif->interface, + /* Data */ data, + /* wLength */ length, + DFU_TIMEOUT); + if (status < 0) { + errx(EX_IOERR, "%s: libusb_control_transfer returned %d", + __FUNCTION__, status); + } + return status; +} + +/* DfuSe only commands */ +/* Leaves the device in dfuDNLOAD-IDLE state */ +int dfuse_special_command(struct dfu_if *dif, unsigned int address, + enum dfuse_command command) +{ + const char* dfuse_command_name[] = { "SET_ADDRESS" , "ERASE_PAGE", + "MASS_ERASE", "READ_UNPROTECT"}; + unsigned char buf[5]; + int length; + int ret; + struct dfu_status dst; + int firstpoll = 1; + + if (command == ERASE_PAGE) { + struct memsegment *segment; + int page_size; + + segment = find_segment(mem_layout, address); + if (!segment || !(segment->memtype & DFUSE_ERASABLE)) { + errx(EX_IOERR, "Page at 0x%08x can not be erased", + address); + } + page_size = segment->pagesize; + if (verbose > 1) + printf("Erasing page size %i at address 0x%08x, page " + "starting at 0x%08x\n", page_size, address, + address & ~(page_size - 1)); + buf[0] = 0x41; /* Erase command */ + length = 5; + last_erased_page = address & ~(page_size - 1); + } else if (command == SET_ADDRESS) { + if (verbose > 2) + printf(" Setting address pointer to 0x%08x\n", + address); + buf[0] = 0x21; /* Set Address Pointer command */ + length = 5; + } else if (command == MASS_ERASE) { + buf[0] = 0x41; /* Mass erase command when length = 1 */ + length = 1; + } else if (command == READ_UNPROTECT) { + buf[0] = 0x92; + length = 1; + } else { + errx(EX_IOERR, "Non-supported special command %d", command); + } + buf[1] = address & 0xff; + buf[2] = (address >> 8) & 0xff; + buf[3] = (address >> 16) & 0xff; + buf[4] = (address >> 24) & 0xff; + + ret = dfuse_download(dif, length, buf, 0); + if (ret < 0) { + errx(EX_IOERR, "Error during special command \"%s\" download", + dfuse_command_name[command]); + } + do { + ret = dfu_get_status(dif, &dst); + if (ret < 0) { + errx(EX_IOERR, "Error during special command \"%s\" get_status", + dfuse_command_name[command]); + } + if (firstpoll) { + firstpoll = 0; + if (dst.bState != DFU_STATE_dfuDNBUSY) { + printf("state(%u) = %s, status(%u) = %s\n", dst.bState, + dfu_state_to_string(dst.bState), dst.bStatus, + dfu_status_to_string(dst.bStatus)); + errx(EX_IOERR, "Wrong state after command \"%s\" download", + dfuse_command_name[command]); + } + } + /* wait while command is executed */ + if (verbose) + printf(" Poll timeout %i ms\n", dst.bwPollTimeout); + milli_sleep(dst.bwPollTimeout); + if (command == READ_UNPROTECT) + return ret; + } while (dst.bState == DFU_STATE_dfuDNBUSY); + + if (dst.bStatus != DFU_STATUS_OK) { + errx(EX_IOERR, "%s not correctly executed", + dfuse_command_name[command]); + } + return ret; +} + +int dfuse_dnload_chunk(struct dfu_if *dif, unsigned char *data, int size, + int transaction) +{ + int bytes_sent; + struct dfu_status dst; + int ret; + + ret = dfuse_download(dif, size, size ? data : NULL, transaction); + if (ret < 0) { + errx(EX_IOERR, "Error during download"); + return ret; + } + bytes_sent = ret; + + do { + ret = dfu_get_status(dif, &dst); + if (ret < 0) { + errx(EX_IOERR, "Error during download get_status"); + return ret; + } + milli_sleep(dst.bwPollTimeout); + } while (dst.bState != DFU_STATE_dfuDNLOAD_IDLE && + dst.bState != DFU_STATE_dfuERROR && + dst.bState != DFU_STATE_dfuMANIFEST); + + if (dst.bState == DFU_STATE_dfuMANIFEST) + printf("Transitioning to dfuMANIFEST state\n"); + + if (dst.bStatus != DFU_STATUS_OK) { + printf(" failed!\n"); + printf("state(%u) = %s, status(%u) = %s\n", dst.bState, + dfu_state_to_string(dst.bState), dst.bStatus, + dfu_status_to_string(dst.bStatus)); + return -1; + } + return bytes_sent; +} + +int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, + const char *dfuse_options) +{ + int total_bytes = 0; + int upload_limit = 0; + unsigned char *buf; + int transaction; + int ret; + + buf = dfu_malloc(xfer_size); + + if (dfuse_options) + dfuse_parse_options(dfuse_options); + if (dfuse_length) + upload_limit = dfuse_length; + if (dfuse_address) { + struct memsegment *segment; + + mem_layout = parse_memory_layout((char *)dif->alt_name); + if (!mem_layout) + errx(EX_IOERR, "Failed to parse memory layout"); + + segment = find_segment(mem_layout, dfuse_address); + if (!dfuse_force && + (!segment || !(segment->memtype & DFUSE_READABLE))) + errx(EX_IOERR, "Page at 0x%08x is not readable", + dfuse_address); + + if (!upload_limit) { + upload_limit = segment->end - dfuse_address + 1; + printf("Limiting upload to end of memory segment, " + "%i bytes\n", upload_limit); + } + dfuse_special_command(dif, dfuse_address, SET_ADDRESS); + dfu_abort_to_idle(dif); + } else { + /* Boot loader decides the start address, unknown to us */ + /* Use a short length to lower risk of running out of bounds */ + if (!upload_limit) + upload_limit = 0x4000; + printf("Limiting default upload to %i bytes\n", upload_limit); + } + + dfu_progress_bar("Upload", 0, 1); + + transaction = 2; + while (1) { + int rc; + + /* last chunk can be smaller than original xfer_size */ + if (upload_limit - total_bytes < xfer_size) + xfer_size = upload_limit - total_bytes; + rc = dfuse_upload(dif, xfer_size, buf, transaction++); + if (rc < 0) { + ret = rc; + goto out_free; + } + + dfu_file_write_crc(fd, 0, buf, rc); + total_bytes += rc; + + if (total_bytes < 0) + errx(EX_SOFTWARE, "Received too many bytes"); + + if (rc < xfer_size || total_bytes >= upload_limit) { + /* last block, return successfully */ + ret = total_bytes; + break; + } + dfu_progress_bar("Upload", total_bytes, upload_limit); + } + + dfu_progress_bar("Upload", total_bytes, total_bytes); + + dfu_abort_to_idle(dif); + if (dfuse_leave) { + dfuse_special_command(dif, dfuse_address, SET_ADDRESS); + dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ + } + + out_free: + free(buf); + + return ret; +} + +/* Writes an element of any size to the device, taking care of page erases */ +/* returns 0 on success, otherwise -EINVAL */ +int dfuse_dnload_element(struct dfu_if *dif, unsigned int dwElementAddress, + unsigned int dwElementSize, unsigned char *data, + int xfer_size) +{ + int p; + int ret; + struct memsegment *segment; + + /* Check at least that we can write to the last address */ + segment = + find_segment(mem_layout, dwElementAddress + dwElementSize - 1); + if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { + errx(EX_IOERR, "Last page at 0x%08x is not writeable", + dwElementAddress + dwElementSize - 1); + } + + dfu_progress_bar("Download", 0, 1); + + for (p = 0; p < (int)dwElementSize; p += xfer_size) { + int page_size; + unsigned int erase_address; + unsigned int address = dwElementAddress + p; + int chunk_size = xfer_size; + + segment = find_segment(mem_layout, address); + if (!segment || !(segment->memtype & DFUSE_WRITEABLE)) { + errx(EX_IOERR, "Page at 0x%08x is not writeable", + address); + } + page_size = segment->pagesize; + + /* check if this is the last chunk */ + if (p + chunk_size > (int)dwElementSize) + chunk_size = dwElementSize - p; + + /* Erase only for flash memory downloads */ + if ((segment->memtype & DFUSE_ERASABLE) && !dfuse_mass_erase) { + /* erase all involved pages */ + for (erase_address = address; + erase_address < address + chunk_size; + erase_address += page_size) + if ((erase_address & ~(page_size - 1)) != + last_erased_page) + dfuse_special_command(dif, + erase_address, + ERASE_PAGE); + + if (((address + chunk_size - 1) & ~(page_size - 1)) != + last_erased_page) { + if (verbose > 2) + printf(" Chunk extends into next page," + " erase it as well\n"); + dfuse_special_command(dif, + address + chunk_size - 1, + ERASE_PAGE); + } + } + + if (verbose) { + printf(" Download from image offset " + "%08x to memory %08x-%08x, size %i\n", + p, address, address + chunk_size - 1, + chunk_size); + } else { + dfu_progress_bar("Download", p, dwElementSize); + } + + dfuse_special_command(dif, address, SET_ADDRESS); + + /* transaction = 2 for no address offset */ + ret = dfuse_dnload_chunk(dif, data + p, chunk_size, 2); + if (ret != chunk_size) { + errx(EX_IOERR, "Failed to write whole chunk: " + "%i of %i bytes", ret, chunk_size); + return -EINVAL; + } + } + if (!verbose) + dfu_progress_bar("Download", dwElementSize, dwElementSize); + return 0; +} + +static void +dfuse_memcpy(unsigned char *dst, unsigned char **src, int *rem, int size) +{ + if (size > *rem) { + errx(EX_IOERR, "Corrupt DfuSe file: " + "Cannot read %d bytes from %d bytes", size, *rem); + } + if (dst != NULL) + memcpy(dst, *src, size); + (*src) += size; + (*rem) -= size; +} + +/* Download raw binary file to DfuSe device */ +int dfuse_do_bin_dnload(struct dfu_if *dif, int xfer_size, + struct dfu_file *file, unsigned int start_address) +{ + unsigned int dwElementAddress; + unsigned int dwElementSize; + unsigned char *data; + int ret; + + dwElementAddress = start_address; + dwElementSize = file->size.total - + file->size.suffix - file->size.prefix; + + printf("Downloading to address = 0x%08x, size = %i\n", + dwElementAddress, dwElementSize); + + data = file->firmware + file->size.prefix; + + ret = dfuse_dnload_element(dif, dwElementAddress, dwElementSize, data, + xfer_size); + if (ret != 0) + goto out_free; + + printf("File downloaded successfully\n"); + ret = dwElementSize; + + out_free: + return ret; +} + +/* Parse a DfuSe file and download contents to device */ +int dfuse_do_dfuse_dnload(struct dfu_if *dif, int xfer_size, + struct dfu_file *file) +{ + uint8_t dfuprefix[11]; + uint8_t targetprefix[274]; + uint8_t elementheader[8]; + int image; + int element; + int bTargets; + int bAlternateSetting; + int dwNbElements; + unsigned int dwElementAddress; + unsigned int dwElementSize; + uint8_t *data; + int ret; + int rem; + int bFirstAddressSaved = 0; + + rem = file->size.total - file->size.prefix - file->size.suffix; + data = file->firmware + file->size.prefix; + + /* Must be larger than a minimal DfuSe header and suffix */ + if (rem < (int)(sizeof(dfuprefix) + + sizeof(targetprefix) + sizeof(elementheader))) { + errx(EX_SOFTWARE, "File too small for a DfuSe file"); + } + + dfuse_memcpy(dfuprefix, &data, &rem, sizeof(dfuprefix)); + + if (strncmp((char *)dfuprefix, "DfuSe", 5)) { + errx(EX_IOERR, "No valid DfuSe signature"); + return -EINVAL; + } + if (dfuprefix[5] != 0x01) { + errx(EX_IOERR, "DFU format revision %i not supported", + dfuprefix[5]); + return -EINVAL; + } + bTargets = dfuprefix[10]; + printf("file contains %i DFU images\n", bTargets); + + for (image = 1; image <= bTargets; image++) { + printf("parsing DFU image %i\n", image); + dfuse_memcpy(targetprefix, &data, &rem, sizeof(targetprefix)); + if (strncmp((char *)targetprefix, "Target", 6)) { + errx(EX_IOERR, "No valid target signature"); + return -EINVAL; + } + bAlternateSetting = targetprefix[6]; + dwNbElements = quad2uint((unsigned char *)targetprefix + 270); + printf("image for alternate setting %i, ", bAlternateSetting); + printf("(%i elements, ", dwNbElements); + printf("total size = %i)\n", + quad2uint((unsigned char *)targetprefix + 266)); + if (bAlternateSetting != dif->altsetting) + printf("Warning: Image does not match current alternate" + " setting.\n" + "Please rerun with the correct -a option setting" + " to download this image!\n"); + for (element = 1; element <= dwNbElements; element++) { + printf("parsing element %i, ", element); + dfuse_memcpy(elementheader, &data, &rem, sizeof(elementheader)); + dwElementAddress = + quad2uint((unsigned char *)elementheader); + dwElementSize = + quad2uint((unsigned char *)elementheader + 4); + printf("address = 0x%08x, ", dwElementAddress); + printf("size = %i\n", dwElementSize); + + if (!bFirstAddressSaved) { + bFirstAddressSaved = 1; + dfuse_address = dwElementAddress; + } + /* sanity check */ + if ((int)dwElementSize > rem) + errx(EX_SOFTWARE, "File too small for element size"); + + if (bAlternateSetting == dif->altsetting) { + ret = dfuse_dnload_element(dif, dwElementAddress, + dwElementSize, data, xfer_size); + } else { + ret = 0; + } + + /* advance read pointer */ + dfuse_memcpy(NULL, &data, &rem, dwElementSize); + + if (ret != 0) + return ret; + } + } + + if (rem != 0) + warnx("%d bytes leftover", rem); + + printf("done parsing DfuSe file\n"); + + return 0; +} + +int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, + const char *dfuse_options) +{ + int ret; + + if (dfuse_options) + dfuse_parse_options(dfuse_options); + mem_layout = parse_memory_layout((char *)dif->alt_name); + if (!mem_layout) { + errx(EX_IOERR, "Failed to parse memory layout"); + } + if (dfuse_unprotect) { + if (!dfuse_force) { + errx(EX_IOERR, "The read unprotect command " + "will erase the flash memory" + "and can only be used with force\n"); + } + dfuse_special_command(dif, 0, READ_UNPROTECT); + printf("Device disconnects, erases flash and resets now\n"); + exit(0); + } + if (dfuse_mass_erase) { + if (!dfuse_force) { + errx(EX_IOERR, "The mass erase command " + "can only be used with force"); + } + printf("Performing mass erase, this can take a moment\n"); + dfuse_special_command(dif, 0, MASS_ERASE); + } + if (dfuse_address) { + if (file->bcdDFU == 0x11a) { + errx(EX_IOERR, "This is a DfuSe file, not " + "meant for raw download"); + } + ret = dfuse_do_bin_dnload(dif, xfer_size, file, dfuse_address); + } else { + if (file->bcdDFU != 0x11a) { + warnx("Only DfuSe file version 1.1a is supported"); + errx(EX_IOERR, "(for raw binary download, use the " + "--dfuse-address option)"); + } + ret = dfuse_do_dfuse_dnload(dif, xfer_size, file); + } + free_segment_list(mem_layout); + + dfu_abort_to_idle(dif); + + if (dfuse_leave) { + dfuse_special_command(dif, dfuse_address, SET_ADDRESS); + dfuse_dnload_chunk(dif, NULL, 0, 2); /* Zero-size */ + } + return ret; +} diff --git a/tools/src/dfu-util/src/dfuse.h b/tools/src/dfu-util/src/dfuse.h new file mode 100755 index 0000000..e82f058 --- /dev/null +++ b/tools/src/dfu-util/src/dfuse.h @@ -0,0 +1,35 @@ +/* This implements the ST Microsystems DFU extensions (DfuSe) + * as per the DfuSe 1.1a specification (Document UM0391) + * + * (C) 2010-2012 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DFUSE_H +#define DFUSE_H + +#include "dfu.h" + +enum dfuse_command { SET_ADDRESS, ERASE_PAGE, MASS_ERASE, READ_UNPROTECT }; + +int dfuse_special_command(struct dfu_if *dif, unsigned int address, + enum dfuse_command command); +int dfuse_do_upload(struct dfu_if *dif, int xfer_size, int fd, + const char *dfuse_options); +int dfuse_do_dnload(struct dfu_if *dif, int xfer_size, struct dfu_file *file, + const char *dfuse_options); + +#endif /* DFUSE_H */ diff --git a/tools/src/dfu-util/src/dfuse_mem.c b/tools/src/dfu-util/src/dfuse_mem.c new file mode 100755 index 0000000..ae339fb --- /dev/null +++ b/tools/src/dfu-util/src/dfuse_mem.c @@ -0,0 +1,198 @@ +/* + * Helper functions for reading the memory map of a device + * following the ST DfuSe 1.1a specification. + * + * Copyright 2011-2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "portable.h" +#include "dfu_file.h" +#include "dfuse_mem.h" + +int add_segment(struct memsegment **segment_list, struct memsegment segment) +{ + struct memsegment *new_element; + + new_element = dfu_malloc(sizeof(struct memsegment)); + *new_element = segment; + new_element->next = NULL; + + if (*segment_list == NULL) + /* list can be empty on first call */ + *segment_list = new_element; + else { + struct memsegment *next_element; + + /* find last element in list */ + next_element = *segment_list; + while (next_element->next != NULL) + next_element = next_element->next; + next_element->next = new_element; + } + return 0; +} + +struct memsegment *find_segment(struct memsegment *segment_list, + unsigned int address) +{ + while (segment_list != NULL) { + if (segment_list->start <= address && + segment_list->end >= address) + return segment_list; + segment_list = segment_list->next; + } + return NULL; +} + +void free_segment_list(struct memsegment *segment_list) +{ + struct memsegment *next_element; + + while (segment_list->next != NULL) { + next_element = segment_list->next; + free(segment_list); + segment_list = next_element; + } + free(segment_list); +} + +/* Parse memory map from interface descriptor string + * encoded as per ST document UM0424 section 4.3.2. + */ +struct memsegment *parse_memory_layout(char *intf_desc) +{ + + char multiplier, memtype; + unsigned int address; + int sectors, size; + char *name, *typestring; + int ret; + int count = 0; + char separator; + int scanned; + struct memsegment *segment_list = NULL; + struct memsegment segment; + + name = dfu_malloc(strlen(intf_desc)); + + ret = sscanf(intf_desc, "@%[^/]%n", name, &scanned); + if (ret < 1) { + free(name); + warnx("Could not read name, sscanf returned %d", ret); + return NULL; + } + printf("DfuSe interface name: \"%s\"\n", name); + + intf_desc += scanned; + typestring = dfu_malloc(strlen(intf_desc)); + + while (ret = sscanf(intf_desc, "/0x%x/%n", &address, &scanned), + ret > 0) { + + intf_desc += scanned; + while (ret = sscanf(intf_desc, "%d*%d%c%[^,/]%n", + §ors, &size, &multiplier, typestring, + &scanned), ret > 2) { + intf_desc += scanned; + + count++; + memtype = 0; + if (ret == 4) { + if (strlen(typestring) == 1 + && typestring[0] != '/') + memtype = typestring[0]; + else { + warnx("Parsing type identifier '%s' " + "failed for segment %i", + typestring, count); + continue; + } + } + + /* Quirk for STM32F4 devices */ + if (strcmp(name, "Device Feature") == 0) + memtype = 'e'; + + switch (multiplier) { + case 'B': + break; + case 'K': + size *= 1024; + break; + case 'M': + size *= 1024 * 1024; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + if (!memtype) { + warnx("Non-valid multiplier '%c', " + "interpreted as type " + "identifier instead", + multiplier); + memtype = multiplier; + break; + } + /* fallthrough if memtype was already set */ + default: + warnx("Non-valid multiplier '%c', " + "assuming bytes", multiplier); + } + + if (!memtype) { + warnx("No valid type for segment %d\n", count); + continue; + } + + segment.start = address; + segment.end = address + sectors * size - 1; + segment.pagesize = size; + segment.memtype = memtype & 7; + add_segment(&segment_list, segment); + + if (verbose) + printf("Memory segment at 0x%08x %3d x %4d = " + "%5d (%s%s%s)\n", + address, sectors, size, sectors * size, + memtype & DFUSE_READABLE ? "r" : "", + memtype & DFUSE_ERASABLE ? "e" : "", + memtype & DFUSE_WRITEABLE ? "w" : ""); + + address += sectors * size; + + separator = *intf_desc; + if (separator == ',') + intf_desc += 1; + else + break; + } /* while per segment */ + + } /* while per address */ + free(name); + free(typestring); + + return segment_list; +} diff --git a/tools/src/dfu-util/src/dfuse_mem.h b/tools/src/dfu-util/src/dfuse_mem.h new file mode 100755 index 0000000..8fe7cc4 --- /dev/null +++ b/tools/src/dfu-util/src/dfuse_mem.h @@ -0,0 +1,44 @@ +/* Helper functions for reading the memory map in a device + * following the ST DfuSe 1.1a specification. + * + * (C) 2011 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DFUSE_MEM_H +#define DFUSE_MEM_H + +#define DFUSE_READABLE 1 +#define DFUSE_ERASABLE 2 +#define DFUSE_WRITEABLE 4 + +struct memsegment { + unsigned int start; + unsigned int end; + int pagesize; + int memtype; + struct memsegment *next; +}; + +int add_segment(struct memsegment **list, struct memsegment new_element); + +struct memsegment *find_segment(struct memsegment *list, unsigned int address); + +void free_segment_list(struct memsegment *list); + +struct memsegment *parse_memory_layout(char *intf_desc_str); + +#endif /* DFUSE_MEM_H */ diff --git a/tools/src/dfu-util/src/main.c b/tools/src/dfu-util/src/main.c new file mode 100755 index 0000000..f59d27d --- /dev/null +++ b/tools/src/dfu-util/src/main.c @@ -0,0 +1,699 @@ +/* + * dfu-util + * + * Copyright 2007-2008 by OpenMoko, Inc. + * Copyright 2013-2014 Hans Petter Selasky + * + * Written by Harald Welte + * + * Based on existing code of dfu-programmer-0.4 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "portable.h" +#include "dfu.h" +#include "usb_dfu.h" +#include "dfu_file.h" +#include "dfu_load.h" +#include "dfu_util.h" +#include "dfuse.h" +#include "quirks.h" + +#ifdef HAVE_USBPATH_H +#include +#endif + +int verbose = 0; + +struct dfu_if *dfu_root = NULL; + +int match_bus = -1; +int match_device = -1; +int match_vendor = -1; +int match_product = -1; +int match_vendor_dfu = -1; +int match_product_dfu = -1; +int match_config_index = -1; +int match_iface_index = -1; +int match_iface_alt_index = -1; +const char *match_iface_alt_name = NULL; +const char *match_serial = NULL; +const char *match_serial_dfu = NULL; + +static int parse_match_value(const char *str, int default_value) +{ + char *remainder; + int value; + + if (str == NULL) { + value = default_value; + } else if (*str == '*') { + value = -1; /* Match anything */ + } else if (*str == '-') { + value = 0x10000; /* Impossible vendor/product ID */ + } else { + value = strtoul(str, &remainder, 16); + if (remainder == str) { + value = default_value; + } + } + return value; +} + +static void parse_vendprod(const char *str) +{ + const char *comma; + const char *colon; + + /* Default to match any DFU device in runtime or DFU mode */ + match_vendor = -1; + match_product = -1; + match_vendor_dfu = -1; + match_product_dfu = -1; + + comma = strchr(str, ','); + if (comma == str) { + /* DFU mode vendor/product being specified without any runtime + * vendor/product specification, so don't match any runtime device */ + match_vendor = match_product = 0x10000; + } else { + colon = strchr(str, ':'); + if (colon != NULL) { + ++colon; + if ((comma != NULL) && (colon > comma)) { + colon = NULL; + } + } + match_vendor = parse_match_value(str, match_vendor); + match_product = parse_match_value(colon, match_product); + if (comma != NULL) { + /* Both runtime and DFU mode vendor/product specifications are + * available, so default DFU mode match components to the given + * runtime match components */ + match_vendor_dfu = match_vendor; + match_product_dfu = match_product; + } + } + if (comma != NULL) { + ++comma; + colon = strchr(comma, ':'); + if (colon != NULL) { + ++colon; + } + match_vendor_dfu = parse_match_value(comma, match_vendor_dfu); + match_product_dfu = parse_match_value(colon, match_product_dfu); + } +} + +static void parse_serial(char *str) +{ + char *comma; + + match_serial = str; + comma = strchr(str, ','); + if (comma == NULL) { + match_serial_dfu = match_serial; + } else { + *comma++ = 0; + match_serial_dfu = comma; + } + if (*match_serial == 0) match_serial = NULL; + if (*match_serial_dfu == 0) match_serial_dfu = NULL; +} + +#ifdef HAVE_USBPATH_H + +static int resolve_device_path(char *path) +{ + int res; + + res = usb_path2devnum(path); + if (res < 0) + return -EINVAL; + if (!res) + return 0; + + match_bus = atoi(path); + match_device = res; + + return 0; +} + +#else /* HAVE_USBPATH_H */ + +static int resolve_device_path(char *path) +{ + (void)path; /* Eliminate unused variable warning */ + errx(EX_SOFTWARE, "USB device paths are not supported by this dfu-util.\n"); +} + +#endif /* !HAVE_USBPATH_H */ + +static void help(void) +{ + fprintf(stderr, "Usage: dfu-util [options] ...\n" + " -h --help\t\t\tPrint this help message\n" + " -V --version\t\t\tPrint the version number\n" + " -v --verbose\t\t\tPrint verbose debug statements\n" + " -l --list\t\t\tList currently attached DFU capable devices\n"); + fprintf(stderr, " -e --detach\t\t\tDetach currently attached DFU capable devices\n" + " -E --detach-delay seconds\tTime to wait before reopening a device after detach\n" + " -d --device :[,:]\n" + "\t\t\t\tSpecify Vendor/Product ID(s) of DFU device\n" + " -p --path \tSpecify path to DFU device\n" + " -c --cfg \t\tSpecify the Configuration of DFU device\n" + " -i --intf \t\tSpecify the DFU Interface number\n" + " -S --serial [,]\n" + "\t\t\t\tSpecify Serial String of DFU device\n" + " -a --alt \t\tSpecify the Altsetting of the DFU Interface\n" + "\t\t\t\tby name or by number\n"); + fprintf(stderr, " -t --transfer-size \tSpecify the number of bytes per USB Transfer\n" + " -U --upload \t\tRead firmware from device into \n" + " -Z --upload-size \tSpecify the expected upload size in bytes\n" + " -D --download \t\tWrite firmware from into device\n" + " -R --reset\t\t\tIssue USB Reset signalling once we're finished\n" + " -s --dfuse-address
\tST DfuSe mode, specify target address for\n" + "\t\t\t\traw file download or upload. Not applicable for\n" + "\t\t\t\tDfuSe file (.dfu) downloads\n" + ); + exit(EX_USAGE); +} + +static void print_version(void) +{ + printf(PACKAGE_STRING "\n\n"); + printf("Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.\n" + "Copyright 2010-2014 Tormod Volden and Stefan Schmidt\n" + "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n\n"); +} + +static struct option opts[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "verbose", 0, 0, 'v' }, + { "list", 0, 0, 'l' }, + { "detach", 0, 0, 'e' }, + { "detach-delay", 1, 0, 'E' }, + { "device", 1, 0, 'd' }, + { "path", 1, 0, 'p' }, + { "configuration", 1, 0, 'c' }, + { "cfg", 1, 0, 'c' }, + { "interface", 1, 0, 'i' }, + { "intf", 1, 0, 'i' }, + { "altsetting", 1, 0, 'a' }, + { "alt", 1, 0, 'a' }, + { "serial", 1, 0, 'S' }, + { "transfer-size", 1, 0, 't' }, + { "upload", 1, 0, 'U' }, + { "upload-size", 1, 0, 'Z' }, + { "download", 1, 0, 'D' }, + { "reset", 0, 0, 'R' }, + { "dfuse-address", 1, 0, 's' }, + { 0, 0, 0, 0 } +}; + +int main(int argc, char **argv) +{ + int expected_size = 0; + unsigned int transfer_size = 0; + enum mode mode = MODE_NONE; + struct dfu_status status; + libusb_context *ctx; + struct dfu_file file; + char *end; + int final_reset = 0; + int ret; + int dfuse_device = 0; + int fd; + const char *dfuse_options = NULL; + int detach_delay = 5; + uint16_t runtime_vendor; + uint16_t runtime_product; + + memset(&file, 0, sizeof(file)); + + /* make sure all prints are flushed */ + setvbuf(stdout, NULL, _IONBF, 0); + + while (1) { + int c, option_index = 0; + c = getopt_long(argc, argv, "hVvleE:d:p:c:i:a:S:t:U:D:Rs:Z:", opts, + &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + help(); + break; + case 'V': + mode = MODE_VERSION; + break; + case 'v': + verbose++; + break; + case 'l': + mode = MODE_LIST; + break; + case 'e': + mode = MODE_DETACH; + match_iface_alt_index = 0; + match_iface_index = 0; + break; + case 'E': + detach_delay = atoi(optarg); + break; + case 'd': + parse_vendprod(optarg); + break; + case 'p': + /* Parse device path */ + ret = resolve_device_path(optarg); + if (ret < 0) + errx(EX_SOFTWARE, "Unable to parse '%s'", optarg); + if (!ret) + errx(EX_SOFTWARE, "Cannot find '%s'", optarg); + break; + case 'c': + /* Configuration */ + match_config_index = atoi(optarg); + break; + case 'i': + /* Interface */ + match_iface_index = atoi(optarg); + break; + case 'a': + /* Interface Alternate Setting */ + match_iface_alt_index = strtoul(optarg, &end, 0); + if (*end) { + match_iface_alt_name = optarg; + match_iface_alt_index = -1; + } + break; + case 'S': + parse_serial(optarg); + break; + case 't': + transfer_size = atoi(optarg); + break; + case 'U': + mode = MODE_UPLOAD; + file.name = optarg; + break; + case 'Z': + expected_size = atoi(optarg); + break; + case 'D': + mode = MODE_DOWNLOAD; + file.name = optarg; + break; + case 'R': + final_reset = 1; + break; + case 's': + dfuse_options = optarg; + break; + default: + help(); + break; + } + } + + print_version(); + if (mode == MODE_VERSION) { + exit(0); + } + + if (mode == MODE_NONE) { + fprintf(stderr, "You need to specify one of -D or -U\n"); + help(); + } + + if (match_config_index == 0) { + /* Handle "-c 0" (unconfigured device) as don't care */ + match_config_index = -1; + } + + if (mode == MODE_DOWNLOAD) { + dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); + /* If the user didn't specify product and/or vendor IDs to match, + * use any IDs from the file suffix for device matching */ + if (match_vendor < 0 && file.idVendor != 0xffff) { + match_vendor = file.idVendor; + printf("Match vendor ID from file: %04x\n", match_vendor); + } + if (match_product < 0 && file.idProduct != 0xffff) { + match_product = file.idProduct; + printf("Match product ID from file: %04x\n", match_product); + } + } + + ret = libusb_init(&ctx); + if (ret) + errx(EX_IOERR, "unable to initialize libusb: %i", ret); + + if (verbose > 2) { + libusb_set_debug(ctx, 255); + } + + probe_devices(ctx); + + if (mode == MODE_LIST) { + list_dfu_interfaces(); + exit(0); + } + + if (dfu_root == NULL) { + errx(EX_IOERR, "No DFU capable USB device available"); + } else if (dfu_root->next != NULL) { + /* We cannot safely support more than one DFU capable device + * with same vendor/product ID, since during DFU we need to do + * a USB bus reset, after which the target device will get a + * new address */ + errx(EX_IOERR, "More than one DFU capable USB device found! " + "Try `--list' and specify the serial number " + "or disconnect all but one device\n"); + } + + /* We have exactly one device. Its libusb_device is now in dfu_root->dev */ + + printf("Opening DFU capable USB device...\n"); + ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); + if (ret || !dfu_root->dev_handle) + errx(EX_IOERR, "Cannot open device"); + + printf("ID %04x:%04x\n", dfu_root->vendor, dfu_root->product); + + printf("Run-time device DFU version %04x\n", + libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); + + /* Transition from run-Time mode to DFU mode */ + if (!(dfu_root->flags & DFU_IFF_DFU)) { + int err; + /* In the 'first round' during runtime mode, there can only be one + * DFU Interface descriptor according to the DFU Spec. */ + + /* FIXME: check if the selected device really has only one */ + + runtime_vendor = dfu_root->vendor; + runtime_product = dfu_root->product; + + printf("Claiming USB DFU Runtime Interface...\n"); + if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { + errx(EX_IOERR, "Cannot claim interface %d", + dfu_root->interface); + } + + if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, 0) < 0) { + errx(EX_IOERR, "Cannot set alt interface zero"); + } + + printf("Determining device status: "); + + err = dfu_get_status(dfu_root, &status); + if (err == LIBUSB_ERROR_PIPE) { + printf("Device does not implement get_status, assuming appIDLE\n"); + status.bStatus = DFU_STATUS_OK; + status.bwPollTimeout = 0; + status.bState = DFU_STATE_appIDLE; + status.iString = 0; + } else if (err < 0) { + errx(EX_IOERR, "error get_status"); + } else { + printf("state = %s, status = %d\n", + dfu_state_to_string(status.bState), status.bStatus); + } + milli_sleep(status.bwPollTimeout); + + switch (status.bState) { + case DFU_STATE_appIDLE: + case DFU_STATE_appDETACH: + printf("Device really in Runtime Mode, send DFU " + "detach request...\n"); + if (dfu_detach(dfu_root->dev_handle, + dfu_root->interface, 1000) < 0) { + warnx("error detaching"); + } + if (dfu_root->func_dfu.bmAttributes & USB_DFU_WILL_DETACH) { + printf("Device will detach and reattach...\n"); + } else { + printf("Resetting USB...\n"); + ret = libusb_reset_device(dfu_root->dev_handle); + if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) + errx(EX_IOERR, "error resetting " + "after detach"); + } + break; + case DFU_STATE_dfuERROR: + printf("dfuERROR, clearing status\n"); + if (dfu_clear_status(dfu_root->dev_handle, + dfu_root->interface) < 0) { + errx(EX_IOERR, "error clear_status"); + } + /* fall through */ + default: + warnx("WARNING: Runtime device already in DFU state ?!?"); + libusb_release_interface(dfu_root->dev_handle, + dfu_root->interface); + goto dfustate; + } + libusb_release_interface(dfu_root->dev_handle, + dfu_root->interface); + libusb_close(dfu_root->dev_handle); + dfu_root->dev_handle = NULL; + + if (mode == MODE_DETACH) { + libusb_exit(ctx); + exit(0); + } + + /* keeping handles open might prevent re-enumeration */ + disconnect_devices(); + + milli_sleep(detach_delay * 1000); + + /* Change match vendor and product to impossible values to force + * only DFU mode matches in the following probe */ + match_vendor = match_product = 0x10000; + + probe_devices(ctx); + + if (dfu_root == NULL) { + errx(EX_IOERR, "Lost device after RESET?"); + } else if (dfu_root->next != NULL) { + errx(EX_IOERR, "More than one DFU capable USB device found! " + "Try `--list' and specify the serial number " + "or disconnect all but one device"); + } + + /* Check for DFU mode device */ + if (!(dfu_root->flags | DFU_IFF_DFU)) + errx(EX_SOFTWARE, "Device is not in DFU mode"); + + printf("Opening DFU USB Device...\n"); + ret = libusb_open(dfu_root->dev, &dfu_root->dev_handle); + if (ret || !dfu_root->dev_handle) { + errx(EX_IOERR, "Cannot open device"); + } + } else { + /* we're already in DFU mode, so we can skip the detach/reset + * procedure */ + /* If a match vendor/product was specified, use that as the runtime + * vendor/product, otherwise use the DFU mode vendor/product */ + runtime_vendor = match_vendor < 0 ? dfu_root->vendor : match_vendor; + runtime_product = match_product < 0 ? dfu_root->product : match_product; + } + +dfustate: +#if 0 + printf("Setting Configuration %u...\n", dfu_root->configuration); + if (libusb_set_configuration(dfu_root->dev_handle, dfu_root->configuration) < 0) { + errx(EX_IOERR, "Cannot set configuration"); + } +#endif + printf("Claiming USB DFU Interface...\n"); + if (libusb_claim_interface(dfu_root->dev_handle, dfu_root->interface) < 0) { + errx(EX_IOERR, "Cannot claim interface"); + } + + printf("Setting Alternate Setting #%d ...\n", dfu_root->altsetting); + if (libusb_set_interface_alt_setting(dfu_root->dev_handle, dfu_root->interface, dfu_root->altsetting) < 0) { + errx(EX_IOERR, "Cannot set alternate interface"); + } + +status_again: + printf("Determining device status: "); + if (dfu_get_status(dfu_root, &status ) < 0) { + errx(EX_IOERR, "error get_status"); + } + printf("state = %s, status = %d\n", + dfu_state_to_string(status.bState), status.bStatus); + + milli_sleep(status.bwPollTimeout); + + switch (status.bState) { + case DFU_STATE_appIDLE: + case DFU_STATE_appDETACH: + errx(EX_IOERR, "Device still in Runtime Mode!"); + break; + case DFU_STATE_dfuERROR: + printf("dfuERROR, clearing status\n"); + if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) { + errx(EX_IOERR, "error clear_status"); + } + goto status_again; + break; + case DFU_STATE_dfuDNLOAD_IDLE: + case DFU_STATE_dfuUPLOAD_IDLE: + printf("aborting previous incomplete transfer\n"); + if (dfu_abort(dfu_root->dev_handle, dfu_root->interface) < 0) { + errx(EX_IOERR, "can't send DFU_ABORT"); + } + goto status_again; + break; + case DFU_STATE_dfuIDLE: + printf("dfuIDLE, continuing\n"); + break; + default: + break; + } + + if (DFU_STATUS_OK != status.bStatus ) { + printf("WARNING: DFU Status: '%s'\n", + dfu_status_to_string(status.bStatus)); + /* Clear our status & try again. */ + if (dfu_clear_status(dfu_root->dev_handle, dfu_root->interface) < 0) + errx(EX_IOERR, "USB communication error"); + if (dfu_get_status(dfu_root, &status) < 0) + errx(EX_IOERR, "USB communication error"); + if (DFU_STATUS_OK != status.bStatus) + errx(EX_SOFTWARE, "Status is not OK: %d", status.bStatus); + + milli_sleep(status.bwPollTimeout); + } + + printf("DFU mode device DFU version %04x\n", + libusb_le16_to_cpu(dfu_root->func_dfu.bcdDFUVersion)); + + if (dfu_root->func_dfu.bcdDFUVersion == libusb_cpu_to_le16(0x11a)) + dfuse_device = 1; + + /* If not overridden by the user */ + if (!transfer_size) { + transfer_size = libusb_le16_to_cpu( + dfu_root->func_dfu.wTransferSize); + if (transfer_size) { + printf("Device returned transfer size %i\n", + transfer_size); + } else { + errx(EX_IOERR, "Transfer size must be specified"); + } + } + +#ifdef HAVE_GETPAGESIZE +/* autotools lie when cross-compiling for Windows using mingw32/64 */ +#ifndef __MINGW32__ + /* limitation of Linux usbdevio */ + if ((int)transfer_size > getpagesize()) { + transfer_size = getpagesize(); + printf("Limited transfer size to %i\n", transfer_size); + } +#endif /* __MINGW32__ */ +#endif /* HAVE_GETPAGESIZE */ + + if (transfer_size < dfu_root->bMaxPacketSize0) { + transfer_size = dfu_root->bMaxPacketSize0; + printf("Adjusted transfer size to %i\n", transfer_size); + } + + switch (mode) { + case MODE_UPLOAD: + /* open for "exclusive" writing */ + fd = open(file.name, O_WRONLY | O_BINARY | O_CREAT | O_EXCL | O_TRUNC, 0666); + if (fd < 0) + err(EX_IOERR, "Cannot open file %s for writing", file.name); + + if (dfuse_device || dfuse_options) { + if (dfuse_do_upload(dfu_root, transfer_size, fd, + dfuse_options) < 0) + exit(1); + } else { + if (dfuload_do_upload(dfu_root, transfer_size, + expected_size, fd) < 0) { + exit(1); + } + } + close(fd); + break; + + case MODE_DOWNLOAD: + if (((file.idVendor != 0xffff && file.idVendor != runtime_vendor) || + (file.idProduct != 0xffff && file.idProduct != runtime_product)) && + ((file.idVendor != 0xffff && file.idVendor != dfu_root->vendor) || + (file.idProduct != 0xffff && file.idProduct != dfu_root->product))) { + errx(EX_IOERR, "Error: File ID %04x:%04x does " + "not match device (%04x:%04x or %04x:%04x)", + file.idVendor, file.idProduct, + runtime_vendor, runtime_product, + dfu_root->vendor, dfu_root->product); + } + if (dfuse_device || dfuse_options || file.bcdDFU == 0x11a) { + if (dfuse_do_dnload(dfu_root, transfer_size, &file, + dfuse_options) < 0) + exit(1); + } else { + if (dfuload_do_dnload(dfu_root, transfer_size, &file) < 0) + exit(1); + } + break; + case MODE_DETACH: + if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { + warnx("can't detach"); + } + break; + default: + errx(EX_IOERR, "Unsupported mode: %u", mode); + break; + } + + if (final_reset) { + if (dfu_detach(dfu_root->dev_handle, dfu_root->interface, 1000) < 0) { + /* Even if detach failed, just carry on to leave the + device in a known state */ + warnx("can't detach"); + } + printf("Resetting USB to switch back to runtime mode\n"); + ret = libusb_reset_device(dfu_root->dev_handle); + if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND) { + errx(EX_IOERR, "error resetting after download"); + } + } + + libusb_close(dfu_root->dev_handle); + dfu_root->dev_handle = NULL; + libusb_exit(ctx); + + return (0); +} diff --git a/tools/src/dfu-util/src/portable.h b/tools/src/dfu-util/src/portable.h new file mode 100755 index 0000000..2609232 --- /dev/null +++ b/tools/src/dfu-util/src/portable.h @@ -0,0 +1,72 @@ + +#ifndef PORTABLE_H +#define PORTABLE_H + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define PACKAGE "dfu-util" +# define PACKAGE_VERSION "0.8-msvc" +# define PACKAGE_STRING "dfu-util 0.8-msvc" +# define PACKAGE_BUGREPORT "dfu-util@lists.gnumonks.org" +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_FTRUNCATE +# include +#else +# include +#endif /* HAVE_FTRUNCATE */ + +#ifdef HAVE_NANOSLEEP +# include +# define milli_sleep(msec) do {\ + if (msec) {\ + struct timespec nanosleepDelay = { (msec) / 1000, ((msec) % 1000) * 1000000 };\ + nanosleep(&nanosleepDelay, NULL);\ + } } while (0) +#elif defined HAVE_WINDOWS_H +# define milli_sleep(msec) do {\ + if (msec) {\ + Sleep(msec);\ + } } while (0) +#else +# error "Can't get no sleep! Please report" +#endif /* HAVE_NANOSLEEP */ + +#ifdef HAVE_ERR +# include +#else +# include +# include +# define warnx(...) do {\ + fprintf(stderr, __VA_ARGS__);\ + fprintf(stderr, "\n"); } while (0) +# define errx(eval, ...) do {\ + warnx(__VA_ARGS__);\ + exit(eval); } while (0) +# define warn(...) do {\ + fprintf(stderr, "%s: ", strerror(errno));\ + warnx(__VA_ARGS__); } while (0) +# define err(eval, ...) do {\ + warn(__VA_ARGS__);\ + exit(eval); } while (0) +#endif /* HAVE_ERR */ + +#ifdef HAVE_SYSEXITS_H +# include +#else +# define EX_OK 0 /* successful termination */ +# define EX_USAGE 64 /* command line usage error */ +# define EX_SOFTWARE 70 /* internal software error */ +# define EX_IOERR 74 /* input/output error */ +#endif /* HAVE_SYSEXITS_H */ + +#ifndef O_BINARY +# define O_BINARY 0 +#endif + +#ifndef off_t +# define off_t long int +#endif + +#endif /* PORTABLE_H */ diff --git a/tools/src/dfu-util/src/prefix.c b/tools/src/dfu-util/src/prefix.c new file mode 100755 index 0000000..05692f9 --- /dev/null +++ b/tools/src/dfu-util/src/prefix.c @@ -0,0 +1,176 @@ +/* + * dfu-prefix + * + * Copyright 2011-2012 Stefan Schmidt + * Copyright 2013 Hans Petter Selasky + * Copyright 2014 Uwe Bonnes + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "portable.h" +#include "dfu_file.h" + +enum mode { + MODE_NONE, + MODE_ADD, + MODE_DEL, + MODE_CHECK +}; + +int verbose; + +static void help(void) +{ + fprintf(stderr, "Usage: dfu-prefix [options] ...\n" + " -h --help\t\t\tPrint this help message\n" + " -V --version\t\t\tPrint the version number\n" + " -c --check \t\tCheck DFU prefix of \n" + " -D --delete \t\tDelete DFU prefix from \n" + " -a --add \t\tAdd DFU prefix to \n" + "In combination with -a:\n" + ); + fprintf(stderr, " -s --stellaris-address
Add TI Stellaris address prefix to \n" + "In combination with -D or -c:\n" + " -T --stellaris\t\tAct on TI Stellaris address prefix of \n" + "In combination with -a or -D or -c:\n" + " -L --lpc-prefix\t\tUse NXP LPC DFU prefix format\n" + ); + exit(EX_USAGE); +} + +static void print_version(void) +{ + printf("dfu-prefix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); + printf("Copyright 2011-2012 Stefan Schmidt, 2014 Uwe Bonnes\n" + "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" + "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); + +} + +static struct option opts[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "check", 1, 0, 'c' }, + { "add", 1, 0, 'a' }, + { "delete", 1, 0, 'D' }, + { "stellaris-address", 1, 0, 's' }, + { "stellaris", 0, 0, 'T' }, + { "LPC", 0, 0, 'L' }, +}; +int main(int argc, char **argv) +{ + struct dfu_file file; + enum mode mode = MODE_NONE; + enum prefix_type type = ZERO_PREFIX; + uint32_t lmdfu_flash_address = 0; + char *end; + + /* make sure all prints are flushed */ + setvbuf(stdout, NULL, _IONBF, 0); + + print_version(); + + memset(&file, 0, sizeof(file)); + + while (1) { + int c, option_index = 0; + c = getopt_long(argc, argv, "hVc:a:D:p:v:d:s:TL", opts, + &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + help(); + break; + case 'V': + exit(0); + break; + case 'D': + file.name = optarg; + mode = MODE_DEL; + break; + case 'c': + file.name = optarg; + mode = MODE_CHECK; + break; + case 'a': + file.name = optarg; + mode = MODE_ADD; + break; + case 's': + lmdfu_flash_address = strtoul(optarg, &end, 0); + if (*end) { + errx(EX_IOERR, "Invalid lmdfu " + "address: %s", optarg); + } + /* fall-through */ + case 'T': + type = LMDFU_PREFIX; + break; + case 'L': + type = LPCDFU_UNENCRYPTED_PREFIX; + break; + default: + help(); + break; + } + } + + if (!file.name) { + fprintf(stderr, "You need to specify a filename\n"); + help(); + } + + switch(mode) { + case MODE_ADD: + if (type == ZERO_PREFIX) + errx(EX_IOERR, "Prefix type must be specified"); + dfu_load_file(&file, MAYBE_SUFFIX, NO_PREFIX); + file.lmdfu_address = lmdfu_flash_address; + file.prefix_type = type; + printf("Adding prefix to file\n"); + dfu_store_file(&file, file.size.suffix != 0, 1); + break; + + case MODE_CHECK: + dfu_load_file(&file, MAYBE_SUFFIX, MAYBE_PREFIX); + show_suffix_and_prefix(&file); + if (type > ZERO_PREFIX && file.prefix_type != type) + errx(EX_IOERR, "No prefix of requested type"); + break; + + case MODE_DEL: + dfu_load_file(&file, MAYBE_SUFFIX, NEEDS_PREFIX); + if (type > ZERO_PREFIX && file.prefix_type != type) + errx(EX_IOERR, "No prefix of requested type"); + printf("Removing prefix from file\n"); + /* if there was a suffix, rewrite it */ + dfu_store_file(&file, file.size.suffix != 0, 0); + break; + + default: + help(); + break; + } + return (0); +} diff --git a/tools/src/dfu-util/src/quirks.c b/tools/src/dfu-util/src/quirks.c new file mode 100755 index 0000000..c90e585 --- /dev/null +++ b/tools/src/dfu-util/src/quirks.c @@ -0,0 +1,56 @@ +/* + * Simple quirk system for dfu-util + * + * Copyright 2010-2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include "quirks.h" + +uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice) +{ + uint16_t quirks = 0; + + /* Device returns bogus bwPollTimeout values */ + if ((vendor == VENDOR_OPENMOKO || vendor == VENDOR_FIC) && + product >= PRODUCT_FREERUNNER_FIRST && + product <= PRODUCT_FREERUNNER_LAST) + quirks |= QUIRK_POLLTIMEOUT; + + if (vendor == VENDOR_VOTI && + product == PRODUCT_OPENPCD) + quirks |= QUIRK_POLLTIMEOUT; + + /* Reports wrong DFU version in DFU descriptor */ + if (vendor == VENDOR_LEAFLABS && + product == PRODUCT_MAPLE3 && + bcdDevice == 0x0200) + quirks |= QUIRK_FORCE_DFU11; + + /* old devices(bcdDevice == 0) return bogus bwPollTimeout values */ + if (vendor == VENDOR_SIEMENS && + (product == PRODUCT_PXM40 || product == PRODUCT_PXM50) && + bcdDevice == 0) + quirks |= QUIRK_POLLTIMEOUT; + + /* M-Audio Transit returns bogus bwPollTimeout values */ + if (vendor == VENDOR_MIDIMAN && + product == PRODUCT_TRANSIT) + quirks |= QUIRK_POLLTIMEOUT; + + return (quirks); +} diff --git a/tools/src/dfu-util/src/quirks.h b/tools/src/dfu-util/src/quirks.h new file mode 100755 index 0000000..3193f25 --- /dev/null +++ b/tools/src/dfu-util/src/quirks.h @@ -0,0 +1,27 @@ +#ifndef DFU_QUIRKS_H +#define DFU_QUIRKS_H + +#define VENDOR_OPENMOKO 0x1d50 /* Openmoko Freerunner / GTA02 */ +#define VENDOR_FIC 0x1457 /* Openmoko Freerunner / GTA02 */ +#define VENDOR_VOTI 0x16c0 /* OpenPCD Reader */ +#define VENDOR_LEAFLABS 0x1eaf /* Maple */ +#define VENDOR_SIEMENS 0x0908 /* Siemens AG */ +#define VENDOR_MIDIMAN 0x0763 /* Midiman */ + +#define PRODUCT_FREERUNNER_FIRST 0x5117 +#define PRODUCT_FREERUNNER_LAST 0x5126 +#define PRODUCT_OPENPCD 0x076b +#define PRODUCT_MAPLE3 0x0003 /* rev 3 and 5 */ +#define PRODUCT_PXM40 0x02c4 /* Siemens AG, PXM 40 */ +#define PRODUCT_PXM50 0x02c5 /* Siemens AG, PXM 50 */ +#define PRODUCT_TRANSIT 0x2806 /* M-Audio Transit (Midiman) */ + +#define QUIRK_POLLTIMEOUT (1<<0) +#define QUIRK_FORCE_DFU11 (1<<1) + +/* Fallback value, works for OpenMoko */ +#define DEFAULT_POLLTIMEOUT 5 + +uint16_t get_quirks(uint16_t vendor, uint16_t product, uint16_t bcdDevice); + +#endif /* DFU_QUIRKS_H */ diff --git a/tools/src/dfu-util/src/suffix.c b/tools/src/dfu-util/src/suffix.c new file mode 100755 index 0000000..ba02a01 --- /dev/null +++ b/tools/src/dfu-util/src/suffix.c @@ -0,0 +1,176 @@ +/* + * dfu-suffix + * + * Copyright 2011-2012 Stefan Schmidt + * Copyright 2013 Hans Petter Selasky + * Copyright 2014 Tormod Volden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#include "portable.h" +#include "dfu_file.h" + +enum mode { + MODE_NONE, + MODE_ADD, + MODE_DEL, + MODE_CHECK +}; + +int verbose; + +static void help(void) +{ + fprintf(stderr, "Usage: dfu-suffix [options] ...\n" + " -h --help\t\t\tPrint this help message\n" + " -V --version\t\t\tPrint the version number\n" + " -c --check \t\tCheck DFU suffix of \n" + " -a --add \t\tAdd DFU suffix to \n" + " -D --delete \t\tDelete DFU suffix from \n" + " -p --pid \t\tAdd product ID into DFU suffix in \n" + " -v --vid \t\tAdd vendor ID into DFU suffix in \n" + " -d --did \t\tAdd device ID into DFU suffix in \n" + " -S --spec \t\tAdd DFU specification ID into DFU suffix in \n" + ); + exit(EX_USAGE); +} + +static void print_version(void) +{ + printf("dfu-suffix (%s) %s\n\n", PACKAGE, PACKAGE_VERSION); + printf("Copyright 2011-2012 Stefan Schmidt, 2013-2014 Tormod Volden\n" + "This program is Free Software and has ABSOLUTELY NO WARRANTY\n" + "Please report bugs to %s\n\n", PACKAGE_BUGREPORT); + +} + +static struct option opts[] = { + { "help", 0, 0, 'h' }, + { "version", 0, 0, 'V' }, + { "check", 1, 0, 'c' }, + { "add", 1, 0, 'a' }, + { "delete", 1, 0, 'D' }, + { "pid", 1, 0, 'p' }, + { "vid", 1, 0, 'v' }, + { "did", 1, 0, 'd' }, + { "spec", 1, 0, 'S' }, +}; + +int main(int argc, char **argv) +{ + struct dfu_file file; + int pid, vid, did, spec; + enum mode mode = MODE_NONE; + + /* make sure all prints are flushed */ + setvbuf(stdout, NULL, _IONBF, 0); + + print_version(); + + pid = vid = did = 0xffff; + spec = 0x0100; /* Default to bcdDFU version 1.0 */ + memset(&file, 0, sizeof(file)); + + while (1) { + int c, option_index = 0; + c = getopt_long(argc, argv, "hVc:a:D:p:v:d:S:s:T", opts, + &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + help(); + break; + case 'V': + exit(0); + break; + case 'D': + file.name = optarg; + mode = MODE_DEL; + break; + case 'p': + pid = strtol(optarg, NULL, 16); + break; + case 'v': + vid = strtol(optarg, NULL, 16); + break; + case 'd': + did = strtol(optarg, NULL, 16); + break; + case 'S': + spec = strtol(optarg, NULL, 16); + break; + case 'c': + file.name = optarg; + mode = MODE_CHECK; + break; + case 'a': + file.name = optarg; + mode = MODE_ADD; + break; + default: + help(); + break; + } + } + + if (!file.name) { + fprintf(stderr, "You need to specify a filename\n"); + help(); + } + + if (spec != 0x0100 && spec != 0x011a) { + fprintf(stderr, "Only DFU specification 0x0100 and 0x011a supported\n"); + help(); + } + + switch(mode) { + case MODE_ADD: + dfu_load_file(&file, NO_SUFFIX, MAYBE_PREFIX); + file.idVendor = vid; + file.idProduct = pid; + file.bcdDevice = did; + file.bcdDFU = spec; + /* always write suffix, rewrite prefix if there was one */ + dfu_store_file(&file, 1, file.size.prefix != 0); + printf("Suffix successfully added to file\n"); + break; + + case MODE_CHECK: + dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); + show_suffix_and_prefix(&file); + break; + + case MODE_DEL: + dfu_load_file(&file, NEEDS_SUFFIX, MAYBE_PREFIX); + dfu_store_file(&file, 0, file.size.prefix != 0); + if (file.size.suffix) /* had a suffix */ + printf("Suffix successfully removed from file\n"); + break; + + default: + help(); + break; + } + return (0); +} diff --git a/tools/src/dfu-util/src/usb_dfu.h b/tools/src/dfu-util/src/usb_dfu.h new file mode 100755 index 0000000..f6fe270 --- /dev/null +++ b/tools/src/dfu-util/src/usb_dfu.h @@ -0,0 +1,99 @@ +#ifndef USB_DFU_H +#define USB_DFU_H +/* USB Device Firmware Update Implementation for OpenPCD + * (C) 2006 by Harald Welte + * + * Protocol definitions for USB DFU + * + * This ought to be compliant to the USB DFU Spec 1.0 as available from + * http://www.usb.org/developers/devclass_docs/usbdfu10.pdf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#define USB_DT_DFU 0x21 + +#ifdef _MSC_VER +# pragma pack(push) +# pragma pack(1) +#endif /* _MSC_VER */ +struct usb_dfu_func_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bmAttributes; +#define USB_DFU_CAN_DOWNLOAD (1 << 0) +#define USB_DFU_CAN_UPLOAD (1 << 1) +#define USB_DFU_MANIFEST_TOL (1 << 2) +#define USB_DFU_WILL_DETACH (1 << 3) + uint16_t wDetachTimeOut; + uint16_t wTransferSize; + uint16_t bcdDFUVersion; +#ifdef _MSC_VER +}; +# pragma pack(pop) +#elif defined __GNUC__ +} __attribute__ ((packed)); +#else + #warning "No way to pack struct on this compiler? This will break!" +#endif /* _MSC_VER */ + +#define USB_DT_DFU_SIZE 9 + +#define USB_TYPE_DFU (LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE) + +/* DFU class-specific requests (Section 3, DFU Rev 1.1) */ +#define USB_REQ_DFU_DETACH 0x00 +#define USB_REQ_DFU_DNLOAD 0x01 +#define USB_REQ_DFU_UPLOAD 0x02 +#define USB_REQ_DFU_GETSTATUS 0x03 +#define USB_REQ_DFU_CLRSTATUS 0x04 +#define USB_REQ_DFU_GETSTATE 0x05 +#define USB_REQ_DFU_ABORT 0x06 + +/* DFU_GETSTATUS bStatus values (Section 6.1.2, DFU Rev 1.1) */ +#define DFU_STATUS_OK 0x00 +#define DFU_STATUS_errTARGET 0x01 +#define DFU_STATUS_errFILE 0x02 +#define DFU_STATUS_errWRITE 0x03 +#define DFU_STATUS_errERASE 0x04 +#define DFU_STATUS_errCHECK_ERASED 0x05 +#define DFU_STATUS_errPROG 0x06 +#define DFU_STATUS_errVERIFY 0x07 +#define DFU_STATUS_errADDRESS 0x08 +#define DFU_STATUS_errNOTDONE 0x09 +#define DFU_STATUS_errFIRMWARE 0x0a +#define DFU_STATUS_errVENDOR 0x0b +#define DFU_STATUS_errUSBR 0x0c +#define DFU_STATUS_errPOR 0x0d +#define DFU_STATUS_errUNKNOWN 0x0e +#define DFU_STATUS_errSTALLEDPKT 0x0f + +enum dfu_state { + DFU_STATE_appIDLE = 0, + DFU_STATE_appDETACH = 1, + DFU_STATE_dfuIDLE = 2, + DFU_STATE_dfuDNLOAD_SYNC = 3, + DFU_STATE_dfuDNBUSY = 4, + DFU_STATE_dfuDNLOAD_IDLE = 5, + DFU_STATE_dfuMANIFEST_SYNC = 6, + DFU_STATE_dfuMANIFEST = 7, + DFU_STATE_dfuMANIFEST_WAIT_RST = 8, + DFU_STATE_dfuUPLOAD_IDLE = 9, + DFU_STATE_dfuERROR = 10 +}; + +#endif /* USB_DFU_H */ diff --git a/tools/src/dfu-util/www/build.html b/tools/src/dfu-util/www/build.html new file mode 100755 index 0000000..2e6de0c --- /dev/null +++ b/tools/src/dfu-util/www/build.html @@ -0,0 +1,147 @@ + + + + + + + Building dfu-util from source + + + + + + + + + +
+

How to build dfu-util from source

+ +

Prerequisites for building from git

+

Mac OS X

+

+First install MacPorts (and if you are on 10.6 or older, the Java Developer Package) and then run: +

+
+	sudo port install libusb-devel git-core
+
+ +

FreeBSD

+
+	sudo pkg_add -r git pkgconf
+
+ +

Ubuntu and Debian and derivatives

+
+	sudo apt-get build-dep dfu-util
+	sudo apt-get install libusb-1.0-0-dev
+
+ +

Get the source code and build it

+

+The first time you will have to clone the git repository: +

+
+	git clone git://gitorious.org/dfu-util/dfu-util.git
+	cd dfu-util
+
+

+If you later want to update to latest git version, just run this: +

+
+	make maintainer-clean
+	git pull
+
+

+To build the source: +

+
+	./autogen.sh
+	./configure  # on most systems
+	make
+
+ +

+If you are building on Mac OS X, replace the ./configure command with: +

+
+	./configure --libdir=/opt/local/lib --includedir=/opt/local/include  # on MacOSX only
+
+ +

+Your dfu-util binary will be inside the src folder. Use it from there, or install it to /usr/local/bin by running "sudo make install". +

+ +

Cross-building for Windows

+ +

+Windows binaries can be built in a MinGW +environment, on a Windows computer or cross-hosted in another OS. +To build it on a Debian or Ubuntu host, first install build dependencies: +

+
+	sudo apt-get build-dep libusb-1.0-0 dfu-util
+	sudo apt-get install mingw32
+
+ +

+The below example builds dfu-util 0.8 and libusb 1.0.19 from unpacked release +tarballs. If you instead build from git, you will have to run "./autogen.sh" +before running the "./configure" steps. +

+ +
+mkdir -p build
+cd libusb-1.0.19
+PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
+    --host=i586-mingw32msvc --prefix=$PWD/../build
+# WINVER workaround needed for 1.0.19 only
+make CFLAGS="-DWINVER=0x0501"
+make install
+cd ..
+
+cd dfu-util-0.8
+PKG_CONFIG_PATH=$PWD/../build/lib/pkgconfig ./configure \
+    --host=i586-mingw32msvc --prefix=$PWD/../build
+make
+make install
+cd ..
+
+The build files will now be in build/bin. +

+ +

Building on Windows using MinGW

+This assumes using release tarballs or having run ./autogen.sh on +the git sources. +
+cd libusb-1.0.19
+./configure --prefix=$HOME
+# WINVER workaround needed for 1.0.19 only
+# MKDIR_P setting should not really be needed...
+make CFLAGS="-DWINVER=0x0501" MKDIR_P="mkdir -p"
+make install
+cd ..
+
+cd dfu-util-0.8
+./configure USB_CFLAGS="-I$HOME/include/libusb-1.0" \
+            USB_LIBS="-L $HOME/lib -lusb-1.0" PKG_CONFIG=true
+make
+make install
+cd ..
+
+To link libusb statically into dfu-util.exe use instead of "make": +
+make LDFLAGS=-static
+
+The built executables (and DLL) will now be under $HOME/bin. + +

+[Back to dfu-util main page] +

+ +
+ + diff --git a/tools/src/dfu-util/www/dfu-util.1.html b/tools/src/dfu-util/www/dfu-util.1.html new file mode 100755 index 0000000..667a369 --- /dev/null +++ b/tools/src/dfu-util/www/dfu-util.1.html @@ -0,0 +1,411 @@ + + +Man page of DFU-UTIL + + +

DFU-UTIL(1)

+ +  +

NAME

+ +dfu-util - Device firmware update (DFU) USB programmer +  +

SYNOPSIS

+ + +
+
+dfu-util + +-l + +[-v] + +[-d + +vid:pid[,vid:pid]] + +[-p + +path] + +[-c + +configuration] + +[-i + +interface] + +[-a + +alt-intf] + +[-S + +serial[,serial]] + + +
+dfu-util + +[-v] + +[-d + +vid:pid[,vid:pid]] + +[-p + +path] + +[-c + +configuration] + +[-i + +interface] + +[-a + +alt-intf] + +[-S + +serial[,serial]] + +[-t + +size] + +[-Z + +size] + +[-s + +address] + +[-R] + +[-D|-U + +file] + + +
+dfu-util + +[-hV] + +
+  +

DESCRIPTION

+ +dfu-util + +is a program that implements the host (computer) side of the USB DFU +(Universal Serial Bus Device Firmware Upgrade) protocol. +

+dfu-util communicates with devices that implement the device side of the +USB DFU protocol, and is often used to upgrade the firmware of such +devices. +  +

OPTIONS

+ +
+
-l, --list + +
+List the currently attached DFU capable USB devices. +
-d, --device [Run-Time VENDOR]:[Run-Time PRODUCT][,[DFU Mode VENDOR]:[DFU Mode PRODUCT]] + +
+
+Specify run-time and/or DFU mode vendor and/or product IDs of the DFU device +to work with. VENDOR and PRODUCT are hexadecimal numbers (no prefix +needed), "*" (match any), or "-" (match nothing). By default, any DFU capable +device in either run-time or DFU mode will be considered. +

+If you only have one standards-compliant DFU device attached to your computer, +this parameter is optional. However, as soon as you have multiple DFU devices +connected, dfu-util will detect this and abort, asking you to specify which +device to use. +

+If only run-time IDs are specified (e.g. "--device 1457:51ab"), then in +addition to the specified run-time IDs, any DFU mode devices will also be +considered. This is beneficial to allow a DFU capable device to be found +again after a switch to DFU mode, since the vendor and/or product ID of a +device usually changes in DFU mode. +

+If only DFU mode IDs are specified (e.g. "--device ,951:26"), then all +run-time devices will be ignored, making it easy to target a specific device in +DFU mode. +

+If both run-time and DFU mode IDs are specified (e.g. "--device +1457:51ab,:2bc"), then unspecified DFU mode components will use the run-time +value specified. +

+Examples: +

+
--device 1457:51ab,951:26 + +
+
+ +Work with a device in run-time mode with +vendor ID 0x1457 and product ID 0x51ab, or in DFU mode with vendor ID 0x0951 +and product ID 0x0026 +

+

--device 1457:51ab,:2bc + +
+
+ +Work with a device in run-time mode with vendor ID 0x1457 and product ID +0x51ab, or in DFU mode with vendor ID 0x1457 and product ID 0x02bc +

+

--device 1457:51ab + +
+
+ +Work with a device in run-time mode with vendor ID 0x1457 and product ID +0x51ab, or in DFU mode with any vendor and product ID +

+

--device ,951:26 + +
+
+ +Work with a device in DFU mode with vendor ID 0x0951 and product ID 0x0026 +

+

--device *,- + +
+
+ +Work with any device in run-time mode, and ignore any device in DFU mode +

+

--device , + +
+
+ +Ignore any device in run-time mode, and Work with any device in DFU mode +
+
+ +
-p, --path BUS-PORT. ... .PORT + +
+Specify the path to the DFU device. +
-c, --cfg CONFIG-NR + +
+Specify the configuration of the DFU device. Note that this is only used for matching, the configuration is not set by dfu-util. +
-i, --intf INTF-NR + +
+Specify the DFU interface number. +
-a, --alt ALT + +
+Specify the altsetting of the DFU interface by name or by number. +
-S, --serial [Run-Time SERIAL][,[DFU Mode SERIAL]] + +
+Specify the run-time and DFU mode serial numbers used to further restrict +device matches. If multiple, identical DFU devices are simultaneously +connected to a system then vendor and product ID will be insufficient for +targeting a single device. In this situation, it may be possible to use this +parameter to specify a serial number which also must match. +

+If only a single serial number is specified, then the same serial number is +used in both run-time and DFU mode. An empty serial number will match any +serial number in the corresponding mode. +

-t, --transfer-size SIZE + +
+Specify the number of bytes per USB transfer. The optimal value is +usually determined automatically so this option is rarely useful. If +you need to use this option for a device, please report it as a bug. +
-Z, --upload-size SIZE + +
+Specify the expected upload size, in bytes. +
-U, --upload FILE + +
+Read firmware from device into +FILE. + +
-D, --download FILE + +
+Write firmware from +FILE + +into device. +
-R, --reset + +
+Issue USB reset signalling after upload or download has finished. +
-s, --dfuse-address address + +
+Specify target address for raw binary download/upload on DfuSe devices. Do +not + +use this for downloading DfuSe (.dfu) files. Modifiers can be added +to the address, separated by a colon, to perform special DfuSE commands such +as "leave" DFU mode, "unprotect" and "mass-erase" flash memory. +
-v, --verbose + +
+Print more information about dfu-util's operation. A second +-v + +will turn on verbose logging of USB requests. Repeat this option to further +increase verbosity. +
-h, --help + +
+Show a help text and exit. +
-V, --version + +
+Show version information and exit. +
+  +

EXAMPLES

+ +  +

Using dfu-util in the OpenMoko project

+ +(with the Neo1973 hardware) +

+ +Flashing the rootfs: +
+ + $ dfu-util -a rootfs -R -D /path/to/openmoko-devel-image.jffs2 + +

+ +Flashing the kernel: +
+ + $ dfu-util -a kernel -R -D /path/to/uImage + +

+ +Flashing the bootloader: +
+ + $ dfu-util -a u-boot -R -D /path/to/u-boot.bin + +

+ +Copying a kernel into RAM: +
+ + $ dfu-util -a 0 -R -D /path/to/uImage + +

+Once this has finished, the kernel will be available at the default load +address of 0x32000000 in Neo1973 RAM. +Note: + +You cannot transfer more than 2MB of data into RAM using this method. +

+  +

Using dfu-util with a DfuSe device

+ +

+ +Flashing a +.dfu + +(special DfuSe format) file to the device: +
+ + $ dfu-util -a 0 -D /path/to/dfuse-image.dfu + +

+ +Reading out 1 KB of flash starting at address 0x8000000: +
+ + $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin + +

+ +Flashing a binary file to address 0x8004000 of device memory and +ask the device to leave DFU mode: +
+ + $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin + + +  +

BUGS

+ +Please report any bugs to the dfu-util mailing list at +dfu-util@lists.gnumonks.org. + +Please use the +--verbose option (repeated as necessary) to provide more + +information in your bug report. +  +

SEE ALSO

+ +The dfu-util home page is +http://dfu-util.gnumonks.org + +  +

HISTORY

+ +dfu-util was originally written for the OpenMoko project by +Weston Schmidt <weston_schmidt@yahoo.com> and +Harald Welte <hwelte@hmw-consulting.de>. Over time, nearly complete +support of DFU 1.0, DFU 1.1 and DfuSe ("1.1a") has been added. +  +

LICENCE

+ +dfu-util + +is covered by the GNU General Public License (GPL), version 2 or later. +  +

COPYRIGHT

+ +This manual page was originally written by Uwe Hermann <uwe@hermann-uwe.de>, +and is now part of the dfu-util project. +

+ +


+ 

Index

+
+
NAME
+
SYNOPSIS
+
DESCRIPTION
+
OPTIONS
+
EXAMPLES
+
+
Using dfu-util in the OpenMoko project
+
Using dfu-util with a DfuSe device
+
+
BUGS
+
SEE ALSO
+
HISTORY
+
LICENCE
+
COPYRIGHT
+
+
+This document was created by man2html, +using the doc/dfu-util.1 manual page from dfu-util 0.8.
+Time: 14:40:57 GMT, September 13, 2014 + + diff --git a/tools/src/dfu-util/www/dfuse.html b/tools/src/dfu-util/www/dfuse.html new file mode 100755 index 0000000..ebb9784 --- /dev/null +++ b/tools/src/dfu-util/www/dfuse.html @@ -0,0 +1,135 @@ + + + + + + DfuSe and dfu-util + + + + + + + + + +
+

Using dfu-util with DfuSe devices

+

DfuSe

+

+ DfuSe (DFU with ST Microsystems extensions) is a protocol based on + DFU 1.1. However, in expanding the functionality of the DFU protocol, + ST Microsystems broke all compatibility with the DFU 1.1 standard. + DfuSe devices report the DFU version as "1.1a". +

+

+ DfuSe can be used to download firmware and other data + from a host computer to a conforming device (or upload in the + opposite direction) over USB similar to standard DFU. +

+

+ The main difference from standard DFU is that the target address in + the device (flash) memory is specified by the host, so that a + download can be performed to parts of the device memory. The host + program is also responsible for erasing flash pages before they + are written to. +

+

.dfu files

+

+ A special file format is defined by ST Microsystems to carry firmware + for DfuSe devices. The file contains target information such as address + and alternate interface information in addition to the binary data. + Several blocks of binary data can be combined in one .dfu file. +

+

Alternate interfaces

+

+ Different memory locations of the device may have different + characteristics that the host program (dfu-util) has to take + into considerations, such as flash memory page size, read-only + versus read-write segments, the need to erase, and so on. + These parameters are reported by the device in the string + descriptors meant for describing the USB interfaces. + The host program decodes these strings to build a memory map of + the device. Different memory units or address spaces are listed + in separate alternate interface settings that must be selected + according to the memory unit to access. +

+

+ Note that dfu-util leaves it to the user to select alternate + interface. When parsing a .dfu file it will skip file segments + not matching the selected alternate interface. Also, some + DfuSe device firmware implementations ignore the setting of + alternate interface and deduct the memory unit from the + address, since they have no address space overlap. +

+

DfuSe special commands

+

+ DfuSe special commands are used by the host program during normal + downloads or uploads, such as SET_ADDRESS and ERASE_PAGE. Also + the normal DFU_DNLOAD and DFU_UPLOAD commands have special + implementations in DfuSe. + Many DfuSe devices also support commands to leave DFU mode, + read unprotect the flash memory or mass erase the flash memory. + dfu-util (from version 0.7) + supports adding "leave", "unprotect", or "mass-erase" + to the -s option argument to send such requests in combination + with a download request. These modifiers are separated with a colon. +

+

+ Some DfuSe devices have their DfuSe bootloader running from flash + memory. Erasing the whole flash memory would therefore destroy + the DfuSe bootloader itself and practically brick the device + for most users. Any use of modifiers such as "unprotect" + and "mass-erase" therefore needs to be combined with the "force" + modifer. This is not included in the examples, to not encourage + ignorant users to copy and paste such instructions and shoot + themselves in the foot. +

+

+ Devices based on for instance STM32F103 all run the bootloader + from flash, since there is no USB bootloader in ROM. +

+

+ For instance STM32F107, STM32F2xx and STM32F4xx devices have a + DfuSe bootloader in ROM, so the flash can be erased while + keeping the device available for USB DFU transfers as long + as the device designers use this built-in bootloader and have + not implemented another DfuSe bootloader in flash that the user is + dependent upon. +

+

+ Well-written bootloaders running from flash will report their + own memory region as read-only and not eraseable, but this does + not prevent dfu-util from sending a "unprotect" or "mass-erase" + request which overrides this, if the user insists. +

+

Example usage

+

+ Flashing a .dfu (special DfuSe format) file to the device: +

+
+         $ dfu-util -a 0 -D /path/to/dfuse-image.dfu
+	
+

+ Reading out 1 KB of flash starting at address 0x8000000: +

+
+         $ dfu-util -a 0 -s 0x08000000:1024 -U newfile.bin
+	
+

+ Flashing a binary file to address 0x8004000 of device memory and ask + the device to leave DFU mode: +

+
+         $ dfu-util -a 0 -s 0x08004000:leave -D /path/to/image.bin
+	
+

+ [Back to dfu-util main page] +

+ +
+ + diff --git a/tools/src/dfu-util/www/index.html b/tools/src/dfu-util/www/index.html new file mode 100755 index 0000000..9bb3223 --- /dev/null +++ b/tools/src/dfu-util/www/index.html @@ -0,0 +1,119 @@ + + + + + + dfu-util Homepage + + + + + + + + + +
+

dfu-util - Device Firmware Upgrade Utilities

+

Description

+

+ dfu-util is a host side implementation of the DFU 1.0 and DFU 1.1 specifications of the USB forum. + + DFU is intended to download and upload firmware to/from devices connected + over USB. It ranges from small devices like micro-controller boards + to mobile phones. Using dfu-util you can download firmware to your + DFU-enabled device or upload firmware from it. dfu-util has been + tested with the Openmoko Neo1973 and Freerunner and many other devices. +

+

+ See the manual page for examples of use. +

+

Supported Devices

+ +

Releases

+

+ Releases of the dfu-util software can be found in the + releases folder. + The current release is 0.8. +

+

+ We offer binaries for Microsoft Windows and some other platforms. + dfu-util uses libusb 1.0 to access your device, so + on Windows you have to register the device with the WinUSB driver + (alternatively libusb-win32 or libusbK), please see the libusbx wiki + for more details. +

+

+ Mac OS X users can also get dfu-util from Homebrew with "brew install dfu-util" or from MacPorts. +

+

+ Most Linux distributions ship dfu-util in binary packages for those + who do not want to compile dfu-util from source. + On Debian, Ubuntu, Fedora and Gentoo you can install it through the + normal software package tools. For other distributions +(namely OpenSuSe, Mandriva, and CentOS) Holger Freyther was kind enough to +provide binary packages through the Open Build Service. +

+

Development

+

+ Development happens in a GIT repository. Browse it via the web +interface or clone it with: +

+
+	git clone git://gitorious.org/dfu-util/dfu-util.git
+	
+

+ See our build instructions for how to + build the source on different platforms. +

+

License

+

+ This software is licensed under the GPL version 2. +

+

Contact

+

+ If you have questions about the development or use of dfu-util please + send an e-mail to our dedicated +mailing list for dfu-util. +

+

People

+

+ dfu-util was originally written by + Harald Welte partially based on code from + dfu-programmer 0.4 and is currently maintained by Stefan Schmidt and + Tormod Volden. +

+ +
+ + diff --git a/tools/src/dfu-util/www/simple.css b/tools/src/dfu-util/www/simple.css new file mode 100755 index 0000000..10b7c1d --- /dev/null +++ b/tools/src/dfu-util/www/simple.css @@ -0,0 +1,56 @@ +body { + margin: 10px; + font-size: 0.82em; + background-color: #EEE; +} + +h1 { + clear: both; + padding: 0 0 12px 0; + margin: 0; + font-size: 2em; + font-weight: bold; +} + +h2 { + clear: both; + margin: 0; + font-size: 1.5em; + font-weight: normal; +} + +h3 { + clear: both; + margin: 15px 0 0 0; + font-size: 1.0em; + font-weight: bold; +} + +p { + line-height: 20px; + padding: 8px 0 8px 0; + margin: 0; + font-size: 1.1em; +} + +pre { + white-space: pre-wrap; + background-color: #CCC; + padding: 3px; +} + +a:hover { + background-color: #DDD; +} + +#middlebox { + width: 600px; + margin: 0px auto; + text-align: left; +} + +#footer { + height: 100px; + padding: 28px 3px 0 0; + margin: 20px 0 20px 0; +} diff --git a/tools/src/maple_loader/README.md b/tools/src/maple_loader/README.md new file mode 100644 index 0000000..c6c9379 --- /dev/null +++ b/tools/src/maple_loader/README.md @@ -0,0 +1,5 @@ +These files build the maple_loader.jar file used on Windows to reset the Sketch via USB Serial, so that the bootloader will run in dfu upload mode, ready for a new sketch to be uploaded + +The files were written by @bobC (github) and have been slightly modified by me (Roger Clark), so that dfu-util no longer attempts to reset the board after upload. +This change to dfu-util's reset command line argument, was required because dfu-util was showing errors on some Windows systems, because the bootloader had reset its self after upload, +before dfu-util had chance to tell it to reset. \ No newline at end of file diff --git a/tools/src/maple_loader/build.xml b/tools/src/maple_loader/build.xml new file mode 100644 index 0000000..63ae9c2 --- /dev/null +++ b/tools/src/maple_loader/build.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + Builds, tests, and runs the project maple_loader. + + + diff --git a/tools/src/maple_loader/build/built-jar.properties b/tools/src/maple_loader/build/built-jar.properties new file mode 100644 index 0000000..94002ae --- /dev/null +++ b/tools/src/maple_loader/build/built-jar.properties @@ -0,0 +1,4 @@ +#Mon, 20 Jul 2015 11:21:26 +1000 + + +C\:\\Users\\rclark\\Desktop\\maple-asp-master\\installer\\maple_loader= diff --git a/tools/src/maple_loader/build/classes/CliTemplate/CliMain.class b/tools/src/maple_loader/build/classes/CliTemplate/CliMain.class new file mode 100644 index 0000000..37ee630 Binary files /dev/null and b/tools/src/maple_loader/build/classes/CliTemplate/CliMain.class differ diff --git a/tools/src/maple_loader/build/classes/CliTemplate/DFUUploader.class b/tools/src/maple_loader/build/classes/CliTemplate/DFUUploader.class new file mode 100644 index 0000000..77087b0 Binary files /dev/null and b/tools/src/maple_loader/build/classes/CliTemplate/DFUUploader.class differ diff --git a/tools/src/maple_loader/build/classes/CliTemplate/ExecCommand.class b/tools/src/maple_loader/build/classes/CliTemplate/ExecCommand.class new file mode 100644 index 0000000..ad95f79 Binary files /dev/null and b/tools/src/maple_loader/build/classes/CliTemplate/ExecCommand.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/Base.class b/tools/src/maple_loader/build/classes/processing/app/Base.class new file mode 100644 index 0000000..4aa0bde Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/Base.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/Preferences.class b/tools/src/maple_loader/build/classes/processing/app/Preferences.class new file mode 100644 index 0000000..89cf010 Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/Preferences.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/Serial.class b/tools/src/maple_loader/build/classes/processing/app/Serial.class new file mode 100644 index 0000000..cceccdd Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/Serial.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/SerialException.class b/tools/src/maple_loader/build/classes/processing/app/SerialException.class new file mode 100644 index 0000000..71048dd Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/SerialException.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class b/tools/src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class new file mode 100644 index 0000000..37250e7 Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/debug/MessageConsumer.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/debug/MessageSiphon.class b/tools/src/maple_loader/build/classes/processing/app/debug/MessageSiphon.class new file mode 100644 index 0000000..e22c8d4 Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/debug/MessageSiphon.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/debug/RunnerException.class b/tools/src/maple_loader/build/classes/processing/app/debug/RunnerException.class new file mode 100644 index 0000000..710f796 Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/debug/RunnerException.class differ diff --git a/tools/src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class b/tools/src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class new file mode 100644 index 0000000..27eca62 Binary files /dev/null and b/tools/src/maple_loader/build/classes/processing/app/helpers/ProcessUtils.class differ diff --git a/tools/src/maple_loader/dist/README.TXT b/tools/src/maple_loader/dist/README.TXT new file mode 100644 index 0000000..795e0cf --- /dev/null +++ b/tools/src/maple_loader/dist/README.TXT @@ -0,0 +1,32 @@ +======================== +BUILD OUTPUT DESCRIPTION +======================== + +When you build an Java application project that has a main class, the IDE +automatically copies all of the JAR +files on the projects classpath to your projects dist/lib folder. The IDE +also adds each of the JAR files to the Class-Path element in the application +JAR files manifest file (MANIFEST.MF). + +To run the project from the command line, go to the dist folder and +type the following: + +java -jar "maple_loader.jar" + +To distribute this project, zip up the dist folder (including the lib folder) +and distribute the ZIP file. + +Notes: + +* If two JAR files on the project classpath have the same name, only the first +JAR file is copied to the lib folder. +* Only JAR files are copied to the lib folder. +If the classpath contains other types of files or folders, these files (folders) +are not copied. +* If a library on the projects classpath also has a Class-Path element +specified in the manifest,the content of the Class-Path element has to be on +the projects runtime path. +* To set a main class in a standard Java project, right-click the project node +in the Projects window and choose Properties. Then click Run and enter the +class name in the Main Class field. Alternatively, you can manually type the +class name in the manifest Main-Class element. diff --git a/tools/src/maple_loader/dist/lib/jssc.jar b/tools/src/maple_loader/dist/lib/jssc.jar new file mode 100644 index 0000000..eb74f15 Binary files /dev/null and b/tools/src/maple_loader/dist/lib/jssc.jar differ diff --git a/tools/src/maple_loader/dist/maple_loader.jar b/tools/src/maple_loader/dist/maple_loader.jar new file mode 100644 index 0000000..e1f9965 Binary files /dev/null and b/tools/src/maple_loader/dist/maple_loader.jar differ diff --git a/tools/src/maple_loader/jars/jssc.jar b/tools/src/maple_loader/jars/jssc.jar new file mode 100644 index 0000000..eb74f15 Binary files /dev/null and b/tools/src/maple_loader/jars/jssc.jar differ diff --git a/tools/src/maple_loader/manifest.mf b/tools/src/maple_loader/manifest.mf new file mode 100644 index 0000000..328e8e5 --- /dev/null +++ b/tools/src/maple_loader/manifest.mf @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +X-COMMENT: Main-Class will be added automatically by build + diff --git a/tools/src/maple_loader/nbproject/build-impl.xml b/tools/src/maple_loader/nbproject/build-impl.xml new file mode 100644 index 0000000..080006a --- /dev/null +++ b/tools/src/maple_loader/nbproject/build-impl.xml @@ -0,0 +1,1413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + No tests executed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set JVM to use for profiling in profiler.info.jvm + Must set profiler agent JVM arguments in profiler.info.jvmargs.agent + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + Must select one file in the IDE or set profile.class + This target only works when run from inside the NetBeans IDE. + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + This target only works when run from inside the NetBeans IDE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + + + Must select some files in the IDE or set test.includes + + + + + Must select one file in the IDE or set run.class + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + Must select some files in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + Must select one file in the IDE or set test.class + Must select some method in the IDE or set test.method + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/src/maple_loader/nbproject/genfiles.properties b/tools/src/maple_loader/nbproject/genfiles.properties new file mode 100644 index 0000000..1007bfc --- /dev/null +++ b/tools/src/maple_loader/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=2e6a03ba +build.xml.script.CRC32=4676ee6b +build.xml.stylesheet.CRC32=8064a381@1.75.2.48 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=2e6a03ba +nbproject/build-impl.xml.script.CRC32=392b3f79 +nbproject/build-impl.xml.stylesheet.CRC32=876e7a8f@1.75.2.48 diff --git a/tools/src/maple_loader/nbproject/private/config.properties b/tools/src/maple_loader/nbproject/private/config.properties new file mode 100644 index 0000000..e69de29 diff --git a/tools/src/maple_loader/nbproject/private/private.properties b/tools/src/maple_loader/nbproject/private/private.properties new file mode 100644 index 0000000..ab05185 --- /dev/null +++ b/tools/src/maple_loader/nbproject/private/private.properties @@ -0,0 +1,6 @@ +compile.on.save=true +do.depend=false +do.jar=true +javac.debug=true +javadoc.preview=true +user.properties.file=C:\\Users\\rclark\\AppData\\Roaming\\NetBeans\\8.0.2\\build.properties diff --git a/tools/src/maple_loader/nbproject/private/private.xml b/tools/src/maple_loader/nbproject/private/private.xml new file mode 100644 index 0000000..9feb3fe --- /dev/null +++ b/tools/src/maple_loader/nbproject/private/private.xml @@ -0,0 +1,10 @@ + + + + + + file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/CliMain.java + file:/C:/Users/rclark/Desktop/maple-asp-master/installer/maple_loader/src/CliTemplate/DFUUploader.java + + + diff --git a/tools/src/maple_loader/nbproject/project.properties b/tools/src/maple_loader/nbproject/project.properties new file mode 100644 index 0000000..984cc6a --- /dev/null +++ b/tools/src/maple_loader/nbproject/project.properties @@ -0,0 +1,79 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.processors.list= +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=maple_loader +application.vendor=bob +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# Files in build.classes.dir which should be excluded from distribution jar +dist.archive.excludes= +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/maple_loader.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.jssc.jar=dist/lib/jssc.jar +file.reference.jssc.jar-1=jars/jssc.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.jssc.jar}:\ + ${file.reference.jssc.jar-1} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.7 +javac.target=1.7 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=CliTemplate.CliMain +manifest.file=manifest.mf +meta.inf.dir=${src.dir}/META-INF +mkdist.disabled=false +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project. +# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value. +# To set system properties for unit tests define test-sys-prop.name=value: +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/tools/src/maple_loader/nbproject/project.xml b/tools/src/maple_loader/nbproject/project.xml new file mode 100644 index 0000000..076fe22 --- /dev/null +++ b/tools/src/maple_loader/nbproject/project.xml @@ -0,0 +1,15 @@ + + + org.netbeans.modules.java.j2seproject + + + maple_loader + + + + + + + + + diff --git a/tools/src/maple_loader/src/CliTemplate/CliMain.java b/tools/src/maple_loader/src/CliTemplate/CliMain.java new file mode 100644 index 0000000..c7dc9f0 --- /dev/null +++ b/tools/src/maple_loader/src/CliTemplate/CliMain.java @@ -0,0 +1,60 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package CliTemplate; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import processing.app.Preferences; + +//import processing.app.I18n; +import processing.app.helpers.ProcessUtils; + +/** + * + * @author cousinr + */ +public class CliMain { + + + /** + * @param args the command line arguments + */ + public static void main(String[] args) { + + String comPort = args[0]; // + String altIf = args[1]; // + String usbID = args[2]; // "1EAF:0003"; + String binFile = args[3]; // bin file + + System.out.println("maple_loader v0.1"); + + Preferences.set ("serial.port",comPort); + Preferences.set ("serial.parity","N"); + Preferences.setInteger ("serial.databits", 8); + Preferences.setInteger ("serial.debug_rate",9600); + Preferences.setInteger ("serial.stopbits",1); + + Preferences.setInteger ("programDelay",1200); + + Preferences.set ("upload.usbID", usbID); + Preferences.set ("upload.altID", altIf); + Preferences.setBoolean ("upload.auto_reset", true); + Preferences.setBoolean ("upload.verbose", false); + + // + DFUUploader dfuUploader = new DFUUploader(); + try { + //dfuUploader.uploadViaDFU(binFile); + dfuUploader.uploadViaDFU(binFile); + } catch (Exception e) + { + System.err.print (MessageFormat.format("an error occurred! {0}\n", e.getMessage())); + } + } +} diff --git a/tools/src/maple_loader/src/CliTemplate/DFUUploader.java b/tools/src/maple_loader/src/CliTemplate/DFUUploader.java new file mode 100644 index 0000000..3dee0b4 --- /dev/null +++ b/tools/src/maple_loader/src/CliTemplate/DFUUploader.java @@ -0,0 +1,345 @@ +/* + DFUUploader - uploader implementation using DFU + + Copyright (c) 2010 + Andrew Meyer + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +package CliTemplate; + +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import processing.app.Preferences; +import processing.app.Serial; +import processing.app.debug.MessageConsumer; +import processing.app.debug.MessageSiphon; +import processing.app.debug.RunnerException; + +/** + * + * @author bob + */ +public class DFUUploader implements MessageConsumer { + + boolean firstErrorFound; + boolean secondErrorFound; + // part of the PdeMessageConsumer interface + boolean notFoundError; + boolean verbose; + RunnerException exception; + + static final String SUPER_BADNESS = + "Compiler error!"; + + public boolean uploadUsingPreferences(String binPath, boolean verbose) + throws RunnerException { + + this.verbose = verbose; + + return uploadViaDFU(binPath); + } + + // works with old and new versions of dfu-util + private boolean found_device (String dfuData, String usbID) + { + return dfuData.contains(("Found DFU: [0x"+usbID.substring(0,4)).toUpperCase()) || + dfuData.contains(("Found DFU: ["+usbID.substring(0,4)).toUpperCase()); + } + + public boolean uploadViaDFU (String binPath) + throws RunnerException { + + this.verbose = Preferences.getBoolean ("upload.verbose"); + + /* todo, check for size overruns! */ + String fileType="bin"; + + if (fileType.equals("bin")) { + String usbID = Preferences.get("upload.usbID"); + if (usbID == null) { + /* fall back on default */ + /* this isnt great because is default Avrdude or dfu-util? */ + usbID = Preferences.get("upload.usbID"); + } + + /* if auto-reset, then emit the reset pulse on dtr/rts */ + if (Preferences.get("upload.auto_reset") != null) { + if (Preferences.get("upload.auto_reset").toLowerCase().equals("true")) { + System.out.println("Resetting to bootloader via DTR pulse"); + emitResetPulse(); + } + } else { + System.out.println("Resetting to bootloader via DTR pulse"); + emitResetPulse(); + } + + String dfuList = new String(); + List commandCheck = new ArrayList(); + commandCheck.add("dfu-util"); + commandCheck.add("-l"); + long startChecking = System.currentTimeMillis(); + System.out.println("Searching for DFU device [" + usbID + "]..."); + do { + try { + Thread.sleep(100); + } catch (InterruptedException e) {} + dfuList = executeCheckCommand(commandCheck); + //System.out.println(dfuList); + } + while ( !found_device (dfuList.toUpperCase(), usbID) && (System.currentTimeMillis() - startChecking < 7000)); + + if ( !found_device (dfuList.toUpperCase(), usbID) ) + { + System.out.println(dfuList); + System.err.println("Couldn't find the DFU device: [" + usbID + "]"); + return false; + } + System.out.println("Found it!"); + + /* todo, add handle to let user choose altIf at upload time! */ + String altIf = Preferences.get("upload.altID"); + + List commandDownloader = new ArrayList(); + commandDownloader.add("dfu-util"); + commandDownloader.add("-a "+altIf); + commandDownloader.add("-R"); + commandDownloader.add("-d "+usbID); + commandDownloader.add("-D"+ binPath); //"./thisbin.bin"); + + return executeUploadCommand(commandDownloader); + } + + System.err.println("Only .bin files are supported at this time"); + return false; + } + + /* we need to ensure both RTS and DTR are low to start, + then pulse DTR on its own. This is the reset signal + maple responds to + */ + private void emitResetPulse() throws RunnerException { + + /* wait a while for the device to reboot */ + int programDelay = Preferences.getInteger("programDelay"); + + try { + Serial serialPort = new Serial(); + + // try to toggle DTR/RTS (old scheme) + serialPort.setRTS(false); + serialPort.setDTR(false); + serialPort.setDTR(true); + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + serialPort.setDTR(false); + + // try magic number + serialPort.setRTS(true); + serialPort.setDTR(true); + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + serialPort.setDTR(false); + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + serialPort.write("1EAF"); + try { + Thread.sleep(50); + } catch (InterruptedException e) {} + serialPort.dispose(); + + } catch(Exception e) { + System.err.println("Reset via USB Serial Failed! Did you select the right serial port?\nAssuming the board is in perpetual bootloader mode and continuing to attempt dfu programming...\n"); + } + } + + protected String executeCheckCommand(Collection commandDownloader) + throws RunnerException + { + firstErrorFound = false; // haven't found any errors yet + secondErrorFound = false; + notFoundError = false; + int result=0; // pre-initialized to quiet a bogus warning from jikes + + String userdir = System.getProperty("user.dir") + File.separator; + String returnStr = new String(); + + try { + String[] commandArray = new String[commandDownloader.size()]; + commandDownloader.toArray(commandArray); + + String armBasePath; + + //armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/"); + armBasePath = ""; + + commandArray[0] = armBasePath + commandArray[0]; + + if (verbose || Preferences.getBoolean("upload.verbose")) { + for(int i = 0; i < commandArray.length; i++) { + System.out.print(commandArray[i] + " "); + } + System.out.println(); + } + + Process process = Runtime.getRuntime().exec(commandArray); + BufferedReader stdInput = new BufferedReader(new + InputStreamReader(process.getInputStream())); + BufferedReader stdError = new BufferedReader(new + InputStreamReader(process.getErrorStream())); + + // wait for the process to finish. if interrupted + // before waitFor returns, continue waiting + // + boolean busy = true; + while (busy) { + try { + result = process.waitFor(); + busy = false; + } catch (InterruptedException intExc) { + } + } + + String s; + while ((s = stdInput.readLine()) != null) { + returnStr += s + "\n"; + } + + process.destroy(); + + if(exception!=null) { + exception.hideStackTrace(); + throw exception; + } + if(result!=0) return "Error!"; + } catch (Exception e) { + e.printStackTrace(); + } + //System.out.println("result2 is "+result); + // if the result isn't a known, expected value it means that something + // is fairly wrong, one possibility is that jikes has crashed. + // + if (exception != null) throw exception; + + if ((result != 0) && (result != 1 )) { + exception = new RunnerException(SUPER_BADNESS); + } + + return returnStr; // ? true : false; + + } + + // Need to overload this from Uploader to use the system-wide dfu-util + protected boolean executeUploadCommand(Collection commandDownloader) + throws RunnerException + { + firstErrorFound = false; // haven't found any errors yet + secondErrorFound = false; + notFoundError = false; + int result=0; // pre-initialized to quiet a bogus warning from jikes + + String userdir = System.getProperty("user.dir") + File.separator; + + try { + String[] commandArray = new String[commandDownloader.size()]; + commandDownloader.toArray(commandArray); + + String armBasePath; + + //armBasePath = new String(Base.getHardwarePath() + "/tools/arm/bin/"); + armBasePath = ""; + + commandArray[0] = armBasePath + commandArray[0]; + + if (verbose || Preferences.getBoolean("upload.verbose")) { + for(int i = 0; i < commandArray.length; i++) { + System.out.print(commandArray[i] + " "); + } + System.out.println(); + } + + Process process = Runtime.getRuntime().exec(commandArray); + new MessageSiphon(process.getInputStream(), this); + new MessageSiphon(process.getErrorStream(), this); + + // wait for the process to finish. if interrupted + // before waitFor returns, continue waiting + // + boolean compiling = true; + while (compiling) { + try { + result = process.waitFor(); + compiling = false; + } catch (InterruptedException intExc) { + } + } + if(exception!=null) { + exception.hideStackTrace(); + throw exception; + } + if(result!=0) + return false; + } catch (Exception e) { + e.printStackTrace(); + } + //System.out.println("result2 is "+result); + // if the result isn't a known, expected value it means that something + // is fairly wrong, one possibility is that jikes has crashed. + // + if (exception != null) throw exception; + + if ((result != 0) && (result != 1 )) { + exception = new RunnerException(SUPER_BADNESS); + //editor.error(exception); + //PdeBase.openURL(BUGS_URL); + //throw new PdeException(SUPER_BADNESS); + } + + return (result == 0); // ? true : false; + + } + + // deal with messages from dfu-util... + public void message(String s) { + + if(s.indexOf("dfu-util - (C) ") != -1) { return; } + if(s.indexOf("This program is Free Software and has ABSOLUTELY NO WARRANTY") != -1) { return; } + + if(s.indexOf("No DFU capable USB device found") != -1) { + System.err.print(s); + exception = new RunnerException("Problem uploading via dfu-util: No Maple found"); + return; + } + + if(s.indexOf("Operation not perimitted") != -1) { + System.err.print(s); + exception = new RunnerException("Problem uploading via dfu-util: Insufficient privilages"); + return; + } + + // else just print everything... + System.out.print(s); + } + +} diff --git a/tools/src/maple_loader/src/CliTemplate/ExecCommand.java b/tools/src/maple_loader/src/CliTemplate/ExecCommand.java new file mode 100644 index 0000000..3d6c106 --- /dev/null +++ b/tools/src/maple_loader/src/CliTemplate/ExecCommand.java @@ -0,0 +1,119 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package CliTemplate; + +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import processing.app.debug.MessageConsumer; +import processing.app.debug.MessageSiphon; +import processing.app.debug.RunnerException; +import processing.app.helpers.ProcessUtils; + +/** + * + * @author cousinr + */ +public class ExecCommand implements MessageConsumer { + + private boolean verbose = true; + private boolean firstErrorFound; + private boolean secondErrorFound; + private RunnerException exception; + + /** + * Either succeeds or throws a RunnerException fit for public consumption. + * + * @param command + * @throws RunnerException + */ + public void execAsynchronously(String[] command) throws RunnerException { + + // eliminate any empty array entries + List stringList = new ArrayList<>(); + for (String string : command) { + string = string.trim(); + if (string.length() != 0) + stringList.add(string); + } + command = stringList.toArray(new String[stringList.size()]); + if (command.length == 0) + return; + int result = 0; + + if (verbose) { + for (String c : command) + System.out.print(c + " "); + System.out.println(); + } + + firstErrorFound = false; // haven't found any errors yet + secondErrorFound = false; + + Process process; + try { + process = ProcessUtils.exec(command); + } catch (IOException e) { + RunnerException re = new RunnerException(e.getMessage()); + re.hideStackTrace(); + throw re; + } + + MessageSiphon in = new MessageSiphon(process.getInputStream(), this); + MessageSiphon err = new MessageSiphon(process.getErrorStream(), this); + + // wait for the process to finish. if interrupted + // before waitFor returns, continue waiting + boolean compiling = true; + while (compiling) { + try { + in.join(); + err.join(); + result = process.waitFor(); + //System.out.println("result is " + result); + compiling = false; + } catch (InterruptedException ignored) { } + } + + // an error was queued up by message(), barf this back to compile(), + // which will barf it back to Editor. if you're having trouble + // discerning the imagery, consider how cows regurgitate their food + // to digest it, and the fact that they have five stomaches. + // + //System.out.println("throwing up " + exception); + if (exception != null) + throw exception; + + if (result > 1) { + // a failure in the tool (e.g. unable to locate a sub-executable) + System.err.println(MessageFormat.format("{0} returned {1}", command[0], result)); + } + + if (result != 0) { + RunnerException re = new RunnerException(MessageFormat.format("exit code: {0}", result)); + re.hideStackTrace(); + throw re; + } + } + + /** + * Part of the MessageConsumer interface, this is called + * whenever a piece (usually a line) of error message is spewed + * out from the compiler. The errors are parsed for their contents + * and line number, which is then reported back to Editor. + * @param s + */ + @Override + public void message(String s) { + int i; + + + System.err.print(s); + } + +} diff --git a/tools/src/maple_loader/src/processing/app/Base.java b/tools/src/maple_loader/src/processing/app/Base.java new file mode 100644 index 0000000..c3a174d --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/Base.java @@ -0,0 +1,53 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-10 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app; + + +/** + * The base class for the main processing application. + * Primary role of this class is for platform identification and + * general interaction with the system (launching URLs, loading + * files and images, etc) that comes from that. + */ +public class Base { + + /** + * returns true if running on windows. + */ + static public boolean isWindows() { + //return PApplet.platform == PConstants.WINDOWS; + return System.getProperty("os.name").indexOf("Windows") != -1; + } + + + /** + * true if running on linux. + */ + static public boolean isLinux() { + //return PApplet.platform == PConstants.LINUX; + return System.getProperty("os.name").indexOf("Linux") != -1; + } + + + +} diff --git a/tools/src/maple_loader/src/processing/app/Preferences.java b/tools/src/maple_loader/src/processing/app/Preferences.java new file mode 100644 index 0000000..6368e38 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/Preferences.java @@ -0,0 +1,157 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-09 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app; + +import java.io.*; +import java.util.*; + + +/** + * Storage class for user preferences and environment settings. + *

+ * This class no longer uses the Properties class, since + * properties files are iso8859-1, which is highly likely to + * be a problem when trying to save sketch folders and locations. + *

+ * The GUI portion in here is really ugly, as it uses exact layout. This was + * done in frustration one evening (and pre-Swing), but that's long since past, + * and it should all be moved to a proper swing layout like BoxLayout. + *

+ * This is very poorly put together, that the preferences panel and the actual + * preferences i/o is part of the same code. But there hasn't yet been a + * compelling reason to bother with the separation aside from concern about + * being lectured by strangers who feel that it doesn't look like what they + * learned in CS class. + *

+ * Would also be possible to change this to use the Java Preferences API. + * Some useful articles + * here and + * here. + * However, haven't implemented this yet for lack of time, but more + * importantly, because it would entail writing to the registry (on Windows), + * or an obscure file location (on Mac OS X) and make it far more difficult to + * find the preferences to tweak them by hand (no! stay out of regedit!) + * or to reset the preferences by simply deleting the preferences.txt file. + */ +public class Preferences { + + // what to call the feller + + static final String PREFS_FILE = "preferences.txt"; + + + // prompt text stuff + + static final String PROMPT_YES = "Yes"; + static final String PROMPT_NO = "No"; + static final String PROMPT_CANCEL = "Cancel"; + static final String PROMPT_OK = "OK"; + static final String PROMPT_BROWSE = "Browse"; + + /** + * Standardized width for buttons. Mac OS X 10.3 wants 70 as its default, + * Windows XP needs 66, and my Ubuntu machine needs 80+, so 80 seems proper. + */ + static public int BUTTON_WIDTH = 80; + + /** + * Standardized button height. Mac OS X 10.3 (Java 1.4) wants 29, + * presumably because it now includes the blue border, where it didn't + * in Java 1.3. Windows XP only wants 23 (not sure what default Linux + * would be). Because of the disparity, on Mac OS X, it will be set + * inside a static block. + */ + static public int BUTTON_HEIGHT = 24; + + // value for the size bars, buttons, etc + + static final int GRID_SIZE = 33; + + + // indents and spacing standards. these probably need to be modified + // per platform as well, since macosx is so huge, windows is smaller, + // and linux is all over the map + + static final int GUI_BIG = 13; + static final int GUI_BETWEEN = 10; + static final int GUI_SMALL = 6; + + + + // data model + + static Hashtable table = new Hashtable();; + static File preferencesFile; + + + static protected void init(String commandLinePrefs) { + + + } + + + public Preferences() { + + } + + // ................................................................. + + // ................................................................. + + // ................................................................. + + // ................................................................. + + + + static public String get(String attribute) { + return (String) table.get(attribute); + } + + static public void set(String attribute, String value) { + table.put(attribute, value); + } + + + static public boolean getBoolean(String attribute) { + String value = get(attribute); + return (new Boolean(value)).booleanValue(); + } + + + static public void setBoolean(String attribute, boolean value) { + set(attribute, value ? "true" : "false"); + } + + + static public int getInteger(String attribute) { + return Integer.parseInt(get(attribute)); + } + + + static public void setInteger(String key, int value) { + set(key, String.valueOf(value)); + } + +} diff --git a/tools/src/maple_loader/src/processing/app/Serial.java b/tools/src/maple_loader/src/processing/app/Serial.java new file mode 100644 index 0000000..04566a7 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/Serial.java @@ -0,0 +1,527 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + PSerial - class for serial port goodness + Part of the Processing project - http://processing.org + + Copyright (c) 2004 Ben Fry & Casey Reas + + 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 +*/ + +package processing.app; +//import processing.core.*; + + +import java.io.*; +import java.text.MessageFormat; +import java.util.*; +import jssc.SerialPort; +import jssc.SerialPortEvent; +import jssc.SerialPortEventListener; +import jssc.SerialPortException; +import jssc.SerialPortList; +import processing.app.debug.MessageConsumer; + + +public class Serial implements SerialPortEventListener { + + //PApplet parent; + + // properties can be passed in for default values + // otherwise defaults to 9600 N81 + + // these could be made static, which might be a solution + // for the classloading problem.. because if code ran again, + // the static class would have an object that could be closed + + SerialPort port; + + int rate; + int parity; + int databits; + int stopbits; + boolean monitor = false; + + // read buffer and streams + + InputStream input; + OutputStream output; + + byte buffer[] = new byte[32768]; + int bufferIndex; + int bufferLast; + + MessageConsumer consumer; + + public Serial(boolean monitor) throws SerialException { + this(Preferences.get("serial.port"), + Preferences.getInteger("serial.debug_rate"), + Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), + new Float(Preferences.get("serial.stopbits")).floatValue()); + this.monitor = monitor; + } + + public Serial() throws SerialException { + this(Preferences.get("serial.port"), + Preferences.getInteger("serial.debug_rate"), + Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), + new Float(Preferences.get("serial.stopbits")).floatValue()); + } + + public Serial(int irate) throws SerialException { + this(Preferences.get("serial.port"), irate, + Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), + new Float(Preferences.get("serial.stopbits")).floatValue()); + } + + public Serial(String iname, int irate) throws SerialException { + this(iname, irate, Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), + new Float(Preferences.get("serial.stopbits")).floatValue()); + } + + public Serial(String iname) throws SerialException { + this(iname, Preferences.getInteger("serial.debug_rate"), + Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), + new Float(Preferences.get("serial.stopbits")).floatValue()); + } + + public Serial(String iname, int irate, + char iparity, int idatabits, float istopbits) + throws SerialException { + //if (port != null) port.close(); + //this.parent = parent; + //parent.attach(this); + + this.rate = irate; + + parity = SerialPort.PARITY_NONE; + if (iparity == 'E') parity = SerialPort.PARITY_EVEN; + if (iparity == 'O') parity = SerialPort.PARITY_ODD; + + this.databits = idatabits; + + stopbits = SerialPort.STOPBITS_1; + if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5; + if (istopbits == 2) stopbits = SerialPort.STOPBITS_2; + + try { + port = new SerialPort(iname); + port.openPort(); + port.setParams(rate, databits, stopbits, parity, true, true); + port.addEventListener(this); + } catch (Exception e) { + throw new SerialException(MessageFormat.format("Error opening serial port ''{0}''.", iname), e); + } + + if (port == null) { + throw new SerialException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?"); + } + } + + + public void setup() { + //parent.registerCall(this, DISPOSE); + } + + public void dispose() throws IOException { + if (port != null) { + try { + if (port.isOpened()) { + port.closePort(); // close the port + } + } catch (SerialPortException e) { + throw new IOException(e); + } finally { + port = null; + } + } + } + + public void addListener(MessageConsumer consumer) { + this.consumer = consumer; + } + + public synchronized void serialEvent(SerialPortEvent serialEvent) { + if (serialEvent.isRXCHAR()) { + try { + byte[] buf = port.readBytes(serialEvent.getEventValue()); + if (buf.length > 0) { + if (bufferLast == buffer.length) { + byte temp[] = new byte[bufferLast << 1]; + System.arraycopy(buffer, 0, temp, 0, bufferLast); + buffer = temp; + } + if (monitor) { + System.out.print(new String(buf)); + } + if (this.consumer != null) { + this.consumer.message(new String(buf)); + } + } + } catch (SerialPortException e) { + errorMessage("serialEvent", e); + } + } + } + + + /** + * Returns the number of bytes that have been read from serial + * and are waiting to be dealt with by the user. + */ + public synchronized int available() { + return (bufferLast - bufferIndex); + } + + + /** + * Ignore all the bytes read so far and empty the buffer. + */ + public synchronized void clear() { + bufferLast = 0; + bufferIndex = 0; + } + + + /** + * Returns a number between 0 and 255 for the next byte that's + * waiting in the buffer. + * Returns -1 if there was no byte (although the user should + * first check available() to see if things are ready to avoid this) + */ + public synchronized int read() { + if (bufferIndex == bufferLast) return -1; + + int outgoing = buffer[bufferIndex++] & 0xff; + if (bufferIndex == bufferLast) { // rewind + bufferIndex = 0; + bufferLast = 0; + } + return outgoing; + } + + + /** + * Returns the next byte in the buffer as a char. + * Returns -1, or 0xffff, if nothing is there. + */ + public synchronized char readChar() { + if (bufferIndex == bufferLast) return (char)(-1); + return (char) read(); + } + + + /** + * Return a byte array of anything that's in the serial buffer. + * Not particularly memory/speed efficient, because it creates + * a byte array on each read, but it's easier to use than + * readBytes(byte b[]) (see below). + */ + public synchronized byte[] readBytes() { + if (bufferIndex == bufferLast) return null; + + int length = bufferLast - bufferIndex; + byte outgoing[] = new byte[length]; + System.arraycopy(buffer, bufferIndex, outgoing, 0, length); + + bufferIndex = 0; // rewind + bufferLast = 0; + return outgoing; + } + + + /** + * Grab whatever is in the serial buffer, and stuff it into a + * byte buffer passed in by the user. This is more memory/time + * efficient than readBytes() returning a byte[] array. + *

+ * Returns an int for how many bytes were read. If more bytes + * are available than can fit into the byte array, only those + * that will fit are read. + */ + public synchronized int readBytes(byte outgoing[]) { + if (bufferIndex == bufferLast) return 0; + + int length = bufferLast - bufferIndex; + if (length > outgoing.length) length = outgoing.length; + System.arraycopy(buffer, bufferIndex, outgoing, 0, length); + + bufferIndex += length; + if (bufferIndex == bufferLast) { + bufferIndex = 0; // rewind + bufferLast = 0; + } + return length; + } + + + /** + * Reads from the serial port into a buffer of bytes up to and + * including a particular character. If the character isn't in + * the serial buffer, then 'null' is returned. + */ + public synchronized byte[] readBytesUntil(int interesting) { + if (bufferIndex == bufferLast) return null; + byte what = (byte)interesting; + + int found = -1; + for (int k = bufferIndex; k < bufferLast; k++) { + if (buffer[k] == what) { + found = k; + break; + } + } + if (found == -1) return null; + + int length = found - bufferIndex + 1; + byte outgoing[] = new byte[length]; + System.arraycopy(buffer, bufferIndex, outgoing, 0, length); + + bufferIndex = 0; // rewind + bufferLast = 0; + return outgoing; + } + + + /** + * Reads from the serial port into a buffer of bytes until a + * particular character. If the character isn't in the serial + * buffer, then 'null' is returned. + *

+ * If outgoing[] is not big enough, then -1 is returned, + * and an error message is printed on the console. + * If nothing is in the buffer, zero is returned. + * If 'interesting' byte is not in the buffer, then 0 is returned. + */ + public synchronized int readBytesUntil(int interesting, byte outgoing[]) { + if (bufferIndex == bufferLast) return 0; + byte what = (byte)interesting; + + int found = -1; + for (int k = bufferIndex; k < bufferLast; k++) { + if (buffer[k] == what) { + found = k; + break; + } + } + if (found == -1) return 0; + + int length = found - bufferIndex + 1; + if (length > outgoing.length) { + System.err.println("readBytesUntil() byte buffer is" + + " too small for the " + length + + " bytes up to and including char " + interesting); + return -1; + } + //byte outgoing[] = new byte[length]; + System.arraycopy(buffer, bufferIndex, outgoing, 0, length); + + bufferIndex += length; + if (bufferIndex == bufferLast) { + bufferIndex = 0; // rewind + bufferLast = 0; + } + return length; + } + + + /** + * Return whatever has been read from the serial port so far + * as a String. It assumes that the incoming characters are ASCII. + *

+ * If you want to move Unicode data, you can first convert the + * String to a byte stream in the representation of your choice + * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. + */ + public synchronized String readString() { + if (bufferIndex == bufferLast) return null; + return new String(readBytes()); + } + + + /** + * Combination of readBytesUntil and readString. See caveats in + * each function. Returns null if it still hasn't found what + * you're looking for. + *

+ * If you want to move Unicode data, you can first convert the + * String to a byte stream in the representation of your choice + * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. + */ + public synchronized String readStringUntil(int interesting) { + byte b[] = readBytesUntil(interesting); + if (b == null) return null; + return new String(b); + } + + + /** + * This will handle both ints, bytes and chars transparently. + */ + public void write(int what) { // will also cover char + try { + port.writeInt(what & 0xff); + } catch (SerialPortException e) { + errorMessage("write", e); + } + } + + + public void write(byte bytes[]) { + try { + port.writeBytes(bytes); + } catch (SerialPortException e) { + errorMessage("write", e); + } + } + + + /** + * Write a String to the output. Note that this doesn't account + * for Unicode (two bytes per char), nor will it send UTF8 + * characters.. It assumes that you mean to send a byte buffer + * (most often the case for networking and serial i/o) and + * will only use the bottom 8 bits of each char in the string. + * (Meaning that internally it uses String.getBytes) + *

+ * If you want to move Unicode data, you can first convert the + * String to a byte stream in the representation of your choice + * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. + */ + public void write(String what) { + write(what.getBytes()); + } + + public void setDTR(boolean state) { + try { + port.setDTR(state); + } catch (SerialPortException e) { + errorMessage("setDTR", e); + } + } + + public void setRTS(boolean state) { + try { + port.setRTS(state); + } catch (SerialPortException e) { + errorMessage("setRTS", e); + } + } + + static public List list() { + return Arrays.asList(SerialPortList.getPortNames()); + } + + + /** + * General error reporting, all corraled here just in case + * I think of something slightly more intelligent to do. + */ + static public void errorMessage(String where, Throwable e) { + System.err.println("Error inside Serial." + where + "()"); + e.printStackTrace(); + } +} + + + /* + class SerialMenuListener implements ItemListener { + //public SerialMenuListener() { } + + public void itemStateChanged(ItemEvent e) { + int count = serialMenu.getItemCount(); + for (int i = 0; i < count; i++) { + ((CheckboxMenuItem)serialMenu.getItem(i)).setState(false); + } + CheckboxMenuItem item = (CheckboxMenuItem)e.getSource(); + item.setState(true); + String name = item.getLabel(); + //System.out.println(item.getLabel()); + PdeBase.properties.put("serial.port", name); + //System.out.println("set to " + get("serial.port")); + } + } + */ + + + /* + protected Vector buildPortList() { + // get list of names for serial ports + // have the default port checked (if present) + Vector list = new Vector(); + + //SerialMenuListener listener = new SerialMenuListener(); + boolean problem = false; + + // if this is failing, it may be because + // lib/javax.comm.properties is missing. + // java is weird about how it searches for java.comm.properties + // so it tends to be very fragile. i.e. quotes in the CLASSPATH + // environment variable will hose things. + try { + //System.out.println("building port list"); + Enumeration portList = CommPortIdentifier.getPortIdentifiers(); + while (portList.hasMoreElements()) { + CommPortIdentifier portId = + (CommPortIdentifier) portList.nextElement(); + //System.out.println(portId); + + if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { + //if (portId.getName().equals(port)) { + String name = portId.getName(); + //CheckboxMenuItem mi = + //new CheckboxMenuItem(name, name.equals(defaultName)); + + //mi.addItemListener(listener); + //serialMenu.add(mi); + list.addElement(name); + } + } + } catch (UnsatisfiedLinkError e) { + e.printStackTrace(); + problem = true; + + } catch (Exception e) { + System.out.println("exception building serial menu"); + e.printStackTrace(); + } + + //if (serialMenu.getItemCount() == 0) { + //System.out.println("dimming serial menu"); + //serialMenu.setEnabled(false); + //} + + // only warn them if this is the first time + if (problem && PdeBase.firstTime) { + JOptionPane.showMessageDialog(this, //frame, + "Serial port support not installed.\n" + + "Check the readme for instructions\n" + + "if you need to use the serial port. ", + "Serial Port Warning", + JOptionPane.WARNING_MESSAGE); + } + return list; + } + */ + + + diff --git a/tools/src/maple_loader/src/processing/app/SerialException.java b/tools/src/maple_loader/src/processing/app/SerialException.java new file mode 100644 index 0000000..525c240 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/SerialException.java @@ -0,0 +1,39 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Copyright (c) 2007 David A. Mellis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app; + +public class SerialException extends Exception { + public SerialException() { + super(); + } + + public SerialException(String message) { + super(message); + } + + public SerialException(String message, Throwable cause) { + super(message, cause); + } + + public SerialException(Throwable cause) { + super(cause); + } +} diff --git a/tools/src/maple_loader/src/processing/app/debug/MessageConsumer.java b/tools/src/maple_loader/src/processing/app/debug/MessageConsumer.java new file mode 100644 index 0000000..5e20429 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/debug/MessageConsumer.java @@ -0,0 +1,42 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-06 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app.debug; + + +/** + * Interface for dealing with parser/compiler output. + *

+ * Different instances of MessageStream need to do different things with + * messages. In particular, a stream instance used for parsing output from + * the compiler compiler has to interpret its messages differently than one + * parsing output from the runtime. + *

+ * Classes which consume messages and do something with them + * should implement this interface. + */ +public interface MessageConsumer { + + public void message(String s); + +} diff --git a/tools/src/maple_loader/src/processing/app/debug/MessageSiphon.java b/tools/src/maple_loader/src/processing/app/debug/MessageSiphon.java new file mode 100644 index 0000000..26901c3 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/debug/MessageSiphon.java @@ -0,0 +1,104 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-06 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app.debug; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.SocketException; + +/** + * Slurps up messages from compiler. + */ +public class MessageSiphon implements Runnable { + + private final BufferedReader streamReader; + private final MessageConsumer consumer; + + private Thread thread; + private boolean canRun; + + public MessageSiphon(InputStream stream, MessageConsumer consumer) { + this.streamReader = new BufferedReader(new InputStreamReader(stream)); + this.consumer = consumer; + this.canRun = true; + + thread = new Thread(this); + // don't set priority too low, otherwise exceptions won't + // bubble up in time (i.e. compile errors have a weird delay) + //thread.setPriority(Thread.MIN_PRIORITY); + thread.setPriority(Thread.MAX_PRIORITY - 1); + thread.start(); + } + + + public void run() { + try { + // process data until we hit EOF; this will happily block + // (effectively sleeping the thread) until new data comes in. + // when the program is finally done, null will come through. + // + String currentLine; + while (canRun && (currentLine = streamReader.readLine()) != null) { + // \n is added again because readLine() strips it out + //EditorConsole.systemOut.println("messaging in"); + consumer.message(currentLine + "\n"); + //EditorConsole.systemOut.println("messaging out"); + } + //EditorConsole.systemOut.println("messaging thread done"); + } catch (NullPointerException npe) { + // Fairly common exception during shutdown + } catch (SocketException e) { + // socket has been close while we were wainting for data. nothing to see here, move along + } catch (Exception e) { + // On Linux and sometimes on Mac OS X, a "bad file descriptor" + // message comes up when closing an applet that's run externally. + // That message just gets supressed here.. + String mess = e.getMessage(); + if ((mess != null) && + (mess.indexOf("Bad file descriptor") != -1)) { + //if (e.getMessage().indexOf("Bad file descriptor") == -1) { + //System.err.println("MessageSiphon err " + e); + //e.printStackTrace(); + } else { + e.printStackTrace(); + } + } finally { + thread = null; + } + } + + // Wait until the MessageSiphon thread is complete. + public void join() throws java.lang.InterruptedException { + // Grab a temp copy in case another thread nulls the "thread" + // member variable + Thread t = thread; + if (t != null) t.join(); + } + + public void stop() { + this.canRun = false; + } + +} diff --git a/tools/src/maple_loader/src/processing/app/debug/RunnerException.java b/tools/src/maple_loader/src/processing/app/debug/RunnerException.java new file mode 100644 index 0000000..0a67d1e --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/debug/RunnerException.java @@ -0,0 +1,161 @@ +/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Processing project - http://processing.org + + Copyright (c) 2004-08 Ben Fry and Casey Reas + Copyright (c) 2001-04 Massachusetts Institute of Technology + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +package processing.app.debug; + + +/** + * An exception with a line number attached that occurs + * during either compile time or run time. + */ +@SuppressWarnings("serial") +public class RunnerException extends Exception { + protected String message; + protected int codeIndex; + protected int codeLine; + protected int codeColumn; + protected boolean showStackTrace; + + + public RunnerException(String message) { + this(message, true); + } + + public RunnerException(String message, boolean showStackTrace) { + this(message, -1, -1, -1, showStackTrace); + } + + public RunnerException(String message, int file, int line) { + this(message, file, line, -1, true); + } + + + public RunnerException(String message, int file, int line, int column) { + this(message, file, line, column, true); + } + + + public RunnerException(String message, int file, int line, int column, + boolean showStackTrace) { + this.message = message; + this.codeIndex = file; + this.codeLine = line; + this.codeColumn = column; + this.showStackTrace = showStackTrace; + } + + + public RunnerException(Exception e) { + super(e); + this.showStackTrace = true; + } + + /** + * Override getMessage() in Throwable, so that I can set + * the message text outside the constructor. + */ + public String getMessage() { + return message; + } + + + public void setMessage(String message) { + this.message = message; + } + + + public int getCodeIndex() { + return codeIndex; + } + + + public void setCodeIndex(int index) { + codeIndex = index; + } + + + public boolean hasCodeIndex() { + return codeIndex != -1; + } + + + public int getCodeLine() { + return codeLine; + } + + + public void setCodeLine(int line) { + this.codeLine = line; + } + + + public boolean hasCodeLine() { + return codeLine != -1; + } + + + public void setCodeColumn(int column) { + this.codeColumn = column; + } + + + public int getCodeColumn() { + return codeColumn; + } + + + public void showStackTrace() { + showStackTrace = true; + } + + + public void hideStackTrace() { + showStackTrace = false; + } + + + /** + * Nix the java.lang crap out of an exception message + * because it scares the children. + *

+ * This function must be static to be used with super() + * in each of the constructors above. + */ + /* + static public final String massage(String msg) { + if (msg.indexOf("java.lang.") == 0) { + //int dot = msg.lastIndexOf('.'); + msg = msg.substring("java.lang.".length()); + } + return msg; + //return (dot == -1) ? msg : msg.substring(dot+1); + } + */ + + + public void printStackTrace() { + if (showStackTrace) { + super.printStackTrace(); + } + } +} diff --git a/tools/src/maple_loader/src/processing/app/helpers/ProcessUtils.java b/tools/src/maple_loader/src/processing/app/helpers/ProcessUtils.java new file mode 100644 index 0000000..c023f58 --- /dev/null +++ b/tools/src/maple_loader/src/processing/app/helpers/ProcessUtils.java @@ -0,0 +1,32 @@ +package processing.app.helpers; + +//import processing.app.Base; + +import java.io.IOException; +import java.util.Map; + +import processing.app.Base; + +public class ProcessUtils { + + public static Process exec(String[] command) throws IOException { + // No problems on linux and mac + if (!Base.isWindows()) { + return Runtime.getRuntime().exec(command); + } + + // Brutal hack to workaround windows command line parsing. + // http://stackoverflow.com/questions/5969724/java-runtime-exec-fails-to-escape-characters-properly + // http://msdn.microsoft.com/en-us/library/a1y7w461.aspx + // http://bugs.sun.com/view_bug.do?bug_id=6468220 + // http://bugs.sun.com/view_bug.do?bug_id=6518827 + String[] cmdLine = new String[command.length]; + for (int i = 0; i < command.length; i++) + cmdLine[i] = command[i].replace("\"", "\\\""); + + ProcessBuilder pb = new ProcessBuilder(cmdLine); + Map env = pb.environment(); + env.put("CYGWIN", "nodosfilewarning"); + return pb.start(); + } +} diff --git a/tools/src/stm32flash_serial/src/main.c b/tools/src/stm32flash_serial/src/main.c index 5105d21..f081d61 100644 --- a/tools/src/stm32flash_serial/src/main.c +++ b/tools/src/stm32flash_serial/src/main.c @@ -38,7 +38,7 @@ #include "parsers/binary.h" #include "parsers/hex.h" -#define VERSION "0.4" +#define VERSION "Arduino_STM32_0.9" /* device globals */ stm32_t *stm = NULL; @@ -121,7 +121,7 @@ int main(int argc, char* argv[]) { FILE *diag = stdout; fprintf(diag, "stm32flash " VERSION "\n\n"); - fprintf(diag, "http://stm32flash.googlecode.com/\n\n"); + fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); if (parse_options(argc, argv) != 0) goto close; diff --git a/tools/src/stm32flash_serial/src/parsers/parsers.a b/tools/src/stm32flash_serial/src/parsers/parsers.a deleted file mode 100644 index ac1b715..0000000 Binary files a/tools/src/stm32flash_serial/src/parsers/parsers.a and /dev/null differ diff --git a/tools/src/stm32flash_serial/src/serial_posix.c b/tools/src/stm32flash_serial/src/serial_posix.c index 30b5ff8..7013436 100644 --- a/tools/src/stm32flash_serial/src/serial_posix.c +++ b/tools/src/stm32flash_serial/src/serial_posix.c @@ -198,18 +198,34 @@ static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, return PORT_ERR_OK; } +/* + * Roger clark. + * This function is no longer used. But has just been commented out in case it needs + * to be reinstated in the future + static int startswith(const char *haystack, const char *needle) { return strncmp(haystack, needle, strlen(needle)) == 0; } +*/ static int is_tty(const char *path) { char resolved[PATH_MAX]; if(!realpath(path, resolved)) return 0; + + /* + * Roger Clark + * Commented out this check, because on OSX some devices are /dev/cu + * and some users use symbolic links to devices, hence the name may not even start + * with /dev + if(startswith(resolved, "/dev/tty")) return 1; - + return 0; + */ + + return 1; } static port_err_t serial_posix_open(struct port_interface *port,