Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Martin Ayotte 2015-06-12 15:48:33 -04:00
commit 517e7fbde1
113 changed files with 6857 additions and 8185 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[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

5
LICENSE Normal file
View File

@ -0,0 +1,5 @@
This project is built of many different components.
Substantial portions were derived from leaflabs libmaple - see https://github.com/leaflabs/libmaple/blob/master/LICENSE
Other sub projects e.g. Texane STlink have their own licenses

View File

@ -1,12 +1,46 @@
Arduino STM32
=============
Arduino STM32
=============
This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.5.x to the latest version (currently 1.6.3) including LeafLabs Maple, and Maple mini, and other generic STM32F103 boards
##Notice
Please read the wiki https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki for full details
This software is experimental and a work in progress.
Under no circumstances should these files be used in relation to any critical system(s).
Use of these files is at your own risk.
Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs
See also my blog
##Summary:
This repo contains, the "Hardware" files to support STM32 based boards on Arduino version 1.5.x to the latest version (currently 1.6.3) including [LeafLabs Maple, and Maple mini](http://www.leaflabs.com/about-maple/), and other generic STM32F103 boards
***PRIMARY SUPPORT FORUM: http://www.stm32duino.com/***
##Background & Support:
* Based on https://github.com/bobc/maple-asp, which is in turn based on LibMaple by Leaflabs
* **Please read the wiki (https://github.com/rogerclarkmelbourne/Arduino_STM32/wiki) for full details**
* See also my blog: http://www.rogerclark.net/stm32f103-and-maple-maple-mini-with-arduino-1-5-x-ide/
* **NEW: Main support site for using STM32 boards with the Arduino IDE: http://www.stm32duino.com/**
* LeafLabs "Maple Language Reference:" http://leaflabs.com/docs/language.html
* LeafLabs "Maple-Arduino Compatibility:" http://leaflabs.com/docs/arduino-compatibility.html
**YouTube Videos:**
* 20141116: [Arduino 1.5.8 IDE with STM32 board](https://www.youtube.com/watch?v=-zwGnytGT8M)
* 20150413: [STM32 for Arduino 1.6.2 or newer (update)](https://www.youtube.com/watch?v=TePglhSkghg)
* 20150419: [Uploading via USB to Serial to STM32F103 boards](https://www.youtube.com/watch?v=G_RF0a0hrak)
##Additional Links & Info:
* https://www.hackster.io/rayburne/4-dollar-90-mips-32-bit-72-mhz-arm-arduino
##Purchase info:
###Entry level boards
* [Ebay search for "arduino maple"](http://www.ebay.com/sch/i.html?_from=R40&_sacat=0&LH_BIN=1&_nkw=arduino+maple&_sop=15) (currently costs <$5 with shipping)
* [AliExpress search for "leaflabs maple"] (http://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20150607085526&SearchText=leaflabs+maple)
### Bigger boards (You need to load the stm32duino bootloader)
Some supplier have this board e.g.
*[ STM32F103VET ](http://www.ebay.com.au/itm/1PCS-STM32F103VET6-ARM-STM32-Minimum-System-Development-Board-Arduino-M77-/301433302819)
*[There is also a STM32F103ZET board which also works, however they are not always available. They have been listed as "STM32F103ZET6 Minimum System Development Board ARM STM32 Cortex-m3 M75"]
(http://www.ebay.com.au/itm/1pcs-STM32F103ZET6-Minimum-System-Development-Board-ARM-STM32-Cortex-m3-M75-/291305557264)
More information is available at http://www.rogerclark.net/stm32f103-and-maple-maple-mini-with-arduino-1-5-x-ide/

View File

@ -6,35 +6,35 @@ menu.bootloader_version=Bootloader version
menu.upload_method=Upload method
##############################################################
maple_mini.name=LeafLabs Maple Mini Rev 2 to Flash
mapleMini.name=LeafLabs Maple Mini Rev 2 to Flash
maple_mini.build.board=MAPLE_MINI
maple_mini.build.core=maple
maple_mini.build.cpu_flags=-DMCU_STM32F103CB -DSERIAL_USB
maple_mini.build.variant=maple_mini
maple_mini.upload.usbID=1EAF:0003
mapleMini.build.board=MAPLE_MINI
mapleMini.build.core=maple
mapleMini.build.cpu_flags=-DMCU_STM32F103CB -DSERIAL_USB
mapleMini.build.variant=maple_mini
mapleMini.upload.usbID=1EAF:0003
maple_mini.upload.tool=maple_upload
maple_mini.upload.protocol=maple_dfu
maple_mini.upload.use_1200bps_touch=false
maple_mini.upload.file_type=bin
maple_mini.upload.auto_reset=true
mapleMini.upload.tool=maple_upload
mapleMini.upload.protocol=maple_dfu
mapleMini.upload.use_1200bps_touch=false
mapleMini.upload.file_type=bin
mapleMini.upload.auto_reset=true
maple_mini.menu.bootloader_version.original = Original (17k RAM,108k Flash)
maple_mini.menu.bootloader_version.original.build.vect=VECT_TAB_ADDR=0x8005000
maple_mini.menu.bootloader_version.original.build.ldscript=ld/flash.ld
maple_mini.menu.bootloader_version.original.upload.ram.maximum_size=17408
maple_mini.menu.bootloader_version.original.upload.flash.maximum_size=110592
maple_mini.menu.bootloader_version.original.upload.maximum_size=110592
maple_mini.menu.bootloader_version.original.upload.altID=1
mapleMini.menu.bootloader_version.original = Original (17k RAM,108k Flash)
mapleMini.menu.bootloader_version.original.build.vect=VECT_TAB_ADDR=0x8005000
mapleMini.menu.bootloader_version.original.build.ldscript=ld/flash.ld
mapleMini.menu.bootloader_version.original.upload.ram.maximum_size=17408
mapleMini.menu.bootloader_version.original.upload.flash.maximum_size=110592
mapleMini.menu.bootloader_version.original.upload.maximum_size=110592
mapleMini.menu.bootloader_version.original.upload.altID=1
maple_mini.menu.bootloader_version.bootloader20 = Bootloader 2.0 (20k RAM,120k Flash)
maple_mini.menu.bootloader_version.bootloader20.build.vect=VECT_TAB_ADDR=0x8002000
maple_mini.menu.bootloader_version.bootloader20.build.ldscript=ld/bootloader_20.ld
maple_mini.menu.bootloader_version.bootloader20.upload.ram.maximum_size=20480
maple_mini.menu.bootloader_version.bootloader20.upload.flash.maximum_size=122880
maple_mini.menu.bootloader_version.bootloader20.upload.maximum_size=122880
maple_mini.menu.bootloader_version.bootloader20.upload.altID=2
mapleMini.menu.bootloader_version.bootloader20 = Bootloader 2.0 (20k RAM,120k Flash)
mapleMini.menu.bootloader_version.bootloader20.build.vect=VECT_TAB_ADDR=0x8002000
mapleMini.menu.bootloader_version.bootloader20.build.ldscript=ld/bootloader_20.ld
mapleMini.menu.bootloader_version.bootloader20.upload.ram.maximum_size=20480
mapleMini.menu.bootloader_version.bootloader20.upload.flash.maximum_size=122880
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
@ -146,7 +146,7 @@ nucleo_f103rb.build.vect=VECT_TAB_ADDR=0x8000000
###################### Generic STM32F103C ########################################
genericSTM32F103C.name= Generic STM32F103C series
genericSTM32F103C.name=Generic STM32F103C series
genericSTM32F103C.build.variant=generic_stm32f103c
genericSTM32F103C.build.vect=VECT_TAB_ADDR=0x8000000
genericSTM32F103C.build.core=maple
@ -173,6 +173,16 @@ genericSTM32F103C.menu.device_variant.STM32F103C8.upload.ram.maximum_size=20480
genericSTM32F103C.menu.device_variant.STM32F103C8.upload.flash.maximum_size=65536
#---------------------------- UPLOAD METHODS ---------------------------
genericSTM32F103C.menu.upload_method.DFUUploadMethod=STM32duino bootloader
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.altID=2
genericSTM32F103C.menu.upload_method.serialMethod=Serial
genericSTM32F103C.menu.upload_method.serialMethod.upload.protocol=maple_serial
genericSTM32F103C.menu.upload_method.serialMethod.upload.tool=serial_upload
@ -189,20 +199,10 @@ genericSTM32F103C.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp
genericSTM32F103C.menu.upload_method.BMPMethod.upload.tool=bmp_upload
genericSTM32F103C.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
genericSTM32F103C.menu.upload_method.DFUUploadMethod=Maple DFU
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103C.menu.upload_method.DFUUploadMethod.build.ldscript=ld/bootloader_20.ld
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103C.menu.upload_method.DFUUploadMethod.upload.altID=2
########################### Generic STM32F103R ###########################
genericSTM32F103R.name= Generic STM32F103R series
genericSTM32F103R.name=Generic STM32F103R series
genericSTM32F103R.build.variant=generic_stm32f103r
genericSTM32F103R.build.vect=VECT_TAB_ADDR=0x8000000
genericSTM32F103R.build.core=maple
@ -235,6 +235,16 @@ genericSTM32F103R.menu.device_variant.STM32F103RE.build.ldscript=ld/stm32f103re.
#---------------------------- UPLOAD METHODS ---------------------------
genericSTM32F103R.menu.upload_method.DFUUploadMethod=STM32duino bootloader
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103re-bootloader.ld
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.altID=2
genericSTM32F103R.menu.upload_method.serialMethod=Serial
genericSTM32F103R.menu.upload_method.serialMethod.upload.protocol=maple_serial
genericSTM32F103R.menu.upload_method.serialMethod.upload.tool=serial_upload
@ -250,19 +260,9 @@ genericSTM32F103R.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp
genericSTM32F103R.menu.upload_method.BMPMethod.upload.tool=bmp_upload
genericSTM32F103R.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
genericSTM32F103R.menu.upload_method.DFUUploadMethod=Maple DFU
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103R.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103re-bootloader.ld
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103R.menu.upload_method.DFUUploadMethod.upload.altID=2
########################### Generic STM32F103V ###########################
genericSTM32F103V.name=Generic STM32F103V series
genericSTM32F103V.build.variant=generic_stm32f103v
genericSTM32F103V.build.vect=VECT_TAB_ADDR=0x8000000
@ -300,11 +300,20 @@ genericSTM32F103V.menu.device_variant.STM32F103VE.upload.flash.maximum_size=5242
genericSTM32F103V.menu.device_variant.STM32F103VE.build.ldscript=ld/stm32f103ve.ld
#---------------------------- UPLOAD METHODS ---------------------------
genericSTM32F103V.menu.upload_method.DFUUploadMethod=STM32duino bootloader
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103veDFU.ld
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.altID=2
genericSTM32F103V.menu.upload_method.serialMethod=Serial
genericSTM32F103V.menu.upload_method.serialMethod.upload.protocol=maple_serial
genericSTM32F103V.menu.upload_method.serialMethod.upload.tool=serial_upload
genericSTM32F103V.menu.upload_method.STLinkMethod=STLink
genericSTM32F103V.menu.upload_method.STLinkMethod.upload.protocol=STLink
genericSTM32F103V.menu.upload_method.STLinkMethod.upload.tool=stlink_upload
@ -315,20 +324,9 @@ genericSTM32F103V.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp
genericSTM32F103V.menu.upload_method.BMPMethod.upload.tool=bmp_upload
genericSTM32F103V.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
genericSTM32F103V.menu.upload_method.DFUUploadMethod=Maple DFU
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103V.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103veDFU.ld
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103V.menu.upload_method.DFUUploadMethod.upload.altID=2
########################### Generic STM32F103Z ###########################
genericSTM32F103Z.name=Generic STM32F103Z series
genericSTM32F103Z.build.variant=generic_stm32f103z
genericSTM32F103Z.build.vect=VECT_TAB_ADDR=0x8000000
@ -360,6 +358,16 @@ genericSTM32F103Z.menu.device_variant.STM32F103ZE.upload.flash.maximum_size=5242
genericSTM32F103Z.menu.device_variant.STM32F103ZE.build.ldscript=ld/stm32f103ze.ld
#---------------------------- UPLOAD METHODS ---------------------------
genericSTM32F103Z.menu.upload_method.DFUUploadMethod=STM32duino bootloader
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103z_dfu.ld
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.altID=2
genericSTM32F103Z.menu.upload_method.serialMethod=Serial
genericSTM32F103Z.menu.upload_method.serialMethod.upload.protocol=maple_serial
genericSTM32F103Z.menu.upload_method.serialMethod.upload.tool=serial_upload
@ -373,12 +381,3 @@ genericSTM32F103Z.menu.upload_method.BMPMethod=BMP (Black Magic Probe)
genericSTM32F103Z.menu.upload_method.BMPMethod.upload.protocol=gdb_bmp
genericSTM32F103Z.menu.upload_method.BMPMethod.upload.tool=bmp_upload
genericSTM32F103Z.menu.upload_method.BMPMethod.build.upload_flags=-DCONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
genericSTM32F103Z.menu.upload_method.DFUUploadMethod=Maple DFU
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.protocol=maple_dfu
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.tool=maple_upload
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.upload_flags=-DSERIAL_USB -DGENERIC_BOOTLOADER
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.vect=VECT_TAB_ADDR=0x8002000
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.build.ldscript=ld/stm32f103z_dfu.ld
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.usbID=1EAF:0003
genericSTM32F103Z.menu.upload_method.DFUUploadMethod.upload.altID=2

View File

@ -37,54 +37,58 @@
#include <libmaple/timer.h>
#include <libmaple/usart.h>
#define DEFINE_HWSERIAL(name, n) \
HardwareSerial name(USART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
#if 0
#define DEFINE_HWSERIAL_UART(name, n) \
HardwareSerial name(UART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
#ifdef SERIAL_USB
#if BOARD_HAVE_USART1
DEFINE_HWSERIAL(Serial1, 1);
#endif
#if BOARD_HAVE_USART2
DEFINE_HWSERIAL(Serial2, 2);
#endif
#if BOARD_HAVE_USART3
DEFINE_HWSERIAL(Serial3, 3);
#endif
#if BOARD_HAVE_UART4
DEFINE_HWSERIAL_UART(Serial4, 4);
#endif
#if BOARD_HAVE_UART5
DEFINE_HWSERIAL_UART(Serial5, 5);
#endif
#if BOARD_HAVE_USART6
DEFINE_HWSERIAL_UART(Serial6, 6);
#endif
#else
#if BOARD_HAVE_USART1
DEFINE_HWSERIAL(Serial, 1);
#endif
#if BOARD_HAVE_USART2
DEFINE_HWSERIAL(Serial1, 2);
#endif
#if BOARD_HAVE_USART3
DEFINE_HWSERIAL(Serial2, 3);
#endif
#if BOARD_HAVE_UART4
DEFINE_HWSERIAL_UART(Serial3, 4);
#endif
#if BOARD_HAVE_UART5
DEFINE_HWSERIAL_UART(Serial4, 5);
#endif
#if BOARD_HAVE_USART6
DEFINE_HWSERIAL_UART(Serial5, 6);
#define DEFINE_HWSERIAL(name, n) \
HardwareSerial name(USART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
#define DEFINE_HWSERIAL_UART(name, n) \
HardwareSerial name(UART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
#ifdef SERIAL_USB
#if BOARD_HAVE_USART1
DEFINE_HWSERIAL(Serial1, 1);
#endif
#if BOARD_HAVE_USART2
DEFINE_HWSERIAL(Serial2, 2);
#endif
#if BOARD_HAVE_USART3
DEFINE_HWSERIAL(Serial3, 3);
#endif
#if BOARD_HAVE_UART4
DEFINE_HWSERIAL_UART(Serial4, 4);
#endif
#if BOARD_HAVE_UART5
DEFINE_HWSERIAL_UART(Serial5, 5);
#endif
#if BOARD_HAVE_USART6
DEFINE_HWSERIAL_UART(Serial6, 6);
#endif
#else
#if BOARD_HAVE_USART1
DEFINE_HWSERIAL(Serial, 1);
#endif
#if BOARD_HAVE_USART2
DEFINE_HWSERIAL(Serial1, 2);
#endif
#if BOARD_HAVE_USART3
DEFINE_HWSERIAL(Serial2, 3);
#endif
#if BOARD_HAVE_UART4
DEFINE_HWSERIAL_UART(Serial3, 4);
#endif
#if BOARD_HAVE_UART5
DEFINE_HWSERIAL_UART(Serial4, 5);
#endif
#if BOARD_HAVE_USART6
DEFINE_HWSERIAL_UART(Serial5, 6);
#endif
#endif
#endif
HardwareSerial::HardwareSerial(usart_dev *usart_device,
uint8 tx_pin,

View File

@ -100,6 +100,20 @@ struct usart_dev;
#define SERIAL_9O2 0B00101011
/* Roger Clark
* Moved macros from hardwareSerial.cpp
*/
#define DEFINE_HWSERIAL(name, n) \
HardwareSerial name(USART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
#define DEFINE_HWSERIAL_UART(name, n) \
HardwareSerial name(UART##n, \
BOARD_USART##n##_TX_PIN, \
BOARD_USART##n##_RX_PIN)
/* Roger clark. Changed class inheritance from Print to Stream.
* Also added new functions for peek() and availableForWrite()

View File

@ -138,6 +138,23 @@ void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode) {
}
}
gpio_pin_mode gpio_get_mode(gpio_dev *dev, uint8 pin) {
gpio_reg_map *regs = dev->regs;
__io uint32 *cr = &regs->CRL + (pin >> 3);
uint32 shift = (pin & 0x7) * 4;
uint32 tmp = *cr;
uint32 crMode = (*cr>>shift) & 0x0F;
// could be pull up or pull down. Nee to check the ODR
if (crMode==GPIO_INPUT_PD && ((regs->ODR >> pin) & 0x01) !=0 )
{
crMode = GPIO_INPUT_PU;
}
return(crMode);
}
/*
* AFIO
*/

View File

@ -63,7 +63,7 @@ void spi_config_gpios(spi_dev *ignored,
uint8 miso_bit,
uint8 mosi_bit) {
if (as_master) {
gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP);
// gpio_set_mode(nss_dev, nss_bit, GPIO_AF_OUTPUT_PP);// Roger Clark. Commented out, so that NSS can be driven as a normal GPIO pin during SPI use
gpio_set_mode(comm_dev, sck_bit, GPIO_AF_OUTPUT_PP);
gpio_set_mode(comm_dev, miso_bit, GPIO_INPUT_FLOATING);
gpio_set_mode(comm_dev, mosi_bit, GPIO_AF_OUTPUT_PP);

View File

@ -163,15 +163,14 @@ __default_handler:
.weak __irq_tim1_cc
.globl __irq_tim1_cc
.set __irq_tim1_cc, __default_handler
.weak __irq_tim2
.globl __irq_tim2
.set __irq_tim2, __default_handler
.weak __irq_tim3
.globl __irq_tim3
.set __irq_tim3, __default_handler
.weak __irq_tim4
.globl __irq_tim4
.set __irq_tim4, __default_handler
.weakref __irq_tim2, __default_handler
.globl __irq_tim2
.weakref __irq_tim3, __default_handler
.globl __irq_tim3
.weakref __irq_tim4, __default_handler
.globl __irq_tim4
.weak __irq_i2c1_ev
.globl __irq_i2c1_ev
.set __irq_i2c1_ev, __default_handler
@ -260,4 +259,4 @@ __default_handler:
.weak __irq_dma2_channel4_5
.globl __irq_dma2_channel4_5
.set __irq_dma2_channel4_5, __default_handler
#endif /* STM32_HIGH_DENSITY */
#endif /* STM32_HIGH_DENSITY */

View File

@ -72,9 +72,17 @@ void USBSerial::begin(void) {
//Roger Clark. Two new begin functions has been added so that normal Arduino Sketches that use Serial.begin(xxx) will compile.
void USBSerial::begin(unsigned long ignoreBaud)
{
volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud;
ignoreBaud=removeCompilerWarningsIgnoreBaud;
}
void USBSerial::begin(unsigned long ignoreBaud, uint8_t ignore)
{
volatile unsigned long removeCompilerWarningsIgnoreBaud=ignoreBaud;
volatile uint8_t removeCompilerWarningsIgnore=ignore;
ignoreBaud=removeCompilerWarningsIgnoreBaud;
ignore=removeCompilerWarningsIgnore;
}
void USBSerial::end(void) {

View File

@ -0,0 +1,76 @@
/**
SPI_1 and SPI_2 port example code
Description:
This sketch sends one byte with value 0x55 over the SPI_1 or SPI_2 port.
The received byte (the answer from the SPI slave device) is stored to the <data> variable.
The sketch as it is, works with SPI_1 port. For using the SPI_2 port, just
un-comment all the nessesary code lines marked with <SPI_2> word.
Created on 10 Jun 2015 by Vassilis Serasidis
email: avrsite@yahoo.gr
Using the first SPI port (SPI_1)
SS <--> PA4 <--> BOARD_SPI1_NSS_PIN
SCK <--> PA5 <--> BOARD_SPI1_SCK_PIN
MISO <--> PA6 <--> BOARD_SPI1_MISO_PIN
MOSI <--> PA7 <--> BOARD_SPI1_MOSI_PIN
Using the second SPI port (SPI_2)
SS <--> PB12 <--> BOARD_SPI2_NSS_PIN
SCK <--> PB13 <--> BOARD_SPI2_SCK_PIN
MISO <--> PB14 <--> BOARD_SPI2_MISO_PIN
MOSI <--> PB15 <--> BOARD_SPI2_MOSI_PIN
*/
#include <SPI.h>
#define SPI1_NSS_PIN PA4 //SPI_1 Chip Select pin is PA4. You can change it to the STM32 pin you want.
#define SPI2_NSS_PIN PB12 //SPI_2 Chip Select pin is PB12. You can change it to the STM32 pin you want.
SPIClass SPI_2(2); //Create an instance of the SPI Class called SPI_2 that uses the 2nd SPI Port
byte data;
void setup() {
// Setup SPI 1
SPI.begin(); //Initialize the SPI_1 port.
SPI.setBitOrder(MSBFIRST); // Set the SPI_1 bit order
SPI.setDataMode(SPI_MODE0); //Set the SPI_2 data mode 0
SPI.setClockDivider(SPI_CLOCK_DIV16); // Slow speed (72 / 16 = 4.5 MHz SPI_1 speed)
pinMode(SPI1_NSS_PIN, OUTPUT);
// Setup SPI 2
SPI_2.begin(); //Initialize the SPI_2 port.
SPI_2.setBitOrder(MSBFIRST); // Set the SPI_2 bit order
SPI_2.setDataMode(SPI_MODE0); //Set the SPI_2 data mode 0
SPI_2.setClockDivider(SPI_CLOCK_DIV16); // Use a different speed to SPI 1
pinMode(SPI2_NSS_PIN, OUTPUT);
}
void loop() {
sendSPI();
sendSPI2();
delayMicroseconds(10); //Delay 10 micro seconds.
}
void sendSPI()
{
digitalWrite(SPI1_NSS_PIN, LOW); // manually take CSN low for SPI_1 transmission
data = SPI.transfer(0x55); //Send the HEX data 0x55 over SPI-1 port and store the received byte to the <data> variable.
digitalWrite(SPI1_NSS_PIN, HIGH); // manually take CSN high between spi transmissions
}
void sendSPI2()
{
digitalWrite(SPI2_NSS_PIN, LOW); // manually take CSN low for SPI_2 transmission
data = SPI_2.transfer(0x55); //Send the HEX data 0x55 over SPI-2 port and store the received byte to the <data> variable.
digitalWrite(SPI2_NSS_PIN, HIGH); // manually take CSN high between spi transmissions
}

View File

@ -119,10 +119,7 @@ SPIClass::SPIClass(uint32 spi_num) {
*/
void SPIClass::begin(void) {
if (dataMode >= 4) {
ASSERT(0);
return;
}
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);
@ -347,7 +344,7 @@ void SPIClass::write(const uint8 *data, uint32 length) {
while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete."
}
uint8 SPIClass::transfer(uint8 byte) {
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 ..."

View File

@ -238,7 +238,7 @@ public:
* @param data Byte to transmit.
* @return Next unread byte.
*/
uint8 transfer(uint8 data);
uint8 transfer(uint8 data) const;
/**
* @brief Sets up a DMA Transfer for "length" bytes.

View File

@ -0,0 +1,45 @@
# EtherCard
**EtherCard** is a driver for the ENC28J60 chip, compatible with Arduino IDE 1.6.3 (or later).
Adapted and extended from code written by Guido Socher and Pascal Stang.
License: GPL2
The documentation for this library is at http://jeelabs.net/pub/docs/ethercard/.
## Physical Installation
### PIN Connections (Using STM32F103):
|ENC28J60|STM32F103|
|:------:|:-----:|
|Vcc|3.3V|
|SCK|PA5|
|SO|PA6|
|SI|PA7|
|CS|PA8| # Selectable with the ether.begin() function
|RST|3.3V|
The **CS** pin is selectable with the ether.begin() function.
e.g. If you want to use the **PA9** as **CS** pin then you can initiallize the ethernet module inside the sketch as:
`if (ether.begin(sizeof Ethernet::buffer, mymac) == 0,`**`PA9`**`) `
By default the pin **PA8** is used as **CS** (you don't have to initiallize it).
## Credits
The **EtherCard** library was written by [Jean-Claude Wippler][F] and ported to **STM32F103** by [Vassilis Serasidis][V]
## Support
That library works perfect on Arduino IDE 1.6.3 (or later) with [Arduino_STM32 project][S] installed.
The Arduino STM32 project has a forum ([STM32duino][F]) also for getting or for providing help to people that are interested in that project .
[F]: https://github.com/jcw
[S]: https://github.com/rogerclarkmelbourne/Arduino_STM32
[F]: http://www.stm32duino.com
[V]: https://github.com/Serasidis

View File

@ -0,0 +1,320 @@
// Collect RF12 packets and send them on as UDP collectd packets on Ethernet.
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// This sketch is derived from RF12eth.pde (and etherNode.ino):
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
#include <EtherCard_STM.h>
#include <JeeLib.h>
#include <avr/eeprom.h>
#define DEBUG 1 // set to 1 to display free RAM on web page
#define SERIAL 1 // set to 1 to show incoming requests on serial port
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
// configuration, as stored in EEPROM
struct Config {
byte band;
byte group;
byte collect;
word port;
byte valid; // keep this as last byte
} config;
// ethernet interface mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// buffer for an outgoing data packet
static byte outBuf[RF12_MAXDATA], outDest;
static char outCount = -1;
// this buffer will be used to construct a collectd UDP packet
static byte collBuf [200], collPos;
#define NUM_MESSAGES 3 // Number of messages saved in history
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
static BufferFiller bfill; // used as cursor while filling the buffer
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
static byte next_msg; // pointer to next rf12rcvd line
static word msgs_rcvd; // total number of lines received modulo 10,000
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
static void loadConfig () {
for (byte i = 0; i < sizeof config; ++i)
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
if (config.valid != 253) {
config.valid = 253;
config.band = 8;
config.group = 1;
config.collect = 1;
config.port = 25827;
}
byte freq = config.band == 4 ? RF12_433MHZ :
config.band == 8 ? RF12_868MHZ :
RF12_915MHZ;
rf12_initialize(31, freq, config.group);
}
static void saveConfig () {
for (byte i = 0; i < sizeof config; ++i)
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
}
#if DEBUG
static int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#endif
void setup (){
Serial.begin(57600);
Serial.println("\n[JeeUdp]");
loadConfig();
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip);
}
const char okHeader[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
;
static void homePage (BufferFiller& buf) {
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
buf.emit_p(PSTR("$F\r\n"
"<title>RF12 JeeUdp</title>"
"<h2>RF12 JeeUdp @ $D - RF12 @ $D.$D</h2>"
"<a href='c'>Configure</a> - <a href='s'>Send Packet</a>"
"<h3>Last $D messages:</h3>"
"<pre>"), okHeader, config.port, mhz, config.group, NUM_MESSAGES);
for (byte i = 0; i < NUM_MESSAGES; ++i) {
byte j = (next_msg + i) % NUM_MESSAGES;
if (history_len[j] > 0) {
word n = msgs_rcvd - NUM_MESSAGES + i;
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
for (byte k = 0; k < history_len[j]; ++k)
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
}
}
long t = millis() / 1000;
word h = t / 3600;
byte m = (t / 60) % 60;
byte s = t % 60;
buf.emit_p(PSTR(
"</pre>"
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
#if DEBUG
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
#endif
}
static int getIntArg(const char* data, const char* key, int value =-1) {
char temp[10];
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
value = atoi(temp);
return value;
}
static void configPage (const char* data, BufferFiller& buf) {
// pick up submitted data, if present
if (data[6] == '?') {
byte b = getIntArg(data, "b", 8);
byte g = getIntArg(data, "g", 1);
byte c = getIntArg(data, "c", 0);
word p = getIntArg(data, "p", 25827);
if (1 <= g && g <= 250 && 1024 <= p && p <= 30000) {
// store values as new settings
config.band = b;
config.group = g;
config.collect = c;
config.port = p;
saveConfig();
// re-init RF12 driver
loadConfig();
// clear history
memset(history_len, 0, sizeof history_len);
// redirect to the home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
}
// else show a configuration form
buf.emit_p(PSTR("$F\r\n"
"<h3>Server node configuration</h3>"
"<form>"
"<p>"
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
"Collect mode: <input type=checkbox name=c value='1' $S> "
"(don't send ACKs)<br><br>"
"UDP Port <input type=text name=p value='$D' size=5> (1024..30000)"
"</p>"
"<input type=submit value=Set>"
"</form>"), okHeader, config.band, config.group,
config.collect ? "CHECKED" : "",
config.port);
}
static void sendPage (const char* data, BufferFiller& buf) {
// pick up submitted data, if present
const char* p = strstr(data, "b=");
byte d = getIntArg(data, "d");
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
// prepare to send data as soon as possible in loop()
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
outCount = 0;
// convert the input string to a number of decimal data bytes in outBuf
++p;
while (*p != 0 && *p != '&') {
outBuf[outCount] = 0;
while ('0' <= *++p && *p <= '9')
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
++outCount;
}
#if SERIAL
Serial.print("Send to ");
Serial.print(outDest, DEC);
Serial.print(':');
for (byte i = 0; i < outCount; ++i) {
Serial.print(' ');
Serial.print(outBuf[i], DEC);
}
Serial.println();
#endif
// redirect to home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
// else show a send form
buf.emit_p(PSTR("$F\r\n"
"<h3>Send a wireless data packet</h3>"
"<form>"
"<p>"
"Data bytes <input type=text name=b size=50> (decimal)<br>"
"Destination node <input type=text name=d size=3> "
"(1..31, or 0 to broadcast)<br>"
"</p>"
"<input type=submit value=Send>"
"</form>"), okHeader);
}
static void collectTypeLen (word type, word len) {
len += 4;
collBuf[collPos++] = type >> 8;
collBuf[collPos++] = (byte) type;
collBuf[collPos++] = len >> 8;
collBuf[collPos++] = (byte) len;
}
static void collectStr (word type, const char* data) {
word len = strlen(data) + 1;
collectTypeLen(type, len);
strcpy((char*) collBuf + collPos, data);
collPos += len;
}
static void collectPayload (word type) {
// Copy the received RF12 data into a as many values as needed.
byte num = rf12_len / 8 + 1; // this many values will be needed
collectTypeLen(type, 2 + 9 * num);
collBuf[collPos++] = 0;
collBuf[collPos++] = num;
for (byte i = 0; i < num; ++i)
collBuf[collPos++] = 0; // counter
for (char i = 0; i < 8 * num; ++i) // include -1, i.e. the length byte
collBuf[collPos++] = i <= rf12_len ? rf12_data[i-1] : 0;
}
static void forwardToUDP () {
static byte destIp[] = { 239,192,74,66 }; // UDP multicast address
char buf[10];
collPos = 0;
collectStr(0x0000, "JeeUdp");
collectStr(0x0002, "RF12");
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
sprintf(buf, "%d.%d", mhz, config.group);
collectStr(0x0003, buf);
collectStr(0x0004, "OK");
sprintf(buf, "%d", rf12_hdr);
collectStr(0x0005, buf);
collectPayload(0x0006);
ether.sendUdp ((char*) collBuf, collPos, 23456, destIp, config.port);
#if SERIAL
Serial.println("UDP sent");
#endif
}
void loop (){
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
// check if valid tcp data is received
if (pos) {
bfill = ether.tcpOffset();
char* data = (char *) Ethernet::buffer + pos;
#if SERIAL
Serial.println(data);
#endif
// receive buf hasn't been clobbered by reply yet
if (strncmp("GET / ", data, 6) == 0)
homePage(bfill);
else if (strncmp("GET /c", data, 6) == 0)
configPage(data, bfill);
else if (strncmp("GET /s", data, 6) == 0)
sendPage(data, bfill);
else
bfill.emit_p(PSTR(
"HTTP/1.0 401 Unauthorized\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<h1>401 Unauthorized</h1>"));
ether.httpServerReply(bfill.position()); // send web page data
}
// RFM12 loop runner, don't report acks
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
history_rcvd[next_msg][0] = rf12_hdr;
for (byte i = 0; i < rf12_len; ++i)
if (i < MESSAGE_TRUNC)
history_rcvd[next_msg][i+1] = rf12_data[i];
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
: MESSAGE_TRUNC+1;
next_msg = (next_msg + 1) % NUM_MESSAGES;
msgs_rcvd = (msgs_rcvd + 1) % 10000;
if (RF12_WANTS_ACK && !config.collect) {
#if SERIAL
Serial.println(" -> ack");
#endif
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
}
forwardToUDP();
}
// send a data packet out if requested
if (outCount >= 0 && rf12_canSend()) {
rf12_sendStart(outDest, outBuf, outCount, 1);
outCount = -1;
}
}

View File

@ -0,0 +1,145 @@
#include <EtherCard_STM.h> |Mac adress|
#include <SPI.h>
const char SSDP_RESPONSE[] PROGMEM = "HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=1200\r\nEXT:\r\nSERVER:Arduino\r\nST: upnp:rootdevice\r\nUSN: uuid:abcdefgh-7dec-11d0-a765-7499692d3040\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
const char SSDP_RESPONSE_XML[] PROGMEM = "/??\r\n\r\n"; // here is the adress of xml file /?? in this exemple but you could use another /upnp.xml\r\n\r\n
const char XML_DESCRIP[] PROGMEM = "HTTP/1.1 200 OK\r\nContent-Type: text/xml\r\n\r\n<?xml version='1.0'?>\r<root xmlns='urn:schemas-upnp-org:device-1-0'><device><deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType><presentationURL>/</presentationURL><friendlyName>Arduino</friendlyName><manufacturer>Fredycpu</manufacturer><manufacturerURL>http://fredycpu.pro</manufacturerURL><serialNumber>1</serialNumber><UDN>uuid:abcdefgh-7dec-11d0-a765-7499692d3040</UDN></device></root> ";
const char SSDP_NOTIFY[] PROGMEM = "NOTIFY * HTTP/1.1\r\nHOST: 239.255.255.250:1900\r\nCACHE-CONTROL: max-age=1200\r\nNT: upnp:rootdevice\r\nUSN: uuid:abcdefga-7dec-11d0-a765-7499692d3040::upnp:rootdevice\r\nNTS: ssdp:alive\r\nSERVER: Arduino UPnP/1.0\r\nLOCATION: http://"; //dont forget our mac adress USN: uuid:abcdefgh-7dec-11d0-a765-Mac addr
// in XML_DESCRIP // <deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType> // declare as home automation
// in XML_DESCRIP // <friendlyName>Arduino</friendlyName> // declare the name of the service here Arduino
// in XML_DESCRIP // <presentationURL>/</presentationURL> // adress of the page who would opened on service double click ,you could use http://ip but if you use dhcp it's better so and dont wase memory
// this is the entire protocol, but you can try to use SSDP_NOTIFY as SSDP_RESPONSE with most systems will work and you can free a bit of flash mem.
static byte myip[] = {
192,168,1,204 };
static byte gwip[] = {
192,168,1,1 };
static byte ssdp[] = {
239,255,255,250 };
static byte mymac[] = {
0x74,0x99,0x69,0x2D,0x30,0x40 }; // if you change it you must update SSDP_RESPONSE and XML_DESCRIP
byte Ethernet::buffer[750]; // tcp ip send and receive buffer
unsigned long timer=9999;
const char pageA[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html>"
"<head><title>"
"multipackets Test"
"</title></head>"
"<body>"
"<a href='/'>Start here</a><br>"
"<a href='/test.jpg'>Image test</a><br>"
"<h3>packet 1</h3>"
"<p><em>"
"the first packet send "
"</em></p>"
;
const char pageB[] PROGMEM =
"<h3>packet 2</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
const char pageC[] PROGMEM =
"<h3>packet 3</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
const char pageD[] PROGMEM =
"<h3>packet 4</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
void setup(){
ether.begin(sizeof Ethernet::buffer, mymac);// 53 for the mega ethernet shield and 10 for normal ethernet shield
ether.staticSetup(myip, gwip);
ENC28J60::disableMulticast(); //disable multicast filter means enable multicast reception
Serial.begin(57600);
}
void loop(){
wait:
word pos = ether.packetLoop(ether.packetReceive());
// check if valid tcp data is received
if (pos) {
char* data = (char *) Ethernet::buffer + pos;
if (strncmp("GET / ", data, 6) == 0) {
ether.httpServerReplyAck(); // send ack to the request
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and send the terminate flag
ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
goto wait;
}
if (strncmp("GET /??", data, 7) == 0) { // description of services (normaly an xml file but here .....)
ether.httpServerReplyAck();
memcpy_P(Ethernet::buffer + TCP_OPTIONS_P,XML_DESCRIP, sizeof XML_DESCRIP);
ether.httpServerReply_with_flags(sizeof XML_DESCRIP - 1 ,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
goto wait;
}
if (strncmp("M-SEARCH", data, 8) == 0) { // service discovery request comes here (udp protocol)
ssdpresp();
goto wait;
}
}
if (((millis()-timer)>50000)||(timer>millis())) {
timer=millis();
ssdpnotify();
}
}
void ssdpresp() { //response to m-search
byte ip_dst[4];
unsigned int port_dst=Ethernet::buffer[34]*256+Ethernet::buffer[35];//extract source port of request
for( int i=0; i<4;i++) { //extract source IP of request
ip_dst[i]=Ethernet::buffer[i+26];
}
int udppos = UDP_DATA_P;
EtherCard::udpPrepare(1900,ip_dst,port_dst);
memcpy_P(Ethernet::buffer + udppos, SSDP_RESPONSE, sizeof SSDP_RESPONSE);
udppos = udppos + sizeof SSDP_RESPONSE-1;
addip(udppos);
}
void ssdpnotify() { //Notification
int udppos = UDP_DATA_P;
EtherCard::udpPrepare(1900,ssdp,1900);
memcpy_P(Ethernet::buffer + udppos, SSDP_NOTIFY, sizeof SSDP_NOTIFY);
udppos = udppos + sizeof SSDP_NOTIFY-1;
addip(udppos);
}
void addip(int udppos) { // add current ip to the request and send it
int adr;
for(int i=0;i<4;i++) { // extract the current ip of arduino
adr = ether.myip[i]/100;
if (adr) {
Ethernet::buffer[udppos]=adr+48;
udppos++;
}
adr=(ether.myip[i]%100)/10;
if (adr) {
Ethernet::buffer[udppos]=adr+48;
udppos++;
}
adr=ether.myip[i]%10;
Ethernet::buffer[udppos]=adr+48;
udppos++;
Ethernet::buffer[udppos]=46;
udppos++; //"."
}
udppos--;//erase the last point
memcpy_P(Ethernet::buffer + udppos,SSDP_RESPONSE_XML,sizeof SSDP_RESPONSE_XML);
udppos = udppos + sizeof SSDP_RESPONSE_XML;
udppos--;
EtherCard::udpTransmit(udppos-UDP_DATA_P); // send all to the computer who make the request on her ip and port who make the request
}

View File

@ -0,0 +1,84 @@
// Present a "Will be back soon web page", as stand-in webserver.
// 2011-01-30 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,1,203 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
#endif
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
const char page[] PROGMEM =
"HTTP/1.0 503 Service Unavailable\r\n"
"Content-Type: text/html\r\n"
"Retry-After: 600\r\n"
"\r\n"
"<html>"
"<head><title>"
"Service Temporarily Unavailable"
"</title></head>"
"<body>"
"<h3>This service is currently unavailable</h3>"
"<p><em>"
"The main server is currently off-line.<br />"
"Please try again later."
"</em></p>"
"</body>"
"</html>"
;
void setup(){
Serial.begin(57600);
delay(10);
Serial.println("\n[backSoon]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
#if STATIC
ether.staticSetup(myip, gwip);
#else
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
}
void loop(){
// wait for an incoming TCP packet, but ignore its contents
if (ether.packetLoop(ether.packetReceive())) {
memcpy_P(ether.tcpOffset(), page, sizeof page);
ether.httpServerReply(sizeof page - 1);
}
}

View File

@ -0,0 +1,295 @@
// Arduino demo sketch for testing RFM12B + ethernet
// 2010-05-20 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// Listens for RF12 messages and displays valid messages on a webpage
// Memory usage exceeds 1K, so use Atmega328 or decrease history/buffers
//
// This sketch is derived from RF12eth.pde:
// May 2010, Andras Tucsni, http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <JeeLib.h>
#include <avr/eeprom.h>
#define DEBUG 1 // set to 1 to display free RAM on web page
#define SERIAL 0 // set to 1 to show incoming requests on serial port
#define CONFIG_EEPROM_ADDR ((byte*) 0x10)
// configuration, as stored in EEPROM
struct Config {
byte band;
byte group;
byte collect;
word refresh;
byte valid; // keep this as last byte
} config;
// ethernet interface mac address - must be unique on your network
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// buffer for an outgoing data packet
static byte outBuf[RF12_MAXDATA], outDest;
static char outCount = -1;
#define NUM_MESSAGES 10 // Number of messages saved in history
#define MESSAGE_TRUNC 15 // Truncate message payload to reduce memory use
static BufferFiller bfill; // used as cursor while filling the buffer
static byte history_rcvd[NUM_MESSAGES][MESSAGE_TRUNC+1]; //history record
static byte history_len[NUM_MESSAGES]; // # of RF12 messages+header in history
static byte next_msg; // pointer to next rf12rcvd line
static word msgs_rcvd; // total number of lines received modulo 10,000
byte Ethernet::buffer[1000]; // tcp/ip send and receive buffer
static void loadConfig() {
for (byte i = 0; i < sizeof config; ++i)
((byte*) &config)[i] = eeprom_read_byte(CONFIG_EEPROM_ADDR + i);
if (config.valid != 253) {
config.valid = 253;
config.band = 8;
config.group = 1;
config.collect = 1;
config.refresh = 5;
}
byte freq = config.band == 4 ? RF12_433MHZ :
config.band == 8 ? RF12_868MHZ :
RF12_915MHZ;
rf12_initialize(31, freq, config.group);
}
static void saveConfig() {
for (byte i = 0; i < sizeof config; ++i)
eeprom_write_byte(CONFIG_EEPROM_ADDR + i, ((byte*) &config)[i]);
}
#if DEBUG
static int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}
#endif
void setup(){
#if SERIAL
Serial.begin(57600);
Serial.println("\n[etherNode]");
#endif
loadConfig();
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
#if SERIAL
ether.printIp("IP: ", ether.myip);
#endif
}
const char okHeader[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
;
static void homePage(BufferFiller& buf) {
word mhz = config.band == 4 ? 433 : config.band == 8 ? 868 : 915;
buf.emit_p(PSTR("$F\r\n"
"<meta http-equiv='refresh' content='$D'/>"
"<title>RF12 etherNode - $D MHz, group $D</title>"
"RF12 etherNode - $D MHz, group $D "
"- <a href='c'>configure</a> - <a href='s'>send packet</a>"
"<h3>Last $D messages:</h3>"
"<pre>"), okHeader, config.refresh, mhz, config.group,
mhz, config.group, NUM_MESSAGES);
for (byte i = 0; i < NUM_MESSAGES; ++i) {
byte j = (next_msg + i) % NUM_MESSAGES;
if (history_len[j] > 0) {
word n = msgs_rcvd - NUM_MESSAGES + i;
buf.emit_p(PSTR("\n$D$D$D$D: OK"), // hack, to show leading zero's
n/1000, (n/100) % 10, (n/10) % 10, n % 10);
for (byte k = 0; k < history_len[j]; ++k)
buf.emit_p(PSTR(" $D"), history_rcvd[j][k]);
}
}
long t = millis() / 1000;
word h = t / 3600;
byte m = (t / 60) % 60;
byte s = t % 60;
buf.emit_p(PSTR(
"</pre>"
"Uptime is $D$D:$D$D:$D$D"), h/10, h%10, m/10, m%10, s/10, s%10);
#if DEBUG
buf.emit_p(PSTR(" ($D bytes free)"), freeRam());
#endif
}
static int getIntArg(const char* data, const char* key, int value =-1) {
char temp[10];
if (ether.findKeyVal(data + 7, temp, sizeof temp, key) > 0)
value = atoi(temp);
return value;
}
static void configPage(const char* data, BufferFiller& buf) {
// pick up submitted data, if present
if (data[6] == '?') {
byte b = getIntArg(data, "b");
byte g = getIntArg(data, "g");
byte c = getIntArg(data, "c", 0);
word r = getIntArg(data, "r");
if (1 <= g && g <= 250 && 1 <= r && r <= 3600) {
// store values as new settings
config.band = b;
config.group = g;
config.collect = c;
config.refresh = r;
saveConfig();
// re-init RF12 driver
loadConfig();
// clear history
memset(history_len, 0, sizeof history_len);
// redirect to the home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
}
// else show a configuration form
buf.emit_p(PSTR("$F\r\n"
"<h3>Server node configuration</h3>"
"<form>"
"<p>"
"Freq band <input type=text name=b value='$D' size=1> (4, 8, or 9)<br>"
"Net group <input type=text name=g value='$D' size=3> (1..250)<br>"
"Collect mode: <input type=checkbox name=c value='1' $S> "
"Don't send ACKs<br><br>"
"Refresh rate <input type=text name=r value='$D' size=4> (1..3600 seconds)"
"</p>"
"<input type=submit value=Set>"
"</form>"), okHeader, config.band, config.group,
config.collect ? "CHECKED" : "",
config.refresh);
}
static void sendPage(const char* data, BufferFiller& buf) {
// pick up submitted data, if present
const char* p = strstr(data, "b=");
byte d = getIntArg(data, "d");
if (data[6] == '?' && p != 0 && 0 <= d && d <= 31) {
// prepare to send data as soon as possible in loop()
outDest = d & RF12_HDR_MASK ? RF12_HDR_DST | d : 0;
outCount = 0;
// convert the input string to a number of decimal data bytes in outBuf
++p;
while (*p != 0 && *p != '&') {
outBuf[outCount] = 0;
while ('0' <= *++p && *p <= '9')
outBuf[outCount] = 10 * outBuf[outCount] + (*p - '0');
++outCount;
}
#if SERIAL
Serial.print("Send to ");
Serial.print(outDest, DEC);
Serial.print(':');
for (byte i = 0; i < outCount; ++i) {
Serial.print(' ');
Serial.print(outBuf[i], DEC);
}
Serial.println();
#endif
// redirect to home page
buf.emit_p(PSTR(
"HTTP/1.0 302 found\r\n"
"Location: /\r\n"
"\r\n"));
return;
}
// else show a send form
buf.emit_p(PSTR("$F\r\n"
"<h3>Send a wireless data packet</h3>"
"<form>"
"<p>"
"Data bytes <input type=text name=b size=50> (decimal)<br>"
"Destination node <input type=text name=d size=3> "
"(1..31, or 0 to broadcast)<br>"
"</p>"
"<input type=submit value=Send>"
"</form>"), okHeader);
}
void loop(){
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
// check if valid tcp data is received
if (pos) {
bfill = ether.tcpOffset();
char* data = (char *) Ethernet::buffer + pos;
#if SERIAL
Serial.println(data);
#endif
// receive buf hasn't been clobbered by reply yet
if (strncmp("GET / ", data, 6) == 0)
homePage(bfill);
else if (strncmp("GET /c", data, 6) == 0)
configPage(data, bfill);
else if (strncmp("GET /s", data, 6) == 0)
sendPage(data, bfill);
else
bfill.emit_p(PSTR(
"HTTP/1.0 401 Unauthorized\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<h1>401 Unauthorized</h1>"));
ether.httpServerReply(bfill.position()); // send web page data
}
// RFM12 loop runner, don't report acks
if (rf12_recvDone() && rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0) {
history_rcvd[next_msg][0] = rf12_hdr;
for (byte i = 0; i < rf12_len; ++i)
if (i < MESSAGE_TRUNC)
history_rcvd[next_msg][i+1] = rf12_data[i];
history_len[next_msg] = rf12_len < MESSAGE_TRUNC ? rf12_len+1
: MESSAGE_TRUNC+1;
next_msg = (next_msg + 1) % NUM_MESSAGES;
msgs_rcvd = (msgs_rcvd + 1) % 10000;
if (RF12_WANTS_ACK && !config.collect) {
#if SERIAL
Serial.println(" -> ack");
#endif
rf12_sendStart(RF12_ACK_REPLY, 0, 0);
}
}
// send a data packet out if requested
if (outCount >= 0 && rf12_canSend()) {
rf12_sendStart(outDest, outBuf, outCount, 1);
outCount = -1;
}
}

View File

@ -0,0 +1,75 @@
// This demo does web requests via DHCP and DNS lookup.
// 2011-07-05 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
#define REQUEST_RATE 5000 // milliseconds
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// remote website name
const char website[] PROGMEM = "google.com";
byte Ethernet::buffer[700];
static long timer;
// called when the client request is complete
static void my_result_cb (uint8_t status, uint16_t off, uint16_t len) {
Serial.print("<<< reply ");
Serial.print(millis() - timer);
Serial.println(" ms");
Serial.println((const char*) Ethernet::buffer + off);
}
void setup () {
Serial.begin(57600);
Serial.println("\n[getDHCPandDNS]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
ether.printIp("My IP: ", ether.myip);
// ether.printIp("Netmask: ", ether.mymask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("Server: ", ether.hisip);
timer = - REQUEST_RATE; // start timing out right away
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer + REQUEST_RATE) {
timer = millis();
Serial.println("\n>>> REQ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
}
}

View File

@ -0,0 +1,76 @@
// This demo does web requests via DNS lookup, using a fixed gateway.
// 2010-11-27 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
#define REQUEST_RATE 5000 // milliseconds
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,1,203 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
// domain name server (dns) address
static byte dnsip[] = { 192,168,1,1 };
// remote website name
const char website[] PROGMEM = "google.com";
byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here
static long timer;
// called when the client request is complete
static void my_result_cb (byte status, uint16_t off, uint16_t len) {
Serial.print("<<< reply ");
Serial.print(millis() - timer);
Serial.println(" ms");
Serial.println((const char*) Ethernet::buffer + off);
}
void setup () {
Serial.begin(57600);
Serial.println("\n[getViaDNS]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
ether.staticSetup(myip, gwip);
ether.copyIp(ether.dnsip, dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("Server: ", ether.hisip);
timer = - REQUEST_RATE; // start timing out right away
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer + REQUEST_RATE) {
timer = millis();
Serial.println("\n>>> REQ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
}
}

View File

@ -0,0 +1,72 @@
// This demo does web requests via DNS lookup, using a fixed gateway.
// 2010-11-27 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
#define REQUEST_RATE 5000 // milliseconds
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,1,203 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
// remote website name
const char website[] PROGMEM = "google.com";
byte Ethernet::buffer[300]; // a very small tcp/ip buffer is enough here
static long timer;
// called when the client request is complete
static void my_result_cb (byte status, uint16_t off, uint16_t len) {
Serial.print("<<< reply ");
Serial.print(millis() - timer);
Serial.println(" ms");
Serial.println((const char*) Ethernet::buffer + off);
}
void setup () {
Serial.begin(57600);
Serial.println("\n[getViaDNS]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
ether.staticSetup(myip, gwip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("Server: ", ether.hisip);
timer = - REQUEST_RATE; // start timing out right away
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer + REQUEST_RATE) {
timer = millis();
Serial.println("\n>>> REQ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_result_cb);
}
}

View File

@ -0,0 +1,99 @@
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
#define TCP_FLAGS_FIN_V 1 //as declared in net.h
#define TCP_FLAGS_ACK_V 0x10 //as declared in net.h
static byte myip[] = { 192,168,1,203 };
static byte gwip[] = { 192,168,1,1 };
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 };
byte Ethernet::buffer[900]; // tcp ip send and receive buffer
const char pageA[] PROGMEM =
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"\r\n"
"<html>"
"<head><title>"
"multipackets Test"
"</title></head>"
"<body>"
"<a href='/'>Start here</a><br>"
"<h3>packet 1</h3>"
"<p><em>"
"the first packet send "
"</em></p>"
;
const char pageB[] PROGMEM =
"<h3>packet 2</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
const char pageC[] PROGMEM =
"<h3>packet 3</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
const char pageD[] PROGMEM =
"<h3>packet 4</h3>"
"<p><em>"
"if you read this it mean it works"
"</em></p>"
;
const char pageE[] PROGMEM =
"<h3>packet 5</h3>"
"<p><em>"
"this is the last packet"
"</em></p>"
;
void setup(){
ether.begin(sizeof Ethernet::buffer, mymac);// 53 for the mega ethernet shield and 10 for normal ethernet shield
ether.staticSetup(myip, gwip);
}
void loop(){
word pos = ether.packetLoop(ether.packetReceive());
// check if valid tcp data is received
if (pos) {
char* data = (char *) Ethernet::buffer + pos;
if (strncmp("GET / ", data, 6) == 0) {
ether.httpServerReplyAck(); // send ack to the request
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA); // send first packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageB, sizeof pageB); // send second packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageB - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageC, sizeof pageC); // send thirdt packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageC - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageD, sizeof pageD); // send fourth packet and not send the terminate flag
ether.httpServerReply_with_flags(sizeof pageD - 1,TCP_FLAGS_ACK_V);
memcpy_P(ether.tcpOffset(), pageE, sizeof pageE); // send fiveth packet and send the terminate flag
ether.httpServerReply_with_flags(sizeof pageE - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V); }
else
{
ether.httpServerReplyAck(); // send ack to the request
memcpy_P(ether.tcpOffset(), pageA, sizeof pageA);//only the first part will sended
ether.httpServerReply_with_flags(sizeof pageA - 1,TCP_FLAGS_ACK_V|TCP_FLAGS_FIN_V);
}
}
}

View File

@ -0,0 +1,129 @@
// works only with tinyfat library
// with SD library packets lost will occurs
// don't know why !
// tested with arduino mega 1280 and uno
// send 240 Megabyte file without packet loss
// at 100 kbyte/s
// tinyfat read a block of 512 bytes on SD card ,
// so the buffer must be 512 + 60 bytes
// on the arduino mega with bigger buffer you can adjust
// if (cur>=512) { // 512 to 1024 with 1100 bytes buffer
#include <EtherCard_STM.h>
#include <tinyFAT.h>
#include <avr/pgmspace.h>
#define TCP_FLAGS_FIN_V 1 //as declared in net.h
#define TCP_FLAGS_ACK_V 16 //as declared in net.h
static byte myip[] = { 192,168,0,66 };
static byte gwip[] = { 192,168,0,250 };
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x39 };
byte Ethernet::buffer[700]; // tcp/ip send and receive buffer
unsigned long cur;
unsigned long pos;
byte res;
void setup() {
// Initialize serial communication at 115200 baud
Serial.begin(115200);
// Initialize tinyFAT
// You might need to select a lower speed than the default SPISPEED_HIGH
file.setSSpin(4);
res=file.initFAT(0);
if (res==NO_ERROR) Serial.println("SD started");
ether.begin(sizeof Ethernet::buffer, mymac , 10); //53 on mega ethernet shield 10 on others
ether.staticSetup(myip, gwip);
Serial.println("ETH started");
}
void loop()
{
wait:
pos = ether.packetLoop(ether.packetReceive());// check if valid tcp data is received
if (pos) {
char* data = (char *) Ethernet::buffer + pos;
cur=0;
if (strncmp("GET / ", data, 6) == 0) {// nothing specified
sendfiles("index.htm");
goto wait;
}
if (strncmp("GET /", data, 5) == 0) { // serve anything on sd card
int i =0;
char temp[15]=""; // here will be the name of requested file
while (data[i+5]!=32) {temp[i]=data[i+5];i++;}//search the end
sendfiles((char*) temp);
goto wait;
}
not_found();
}
}
void not_found() { //content not found
cur=0;
streamfile ("404.hea",TCP_FLAGS_FIN_V);
// Serial.println("not found");
}
byte streamfile (char* name , byte lastflag) { //send a file to the buffer
if (!file.exists(name)) {return 0;}
res=file.openFile(name, FILEMODE_BINARY);
int car=512;
while (car==512) {
car=file.readBinary();
for(int i=0;i<car;i++) {
cur++;
Ethernet::buffer[cur+53]=file.buffer[i];
}
if (cur>=512) {
ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V);
cur=0;
} else {
if (lastflag==TCP_FLAGS_FIN_V) {
ether.httpServerReply_with_flags(cur,TCP_FLAGS_ACK_V+TCP_FLAGS_FIN_V);
}
}
}
file.closeFile();
return 1;
}
byte sendfiles(char* name) { // function to find the correct header and send a file
ether.httpServerReplyAck();
int i =0;
char dtype[13]="";
while (name[i]!=0) {
i++;
}//search the end
int b=i-1;
while ((name[b]!=46)&&(b>0)) {
b--;
}//search the point
int a=b+1;
while (a<i) {
dtype[a-b-1]=name[a];
a++;
}
dtype[a-b-1]='.';
dtype[a-b]='h';
dtype[a-b+1]='e';
dtype[a-b+2]='a';
//Serial.println(dtype); // print the requested header file
if (streamfile ((char *)dtype,0)==0) {
streamfile ("txt.hea",0);
}
//Serial.println(name); // print the requested file
if (streamfile ((char *)name,TCP_FLAGS_FIN_V)==0) {
cur=0;
not_found();
}
/* uncomment this if you want to have printed the ip of the target browser
Serial.print("content send to ");
for(int i=30; i<34; i++) {
Serial.print(Ethernet::buffer[i]);
if (i<33) Serial.print(".");
}
Serial.println(" ");
*/
}

View File

@ -0,0 +1,59 @@
// Example of EtherCard usage, contributed by Will Rose, 2012-07-05.
#include <EtherCard_STM.h>
#include <SPI.h>
#define BUF_SIZE 512
byte mac[] = { 0x00, 0x04, 0xA3, 0x21, 0xCA, 0x38 }; // Nanode MAC address.
uint8_t ip[] = { 192, 168, 1, 203 }; // The fallback board address.
uint8_t dns[] = { 192, 168, 1, 1 }; // The DNS server address.
uint8_t gateway[] = { 192, 168, 1, 1 }; // The gateway router address.
uint8_t subnet[] = { 255, 255, 255, 0 }; // The subnet mask.
byte Ethernet::buffer[BUF_SIZE];
byte fixed; // Address fixed, no DHCP
void setup(void)
{
Serial.begin(57600);
delay(2000);
/* Check that the Ethernet controller exists */
Serial.println("Initialising the Ethernet controller");
if (ether.begin(sizeof Ethernet::buffer, mac) == 0) {
Serial.println( "Ethernet controller NOT initialized");
while (true)
/* MT */ ;
}
/* Get a DHCP connection */
Serial.println("Attempting to get an IP address using DHCP");
fixed = false;
if (ether.dhcpSetup()) {
ether.printIp("Got an IP address using DHCP: ", ether.myip);
}
/* If DHCP fails, start with a hard-coded address */
else {
ether.staticSetup(ip, gateway, dns);
ether.printIp("DHCP FAILED, using fixed address: ", ether.myip);
fixed = true;
}
return;
}
void loop(void)
{
word rc;
/* These function calls are required if ICMP packets are to be accepted */
rc = ether.packetLoop(ether.packetReceive());
Serial.print("ether.packetLoop() returned ");
Serial.println(rc, DEC);
// For debugging
delay(5000);
return;
}

View File

@ -0,0 +1,293 @@
// NoIP client sketch for ENC28J60 based Ethernet Shield.
// You need a free account from www.no-ip.com
//
// 1. On NoIP website, create a host of type DNS Host (A)
// 2. Insert your host name in noIP_host[] variable
// 3. Encode "username:password" in base64 using an online tool like
// 4. Paste the encoded string in noIP_auth[] variable
//
// Contributed by Luca Dentella <luca@dentella.it>
// http://www.lucadentella.it/2012/04/28/enc28j60-e-arduino-6/
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
// Finite-State Machine states
#define STATUS_IDLE 0
#define STATUS_WAITING_FOR_PUBLIC_IP 1
#define STATUS_NOIP_NEEDS_UPDATE 2
#define STATUS_WAITING_FOR_NOIP 3
#define STATUS_ERROR 99
// The sketch will check your public IP every CHECK_IP_INTERVAL ms,
// and wait for REQUEST_TIMEOUT ms for a response.
// It will retry for maximum of MAX_ATTEMPTS attemps.
#define CHECK_IP_INTERVAL 60000
#define REQUEST_TIMEOUT 10000
#define MAX_ATTEMPTS 3
// MAC Address of Ethernet Shield
static byte mymac[] = {0x74,0x69,0x69,0x2D,0x30,0x31};
// Insert your hostname and authentication string
const char noIP_host[] PROGMEM = "<YourDomainName>"; //e.g. myname.no-ip.info
const char noIP_auth[] PROGMEM = "<YourPassword>";
//----------------------------------------------------------
// Don't change these ones...
const char getIP_web[] PROGMEM = "www.lucadentella.it";
const char noIP_web[] PROGMEM = "dynupdate.no-ip.com";
//----------------------------------------------------------
// Some global variables
byte Ethernet::buffer[700];
byte getIP_address[4];
byte noIP_address[4];
byte actual_status;
static byte session_id;
static uint32_t check_ip_timer;
static uint32_t request_timer;
int attempt;
Stash stash;
void setup () {
Serial.begin(57600);
Serial.println(F("NoIP Client Demo"));
Serial.println();
if (!ether.begin(sizeof Ethernet::buffer, mymac))
Serial.println(F( "Failed to access Ethernet controller"));
else
Serial.println(F("Ethernet controller initialized"));
Serial.println();
if (!ether.dhcpSetup())
Serial.println(F("Failed to get configuration from DHCP"));
else
Serial.println(F("DHCP configuration done"));
ether.printIp("IP Address:\t", ether.myip);
ether.printIp("Netmask:\t", ether.netmask);
ether.printIp("Gateway:\t", ether.gwip);
Serial.println();
actual_status = STATUS_IDLE;
attempt = 0;
// Resolve IP for getIP_web and noIP_web
// and store them into global variables
if (!ether.dnsLookup(getIP_web)) {
Serial.print(F("Unable to resolve IP for "));
SerialPrint_P(getIP_web);
actual_status = STATUS_ERROR;
} else {
ether.copyIp(getIP_address, ether.hisip);
SerialPrint_P(getIP_web);
ether.printIp(" resolved to:\t", ether.hisip);
}
if (!ether.dnsLookup(noIP_web)) {
Serial.print(F("Unable to resolve IP for "));
SerialPrint_P(noIP_web);
actual_status = STATUS_ERROR;
} else {
ether.copyIp(noIP_address, ether.hisip);
SerialPrint_P(noIP_web);
ether.printIp(" resolved to:\t", ether.hisip);
}
Serial.println();
}
void loop() {
ether.packetLoop(ether.packetReceive());
// FSM
switch(actual_status) {
case STATUS_IDLE: checkPublicIP(); break;
case STATUS_WAITING_FOR_PUBLIC_IP: checkPublicIPResponse(); break;
case STATUS_NOIP_NEEDS_UPDATE: updateNoIP(); break;
case STATUS_WAITING_FOR_NOIP: checkNoIPResponse(); break;
}
}
void checkPublicIP() {
if(millis() > check_ip_timer) {
Serial.print(F("Checking public IP... "));
// Create a request for GetIP service,
// set destination IP and send request saving session_id
Stash::prepare(PSTR("GET /demo/getip.php HTTP/1.1" "\r\n" "Host: $F" "\r\n" "\r\n"), getIP_web);
ether.copyIp(ether.hisip, getIP_address);
session_id = ether.tcpSend();
// Change FSM state, prepare for timeout and increment attempts counter
actual_status = STATUS_WAITING_FOR_PUBLIC_IP;
request_timer = millis() + REQUEST_TIMEOUT;
attempt++;
}
}
void checkPublicIPResponse() {
String actualIp, dnsIp;
const char* reply = ether.tcpReply(session_id);
// We got a valid response
if(reply != 0) {
// Parse response for public IP
for(int i = 0; i < strlen(reply) - 189; i++) actualIp = actualIp + reply[187 + i];
Serial.println(actualIp);
// If we can't resolve actual IP for our hostname on NoIP,
// return to IDLE state and wait for the next interval
if(!ether.dnsLookup(noIP_host)) {
Serial.print(F("Unable to resolve actual IP for "));
SerialPrint_P(noIP_host);
Serial.println();
actual_status = STATUS_IDLE;
attempt = 0;
check_ip_timer = millis() + CHECK_IP_INTERVAL;
// If we can resolve the IP for our hostname, save it in xxx.xxx.xxx.xxx form
// and compare it with our public IP
} else {
for(int i = 0; i < 4; i++) {
dnsIp = dnsIp + String(ether.hisip[i]);
if(i < 3) dnsIp = dnsIp + ".";
}
SerialPrint_P(noIP_host);
Serial.print(F(" resolved to "));
Serial.println(dnsIp);
// If they are the same, we can sit down and wait for the next interval
if(actualIp.compareTo(dnsIp) == 0) {
Serial.println(F("No update needed :)"));
actual_status = STATUS_IDLE;
attempt = 0;
check_ip_timer = millis() + CHECK_IP_INTERVAL;
// Different? We'd better to update NoIP!
} else {
Serial.println(F("Update needed :("));
actual_status = STATUS_NOIP_NEEDS_UPDATE;
attempt = 0;
}
}
// No valid response? Check for timeout
// If we've already sent a max number of requests, return to IDLE state
// and wait for the next interval
} else {
if(millis() > request_timer) {
Serial.println(F(" no response :("));
actual_status = STATUS_IDLE;
if(attempt == MAX_ATTEMPTS) {
Serial.println(F("Max number of attempts reached"));
attempt = 0;
check_ip_timer = millis() + CHECK_IP_INTERVAL;
}
}
}
}
void updateNoIP() {
Serial.print(F("Updating NoIP..."));
// Create a request for updating NoIP using NoIP API,
// set destination IP and send request saving session_id
Stash::prepare(PSTR("GET /nic/update?hostname=$F HTTP/1.0" "\r\n"
"Host: $F" "\r\n"
"Authorization: Basic $F" "\r\n"
"User-Agent: NoIP_Client" "\r\n" "\r\n"),
noIP_host, noIP_web, noIP_auth);
ether.copyIp(ether.hisip, noIP_address);
session_id = ether.tcpSend();
// Wait for response or timeout...
actual_status = STATUS_WAITING_FOR_NOIP;
request_timer = millis() + REQUEST_TIMEOUT;
attempt++;
}
void checkNoIPResponse() {
const char* reply = ether.tcpReply(session_id);
boolean done;
// We got a valid response...
if(reply != 0) {
// Parse NoIP response looking for status/error codes...
if(strstr(reply, "good") != 0) {
Serial.println(F(" done!"));
done = true;
}
else if(strstr(reply, "nochg") != 0) {
Serial.println(F(" no change required!"));
done = true;
}
else if(strstr(reply, "nohost") != 0) Serial.println(F(" host not found :("));
else if(strstr(reply, "badauth") != 0) Serial.println(F(" invalid username or password :("));
else if(strstr(reply, "badagent") != 0) Serial.println(F(" agent banned :("));
else if(strstr(reply, "!donator") != 0) Serial.println(F(" feature not available for specified username :("));
else if(strstr(reply, "abuse") != 0) Serial.println(F(" username blocked due to abuse :("));
else Serial.println(F(" generic error :("));
// Record has been updated? Ok wait for next interval...
if(done) {
actual_status = STATUS_IDLE;
attempt = 0;
check_ip_timer = millis() + CHECK_IP_INTERVAL;
}
// No valid response? Check for timeout
// If we've already sent a max number of requests, return to IDLE state
// and wait for the next interval
} else {
if(millis() > request_timer) {
Serial.println(F("No response from NoIP"));
if(attempt == MAX_ATTEMPTS) {
Serial.println(F("Max number of attempts reached"));
actual_status = STATUS_IDLE;
attempt = 0;
check_ip_timer = millis() + CHECK_IP_INTERVAL;
}
else
actual_status = STATUS_NOIP_NEEDS_UPDATE;
}
}
}
void SerialPrint_P(PGM_P str) {
for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
}

View File

@ -0,0 +1,96 @@
// Ping a remote server, also uses DHCP and DNS.
// 2011-06-12 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <SPI.h>
#include <EtherCard_STM.h>
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
static byte myip[] = { 192,168,1,203 };
// gateway ip address
static byte gwip[] = { 192,168,1,1 };
// domain name server (dns) address
static byte dnsip[] = { 192,168,1,1 };
// called when a ping comes in (replies to it are automatic)
static void gotPinged (byte* ptr) {
ether.printIp(">>> ping from: ", ptr);
}
void setup () {
Serial.begin(57600);
delay(10);
Serial.println("\n[pings]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(("Failed to access Ethernet controller"));
if (!ether.dhcpSetup()){//If DHCP fails set the static IP, Gateway and DNS IP.
Serial.println(F("DHCP failed"));
ether.staticSetup(myip, gwip);
ether.copyIp(ether.dnsip, dnsip);
}
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
//#if 1
// use DNS to locate the IP address we want to ping
if (!ether.dnsLookup(PSTR("www.google.com")))
Serial.println("DNS failed");
//#else
//ether.parseIp(ether.hisip, "173.194.112.119");
//#endif
ether.printIp("SRV: ", ether.hisip);
// call this to report others pinging us
ether.registerPingCallback(gotPinged);
timer = -9999999; // start timing out right away
Serial.println();
}
void loop () {
word len = ether.packetReceive(); // go receive new packets
word pos = ether.packetLoop(len); // respond to incoming pings
// report whenever a reply to our outgoing ping comes back
if (len > 0 && ether.packetLoopIcmpCheckReply(ether.hisip)) {
Serial.print(" ");
Serial.print((micros() - timer) * 0.001, 3);
Serial.println(" ms");
}
// ping a remote server once every few seconds
if (micros() - timer >= 5000000) {
ether.printIp("Pinging: ", ether.hisip);
timer = micros();
ether.clientIcmpRequest(ether.hisip);
}
}

View File

@ -0,0 +1,72 @@
// This is a demo of the RBBB running as webserver with the Ether Card
// 2010-05-28 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
static byte myip[] = { 192,168,1,203 };
byte Ethernet::buffer[500];
BufferFiller bfill;
void setup () {
Serial.begin(57600);
delay(10);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
ether.staticSetup(myip);
//if (!ether.dhcpSetup())
// Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
}
static word homePage() {
long t = millis() / 1000;
word h = t / 3600;
byte m = (t / 60) % 60;
byte s = t % 60;
bfill = ether.tcpOffset();
bfill.emit_p(PSTR(
"HTTP/1.0 200 OK\r\n"
"Content-Type: text/html\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"<meta http-equiv='refresh' content='1'/>"
"<title>RBBB server</title>"
"<h1>$D$D:$D$D:$D$D</h1>"),
h/10, h%10, m/10, m%10, s/10, s%10);
return bfill.position();
}
void loop () {
if (ether.packetLoop(ether.packetReceive())){ // check if valid tcp data is received
ether.httpServerReply(homePage()); // send web page data
}
}

View File

@ -0,0 +1,119 @@
// Test the offloaded RAM stash mechanism.
// 2011-07-10 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
#include <EtherCard_STM.h>
#include <SPI.h>
// ethernet interface mac address, must be unique on the LAN
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
void dumpBlock (const char* msg, byte idx) {
Serial.print(msg);
Serial.print(" [");
Serial.print(idx, DEC);
Serial.print("] @ ");
Serial.print(Stash::bufs[idx].bnum, DEC);
Serial.print(" free ");
Serial.print(Stash::freeCount(), DEC);
for (byte i = 0; i < 64; ++i) {
if (i % 16 == 0)
Serial.println();
Serial.print(' ');
Serial.print(Stash::bufs[idx].bytes[i], DEC);
}
Serial.println();
}
void dumpStash (const char* msg, void* ptr) {
Stash& buf = *(Stash*) ptr;
Serial.print(msg);
Serial.print(" c");
Serial.print(buf.count, DEC);
Serial.print(" f");
Serial.print(buf.first, DEC);
Serial.print(" l");
Serial.print(buf.last, DEC);
Serial.print(" u");
Serial.print(buf.curr, DEC);
Serial.print(" o");
Serial.print(buf.offs, DEC);
Serial.print(" #");
Serial.println(buf.size());
}
void setup () {
Serial.begin(57600);
delay(1);
Serial.println("\n[stashTest]");
ether.begin(sizeof Ethernet::buffer, mymac);
#if 1
Stash buf;
dumpStash("> AAA", &buf);
byte fd = buf.create();
Serial.print("fd ");
Serial.println(fd, DEC);
dumpStash("> BBB", &buf);
dumpBlock("EMPTY", 0);
for (char c = 'a'; c <= 'z'; ++c)
buf.put(c);
for (char c = 'A'; c <= 'Z'; ++c)
buf.put(c);
dumpBlock("LETTERS", 0);
dumpStash("> CCC", &buf);
for (char c = '0'; c <= '9'; ++c)
buf.put(c);
dumpBlock("DIGITS", 0);
dumpStash("> DDD", &buf);
buf.print(" x = ");
buf.println(123.45);
dumpBlock("PRINT", 0);
dumpStash("> EEE", &buf);
buf.load(1, 1);
dumpBlock("FIRST", 1);
buf.save();
buf.load(1, 1);
dumpBlock("FLUSHED", 1);
dumpStash("> FFF", &buf);
for (;;) {
char c = buf.get();
if (c == 0)
break;
Serial.print(c);
}
Serial.println();
dumpStash("> GGG", &buf);
#endif
Stash buf2;
byte fd2 = buf2.create();
buf2.print("<XYZ>");
buf2.save();
buf2.load(1, fd2);
dumpBlock("SECOND", 1);
dumpStash("> HHH", &buf2);
Stash::prepare(PSTR("a $S b $F c $D d $H e"),
"123", PSTR("4567"), -12345, fd2);
dumpBlock("BUFFER", 0);
Serial.println(Stash::length());
for (word i = 0, n = Stash::length(); i < n; ++i) {
char c;
Stash::extract(i, 1, &c);
Serial.print(c);
}
Serial.println();
Stash::cleanup();
#if 1
buf.release();
#endif
Serial.print("free ");
Serial.println(Stash::freeCount(), DEC);
Serial.println("DONE");
}
void loop () {
// ether.packetLoop(ether.packetReceive());
}

View File

@ -0,0 +1,60 @@
// Arduino demo sketch for testing the DHCP client code
//
// Original author: Andrew Lindsay
// Major rewrite and API overhaul by jcw, 2011-06-07
//
// Copyright: GPL V2
// See http://www.gnu.org/licenses/gpl.html
//
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <SPI.h>
#include <EtherCard_STM.h>
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
void setup () {
Serial.begin(57600);
Serial.println(F("\n[testDHCP]"));
Serial.print("MAC: ");
for (byte i = 0; i < 6; ++i) {
Serial.print(mymac[i], HEX);
if (i < 5)
Serial.print(':');
}
Serial.println();
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
Serial.println(F("Setting up DHCP"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
ether.printIp("My IP: ", ether.myip);
ether.printIp("Netmask: ", ether.netmask);
ether.printIp("GW IP: ", ether.gwip);
ether.printIp("DNS IP: ", ether.dnsip);
}
void loop () {}

View File

@ -0,0 +1,85 @@
// Twitter client sketch for ENC28J60 based Ethernet Shield. Uses
// arduino-tweet.appspot.com as a OAuth gateway.
// Step by step instructions:
//
// 1. Get a oauth token:
// http://arduino-tweet.appspot.com/oauth/twitter/login
// 2. Put the token value in the TOKEN define below
// 3. Run the sketch!
//
// WARNING: Don't send more than 1 tweet per minute!
// NOTE: Twitter rejects tweets with identical content as dupes (returns 403)
#include <SPI.h>
#include <EtherCard_STM.h>
// OAUTH key from http://arduino-tweet.appspot.com/
#define TOKEN "Insert-your-token-here"
// ethernet interface mac address, must be unique on the LAN
byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
const char website[] PROGMEM = "arduino-tweet.appspot.com";
static byte session;
byte Ethernet::buffer[700];
Stash stash;
static void sendToTwitter () {
Serial.println("Sending tweet...");
byte sd = stash.create();
const char tweet[] = "@solarkennedy the test Twitter sketch works!";
stash.print("token=");
stash.print(TOKEN);
stash.print("&status=");
stash.println(tweet);
stash.save();
int stash_size = stash.size();
// Compose the http POST request, taking the headers below and appending
// previously created stash in the sd holder.
Stash::prepare(PSTR("POST http://$F/update HTTP/1.0" "\r\n"
"Host: $F" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"),
website, website, stash_size, sd);
// send the packet - this also releases all stash buffers once done
// Save the session ID so we can watch for it in the main loop.
session = ether.tcpSend();
}
void setup () {
Serial.begin(57600);
Serial.println("\n[Twitter Client]");
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println(F("DNS failed"));
ether.printIp("SRV: ", ether.hisip);
sendToTwitter();
}
void loop () {
ether.packetLoop(ether.packetReceive());
const char* reply = ether.tcpReply(session);
if (reply != 0) {
Serial.println("Got a response!");
Serial.println(reply);
}
}

View File

@ -0,0 +1,29 @@
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class UDPClient {
public static void main(String[] args) throws UnknownHostException {
DatagramSocket s;
byte[] sendBuffer = new byte[1024];
DatagramPacket sendPacket;
final InetAddress ADDRESS = InetAddress.getByName("localhost");
final int PORT = 1234;
try {
s = new DatagramSocket();
System.out.println("Odesilam data na server...");
sendBuffer = "abc123".getBytes();
sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length,
ADDRESS, PORT);
s.send(sendPacket);
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,39 @@
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class UDPserver {
public static void main(String[] args) {
UDPserver server = new UDPserver(1234);
server.start();
}
private int port;
private DatagramSocket s;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public UDPserver(int port) {
this.port = port;
}
public void start() {
System.out.println("SERVER: Waiting for incomming connections...");
System.out.println("DATE TIME IP:PORT received_data");
try {
s = new DatagramSocket(this.port);
while (true) {
byte[] data = new byte[1412];
DatagramPacket p = new DatagramPacket(data,
data.length);
s.receive(p);
System.out.print(sdf.format(new Date()).toString() + " ");
System.out.print(p.getSocketAddress() + " ");
System.out.println(new String(p.getData()));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,40 @@
#include <SPI.h>
#include <EtherCard_STM.h>
static byte mymac[] = { 0x1A,0x2B,0x3C,0x4D,0x5E,0x6F };
byte Ethernet::buffer[700];
static uint32_t timer;
char website[] PROGMEM = "server.example.net";
const int dstPort PROGMEM = 1234;
const int srcPort PROGMEM = 4321;
void setup () {
Serial.begin(9600);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println( "Failed to access Ethernet controller");
if (!ether.dhcpSetup())
Serial.println("DHCP failed");
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("SRV: ", ether.hisip);
}
char textToSend[] = "test 123";
void loop () {
if (millis() > timer) {
timer = millis() + 5000;
//static void sendUdp (char *data,uint8_t len,uint16_t sport, uint8_t *dip, uint16_t dport);
ether.sendUdp(textToSend, sizeof(textToSend), srcPort, ether.hisip, dstPort );
}
}

View File

@ -0,0 +1,101 @@
// Demonstrates usage of the new udpServer feature.
//You can register the same function to multiple ports, and multiple functions to the same port.
//
// 2013-4-7 Brian Lee <cybexsoft@hotmail.com>
//*************************************************************
//
// IT DOESN'T WORK ON STM32 YET (IS NOT PORTED YET).
//
//*************************************************************
#include <EtherCard_STM.h>
#include <IPAddress.h>
#define STATIC 0 // set to 1 to disable DHCP (adjust myip/gwip values below)
#if STATIC
// ethernet interface ip address
static byte myip[] = { 192,168,0,200 };
// gateway ip address
static byte gwip[] = { 192,168,0,1 };
#endif
// ethernet mac address - must be unique on your network
static byte mymac[] = { 0x70,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[500]; // tcp/ip send and receive buffer
//callback that prints received packets to the serial port
void udpSerialPrint(word port, byte ip[4], const char *data, word len) {
IPAddress src(ip[0], ip[1], ip[2], ip[3]);
Serial.println(src);
Serial.println(port);
Serial.println(data);
Serial.println(len);
}
void setup(){
Serial.begin(57600);
Serial.println(F("\n[backSoon]"));
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
#if STATIC
ether.staticSetup(myip, gwip);
#else
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
#endif
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
//register udpSerialPrint() to port 1337
ether.udpServerListenOnPort(&udpSerialPrint, 1337);
//register udpSerialPrint() to port 42.
ether.udpServerListenOnPort(&udpSerialPrint, 42);
}
void loop(){
//this must be called for ethercard functions to work.
ether.packetLoop(ether.packetReceive());
}
/*
//Processing sketch to send test UDP packets.
import hypermedia.net.*;
UDP udp; // define the UDP object
void setup() {
udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000
//udp.log( true ); // <-- printout the connection activity
udp.listen( true ); // and wait for incoming message
}
void draw()
{
}
void keyPressed() {
String ip = "192.168.0.200"; // the remote IP address
int port = 1337; // the destination port
udp.send("Greetings via UDP!", ip, port ); // the message to send
}
void receive( byte[] data ) { // <-- default handler
//void receive( byte[] data, String ip, int port ) { // <-- extended handler
for(int i=0; i < data.length; i++)
print(char(data[i]));
println();
}
*/

View File

@ -0,0 +1,69 @@
// Demo using DHCP and DNS to perform a web client request.
// 2011-06-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <SPI.h>
#include <EtherCard_STM.h>
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[700];
static uint32_t timer;
const char website[] PROGMEM = "www.google.com";
// called when the client request is complete
static void my_callback (byte status, uint16_t off, uint16_t len) {
Serial.println(">>>");
Ethernet::buffer[off+300] = 0;
Serial.print((const char*) Ethernet::buffer + off);
Serial.println("...");
}
void setup () {
Serial.begin(57600);
Serial.println(F("\n[webClient]"));
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0)
Serial.println(F("Failed to access Ethernet controller"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("SRV: ", ether.hisip);
}
void loop () {
ether.packetLoop(ether.packetReceive());
if (millis() > timer) {
timer = millis() + 5000;
Serial.println();
Serial.print("<<< REQ ");
ether.browseUrl(PSTR("/foo/"), "bar", website, my_callback);
}
}

View File

@ -0,0 +1,158 @@
// Simple demo for feeding some random data to Pachube.
// 2011-07-08 <jc@wippler.nl> http://opensource.org/licenses/mit-license.php
// Handle returning code and reset ethernet module if needed
// 2013-10-22 hneiraf@gmail.com
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
//
//
#include <EtherCard_STM.h>
#include <SPI.h>
// change these settings to match your own setup
#define FEED "12345678" //Write here your FEED key (look at "Feed Keys" on xively.
#define APIKEY "asgEEwewtwerweTRRWER323SSDFfds" //Write your own APIKEY.
// ethernet interface mac address, must be unique on the LAN
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
const char website[] PROGMEM = "api.xively.com";
byte Ethernet::buffer[350];
uint32_t timer;
Stash stash;
byte session;
//timing variable
int res = 0;
void setup () {
Serial.begin(57600);
Serial.println("\n[Xively example]");
//Initialize Ethernet
initialize_ethernet();
}
void loop () {
//if correct answer is not received then re-initialize ethernet module
if (res > 220){
initialize_ethernet();
}
res = res + 1;
ether.packetLoop(ether.packetReceive());
//200 res = 10 seconds (50ms each res)
if (res == 200) {
//Generate random info
float demo = random(0,500);
word one = random(0,500);
String msje;
if (demo < 250){
msje = "low";
}
else{
msje = "high";
}
// generate two fake values as payload - by using a separate stash,
// we can determine the size of the generated message ahead of time
byte sd = stash.create();
stash.print("demo,");
stash.println(demo);
stash.print("one,");
stash.println(one);
stash.print("mensaje,");
stash.println(msje);
stash.save();
//Display data to be sent
Serial.println(demo);
Serial.println(one);
// generate the header with payload - note that the stash size is used,
// and that a "stash descriptor" is passed in as argument using "$H"
Stash::prepare(PSTR("PUT http://$F/v2/feeds/$F.csv HTTP/1.0" "\r\n"
"Host: $F" "\r\n"
"X-PachubeApiKey: $F" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"),
website, PSTR(FEED), website, PSTR(APIKEY), stash.size(), sd);
// send the packet - this also releases all stash buffers once done
session = ether.tcpSend();
}
const char* reply = ether.tcpReply(session);
if (reply != 0) {
res = 0;
Serial.println(reply);
}
delay(50);
}
void initialize_ethernet(void){
for(;;){ // keep trying until you succeed
//Reinitialize ethernet module
pinMode(5, OUTPUT);
Serial.println("Reseting Ethernet...");
digitalWrite(5, LOW);
delay(1000);
digitalWrite(5, HIGH);
delay(500);
if (ether.begin(sizeof Ethernet::buffer, mymac) == 0){
Serial.println( "Failed to access Ethernet controller");
continue;
}
if (!ether.dhcpSetup()){
Serial.println("DHCP failed");
continue;
}
ether.printIp("IP: ", ether.myip);
ether.printIp("GW: ", ether.gwip);
ether.printIp("DNS: ", ether.dnsip);
if (!ether.dnsLookup(website))
Serial.println("DNS failed");
ether.printIp("SRV: ", ether.hisip);
//reset init value
res = 0;
break;
}
}

View File

@ -0,0 +1,53 @@
#######################################
# Syntax Coloring Map EtherCard_STM
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
EtherCard_STM KEYWORD1
ether KEYWORD1
BufferFiller KEYWORD1
Stash KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
emit_p KEYWORD2
emit_raw KEYWORD2
emit_raw_p KEYWORD2
buffer KEYWORD2
Ethernet KEYWORD2
printIp KEYWORD2
staticSetup KEYWORD2
dhcpSetup KEYWORD2
packetLoop KEYWORD2
packetReceive KEYWORD2
httpServerReply KEYWORD2
browseUrl KEYWORD2
memcpy_P KEYWORD2
tcpOffset KEYWORD2
tcpSend KEYWORD2
tcpReply KEYWORD2
dnsLookup KEYWORD2
httpServerReply KEYWORD2
sizeof KEYWORD2
SerialPrint_P KEYWORD2
copyIp KEYWORD2
getIP_address KEYWORD2
hisip KEYWORD2
myip KEYWORD2
gwip KEYWORD2
mymask KEYWORD2
dnsip KEYWORD2
cleanup KEYWORD2
freeCount KEYWORD2
extract KEYWORD2
save KEYWORD2
size KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
STATUS_ERROR LITERAL1

View File

@ -0,0 +1,8 @@
name=Serasidis_EtherCard_STM
version=1.0
author=(Original) Jean-Claude Wippler :: Ported to STM32 by Vassilis Serasidis.
email=
sentence=ENC28J60 Ethernet module library
paragraph=Ethernet module library for STM32F1
url=https://github.com/Serasidis/STM32duino/tree/master/libraries/Serasidis_EtherCard_STM
architectures=STM32F1

View File

@ -0,0 +1,73 @@
/* Get rid of all those overriden font families */
body, table, div, p, dl,
#projectname,
#projectbrief,
#nav-tree .label {
font: 15px/21px Georgia,serif
}
#projectname {
color: #990000;
font-weight: bold;
font-size: 24px;
}
#titlearea table {
padding: 20px;
}
dl.reflist dt, div.memproto {
border: 1px solid #A8B8D9;
}
dl.reflist dd, div.memdoc {
border-width: 0;
}
div.contents {
margin-left: 20px; margin-right: 16px;
width: 700 px;
}
/* Get rid of the gradient backgrounds and background colors */
div.header,
#nav-tree,
.navpath ul,
.memproto, dl.reflist dt {
background: none;
}
#nav-tree .selected {
background: none;
background-color: #990000;
text-shadow: none;
}
a, a:link, a:visited {
color: #2A5685;
text-decoration: underline;
}
a:active, a:hover {
color: #CC0000;
}
.directory tr.even,
pre.fragment,
.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams,
.memproto, dl.reflist dt {
background-color: #EEE;
box-shadow: none;
border-radius: 0;
}
.memdoc, dl.reflist dd {
background: none;
box-shadow: none;
border-radius: 0;
}
pre.fragment {
background-color: #FAFAFA;
border: 1px solid #DADADA;
margin: 1em 1em 1em 1.6em;
overflow-x: auto;
overflow-y: hidden;
width: auto;
}

View File

@ -0,0 +1,433 @@
// This code slightly follows the conventions of, but is not derived from:
// EHTERSHIELD_H library for Arduino etherShield
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
// It is however derived from the enc28j60 and ip code (which is GPL v2)
// Author: Pascal Stang
// Modified by: Guido Socher
// DHCP code: Andrew Lindsay
// Hence: GPL V2
//
// 2010-05-19 <jc@wippler.nl>
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
#include <EtherCard_STM.h>
#include <stdarg.h>
//#include <avr/eeprom.h>
//#define FLOATEMIT // uncomment line to enable $T in emit_P for float emitting
byte Stash::map[256/8];
Stash::Block Stash::bufs[2];
uint8_t Stash::allocBlock () {
for (uint8_t i = 0; i < sizeof map; ++i)
if (map[i] != 0)
for (uint8_t j = 0; j < 8; ++j)
if (bitRead(map[i], j)) {
bitClear(map[i], j);
return (i << 3) + j;
}
return 0;
}
void Stash::freeBlock (uint8_t block) {
bitSet(map[block>>3], block & 7);
}
uint8_t Stash::fetchByte (uint8_t blk, uint8_t off) {
return blk == bufs[0].bnum ? bufs[0].bytes[off] :
blk == bufs[1].bnum ? bufs[1].bytes[off] :
ether.peekin(blk, off);
}
void Stash::initMap (uint8_t last) {
while (--last > 0)
freeBlock(last);
}
void Stash::load (uint8_t idx, uint8_t blk) {
if (blk != bufs[idx].bnum) {
if (idx == 0) {
ether.copyout(bufs[idx].bnum, bufs[idx].bytes);
if (blk == bufs[1].bnum)
bufs[1].bnum = 255; // forget read page if same
} else if (blk == bufs[0].bnum) {
// special case: read page is same as write buffer
memcpy(&bufs[1], &bufs[0], sizeof bufs[0]);
return;
}
bufs[idx].bnum = blk;
ether.copyin(bufs[idx].bnum, bufs[idx].bytes);
}
}
uint8_t Stash::freeCount () {
uint8_t count = 0;
for (uint8_t i = 0; i < 256/8; ++i)
for (uint8_t m = 0x80; m != 0; m >>= 1)
if (map[i] & m)
++count;
return count;
}
uint8_t Stash::create () {
uint8_t blk = allocBlock();
load(0, blk);
bufs[0].head.count = 0;
bufs[0].head.first = bufs[0].head.last = blk;
bufs[0].tail = sizeof (StashHeader);
bufs[0].next = 0;
return open(blk);
}
uint8_t Stash::open (uint8_t blk) {
curr = blk;
offs = sizeof (StashHeader);
load(1, curr);
memcpy((StashHeader*) this, bufs[1].bytes, sizeof (StashHeader));
return curr;
}
void Stash::save () {
load(0, first);
memcpy(bufs[0].bytes, (StashHeader*) this, sizeof (StashHeader));
if (bufs[1].bnum == first)
load(1, 0); // invalidates original in case it was the same block
}
void Stash::release () {
while (first > 0) {
freeBlock(first);
first = ether.peekin(first, 63);
}
}
void Stash::put (char c) {
load(0, last);
uint8_t t = bufs[0].tail;
bufs[0].bytes[t++] = c;
if (t <= 62)
bufs[0].tail = t;
else {
bufs[0].next = allocBlock();
last = bufs[0].next;
load(0, last);
bufs[0].tail = bufs[0].next = 0;
++count;
}
}
char Stash::get () {
load(1, curr);
if (curr == last && offs >= bufs[1].tail)
return 0;
uint8_t b = bufs[1].bytes[offs];
if (++offs >= 63 && curr != last) {
curr = bufs[1].next;
offs = 0;
}
return b;
}
uint16_t Stash::size () {
return 63 * count + fetchByte(last, 62) - sizeof (StashHeader);
}
static char* wtoa (uint16_t value, char* ptr) {
if (value > 9)
ptr = wtoa(value / 10, ptr);
*ptr = '0' + value % 10;
*++ptr = 0;
return ptr;
}
void Stash::prepare (PGM_P fmt, ...) {
Stash::load(0, 0);
uint16_t* segs = Stash::bufs[0].words;
*segs++ = strlen_P(fmt);
#ifdef __AVR__
*segs++ = (uint16_t) fmt;
#else
*segs++ = (uint32_t) fmt;
*segs++ = (uint32_t) fmt >> 16;
#endif
va_list ap;
va_start(ap, fmt);
for (;;) {
char c = pgm_read_byte(fmt++);
if (c == 0)
break;
if (c == '$') {
#ifdef __AVR__
uint16_t argval = va_arg(ap, uint16_t), arglen = 0;
#else
uint32_t argval = va_arg(ap, int), arglen = 0;
#endif
switch (pgm_read_byte(fmt++)) {
case 'D': {
char buf[7];
wtoa(argval, buf);
arglen = strlen(buf);
break;
}
case 'S':
arglen = strlen((const char*) argval);
break;
case 'F':
arglen = strlen_P((PGM_P) argval);
break;
case 'E': {
byte* s = (byte*) argval;
char d;
//while ((d = eeprom_read_byte(s++)) != 0)
// ++arglen;
break;
}
case 'H': {
Stash stash (argval);
arglen = stash.size();
break;
}
}
#ifdef __AVR__
*segs++ = argval;
#else
*segs++ = argval;
*segs++ = argval >> 16;
#endif
Stash::bufs[0].words[0] += arglen - 2;
}
}
va_end(ap);
}
uint16_t Stash::length () {
Stash::load(0, 0);
return Stash::bufs[0].words[0];
}
void Stash::extract (uint16_t offset, uint16_t count, void* buf) {
Stash::load(0, 0);
uint16_t* segs = Stash::bufs[0].words;
#ifdef __AVR__
PGM_P fmt = (PGM_P) *++segs;
#else
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
segs += 2;
#endif
Stash stash;
char mode = '@', tmp[7], *ptr = NULL, *out = (char*) buf;
for (uint16_t i = 0; i < offset + count; ) {
char c = 0;
switch (mode) {
case '@': {
c = pgm_read_byte(fmt++);
if (c == 0)
return;
if (c != '$')
break;
#ifdef __AVR__
uint16_t arg = *++segs;
#else
uint32_t arg = *++segs;
arg |= *++segs << 16;
#endif
mode = pgm_read_byte(fmt++);
switch (mode) {
case 'D':
wtoa(arg, tmp);
ptr = tmp;
break;
case 'S':
case 'F':
case 'E':
ptr = (char*) arg;
break;
case 'H':
stash.open(arg);
ptr = (char*) &stash;
break;
}
continue;
}
case 'D':
case 'S':
c = *ptr++;
break;
case 'F':
c = pgm_read_byte(ptr++);
break;
case 'E':
//c = eeprom_read_byte((byte*) ptr++);
break;
case 'H':
c = ((Stash*) ptr)->get();
break;
}
if (c == 0) {
mode = '@';
continue;
}
if (i >= offset)
*out++ = c;
++i;
}
}
void Stash::cleanup () {
Stash::load(0, 0);
uint16_t* segs = Stash::bufs[0].words;
#ifdef __AVR__
PGM_P fmt = (PGM_P) *++segs;
#else
PGM_P fmt = (PGM_P)((segs[2] << 16) | segs[1]);
segs += 2;
#endif
for (;;) {
char c = pgm_read_byte(fmt++);
if (c == 0)
break;
if (c == '$') {
#ifdef __AVR__
uint16_t arg = *++segs;
#else
uint32_t arg = *++segs;
arg |= *++segs << 16;
#endif
if (pgm_read_byte(fmt++) == 'H') {
Stash stash (arg);
stash.release();
}
}
}
}
void BufferFiller::emit_p(PGM_P fmt, ...) {
va_list ap;
va_start(ap, fmt);
for (;;) {
char c = pgm_read_byte(fmt++);
if (c == 0)
break;
if (c != '$') {
*ptr++ = c;
continue;
}
c = pgm_read_byte(fmt++);
switch (c) {
case 'D':
#ifdef __AVR__
wtoa(va_arg(ap, uint16_t), (char*) ptr);
#else
wtoa(va_arg(ap, int), (char*) ptr);
#endif
break;
#ifdef FLOATEMIT
case 'T':
dtostrf ( va_arg(ap, double), 10, 3, (char*)ptr );
break;
#endif
case 'H': {
#ifdef __AVR__
char p1 = va_arg(ap, uint16_t);
#else
char p1 = va_arg(ap, int);
#endif
char p2;
p2 = (p1 >> 4) & 0x0F;
p1 = p1 & 0x0F;
if (p1 > 9) p1 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
p1 += 0x30; // and complete
if (p2 > 9) p2 += 0x07; // adjust 0x0a-0x0f to come out 'a'-'f'
p2 += 0x30; // and complete
*ptr++ = p2;
*ptr++ = p1;
continue;
}
case 'L':
//ltoa(va_arg(ap, long), (char*) ptr, 10);
break;
case 'S':
strcpy((char*) ptr, va_arg(ap, const char*));
break;
case 'F': {
PGM_P s = va_arg(ap, PGM_P);
char d;
while ((d = pgm_read_byte(s++)) != 0)
*ptr++ = d;
continue;
}
case 'E': {
byte* s = va_arg(ap, byte*);
char d;
//while ((d = eeprom_read_byte(s++)) != 0)
// *ptr++ = d;
continue;
}
default:
*ptr++ = c;
continue;
}
ptr += strlen((char*) ptr);
}
va_end(ap);
}
EtherCard ether;
uint8_t EtherCard::mymac[6]; // my MAC address
uint8_t EtherCard::myip[4]; // my ip address
uint8_t EtherCard::netmask[4]; // subnet mask
uint8_t EtherCard::broadcastip[4]; // broadcast address
uint8_t EtherCard::gwip[4]; // gateway
uint8_t EtherCard::dhcpip[4]; // dhcp server
uint8_t EtherCard::dnsip[4]; // dns server
uint8_t EtherCard::hisip[4]; // ip address of remote host
uint16_t EtherCard::hisport = 80; // tcp port to browse to
bool EtherCard::using_dhcp = false;
bool EtherCard::persist_tcp_connection = false;
uint16_t EtherCard::delaycnt = 0; //request gateway ARP lookup
uint8_t EtherCard::begin (const uint16_t size,
const uint8_t* macaddr,
uint8_t csPin) {
using_dhcp = false;
Stash::initMap(56);
copyMac(mymac, macaddr);
return initialize(size, mymac, csPin);
}
bool EtherCard::staticSetup (const uint8_t* my_ip,
const uint8_t* gw_ip,
const uint8_t* dns_ip,
const uint8_t* mask) {
using_dhcp = false;
if (my_ip != 0)
copyIp(myip, my_ip);
if (gw_ip != 0)
setGwIp(gw_ip);
if (dns_ip != 0)
copyIp(dnsip, dns_ip);
if(mask != 0)
copyIp(netmask, mask);
updateBroadcastAddress();
delaycnt = 0; //request gateway ARP lookup
return true;
}

View File

@ -0,0 +1,595 @@
// This code slightly follows the conventions of, but is not derived from:
// EHTERSHIELD_H library for Arduino etherShield
// Copyright (c) 2008 Xing Yu. All right reserved. (this is LGPL v2.1)
// It is however derived from the enc28j60 and ip code (which is GPL v2)
// Author: Pascal Stang
// Modified by: Guido Socher
// DHCP code: Andrew Lindsay
// Hence: GPL V2
//
// 2010-05-19 <jc@wippler.nl>
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
#ifndef EtherCard_STM_h
#define EtherCard_STM_h
#ifndef __PROG_TYPES_COMPAT__
#define __PROG_TYPES_COMPAT__
#endif
#if ARDUINO >= 100
#include <Arduino.h> // Arduino 1.0
#define WRITE_RESULT size_t
#define WRITE_RETURN return 1;
#else
#include <WProgram.h> // Arduino 0022
#define WRITE_RESULT void
#define WRITE_RETURN
#endif
#include <avr/pgmspace.h>
#include "enc28j60.h"
#include "net.h"
/** This type definition defines the structure of a UDP server event handler callback funtion */
typedef void (*UdpServerCallback)(
uint16_t dest_port, ///< Port the packet was sent to
uint8_t src_ip[4], ///< IP address of the sender
uint16_t src_port, ///< Port the packet was sent from
const char *data, ///< UDP payload data
uint16_t len); ///< Length of the payload data
/** This type definition defines the structure of a DHCP Option callback funtion */
typedef void (*DhcpOptionCallback)(
uint8_t option, ///< The option number
const byte* data, ///< DHCP option data
uint8_t len); ///< Length of the DHCP option data
/** This structure describes the structure of memory used within the ENC28J60 network interface. */
typedef struct {
uint8_t count; ///< Number of allocated pages
uint8_t first; ///< First allocated page
uint8_t last; ///< Last allocated page
} StashHeader;
/** This class provides access to the memory within the ENC28J60 network interface. */
class Stash : public /*Stream*/ Print, private StashHeader {
uint8_t curr; //!< Current page
uint8_t offs; //!< Current offset in page
typedef struct {
union {
uint8_t bytes[64];
uint16_t words[32];
struct {
StashHeader head;
uint8_t filler[59];
uint8_t tail;
uint8_t next;
};
};
uint8_t bnum;
} Block;
static uint8_t allocBlock ();
static void freeBlock (uint8_t block);
static uint8_t fetchByte (uint8_t blk, uint8_t off);
static Block bufs[2];
static uint8_t map[256/8];
public:
static void initMap (uint8_t last);
static void load (uint8_t idx, uint8_t blk);
static uint8_t freeCount ();
Stash () : curr (0) { first = 0; }
Stash (uint8_t fd) { open(fd); }
uint8_t create ();
uint8_t open (uint8_t blk);
void save ();
void release ();
void put (char c);
char get ();
uint16_t size ();
virtual WRITE_RESULT write(uint8_t b) { put(b); WRITE_RETURN }
// virtual int available() {
// if (curr != last)
// return 1;
// load(1, last);
// return offs < bufs[1].tail;
// }
// virtual int read() {
// return available() ? get() : -1;
// }
// virtual int peek() {
// return available() ? bufs[1].bytes[offs] : -1;
// }
// virtual void flush() {
// curr = last;
// offs = 63;
// }
static void prepare (PGM_P fmt, ...);
static uint16_t length ();
static void extract (uint16_t offset, uint16_t count, void* buf);
static void cleanup ();
friend void dumpBlock (const char* msg, uint8_t idx); // optional
friend void dumpStash (const char* msg, void* ptr); // optional
};
/** This class populates network send and receive buffers.
*
* This class provides formatted printing into memory. Users can use it to write into send buffers.
*
* Nota: PGM_P: is a pointer to a string in program space (defined in the source code)
*
* # Format string
*
* | Format | Parameter | Output
* |--------|-------------|----------
* | $D | uint16_t | Decimal representation
* | $T ¤ | double | Decimal representation with 3 digits after decimal sign ([-]d.ddd)
* | $H | uint16_t | Hexadecimal value of lsb (from 00 to ff)
* | $L | long | Decimal representation
* | $S | const char* | Copy null terminated string from main memory
* | $F | PGM_P | Copy null terminated string from program space
* | $E | byte* | Copy null terminated string from EEPROM space
* | $$ | _none_ | '$'
*
* ¤ _Available only if FLOATEMIT is defined_
*
* # Examples
* ~~~~~~~~~~~~~{.c}
* uint16_t ddd = 123;
* double ttt = 1.23;
* uint16_t hhh = 0xa4;
* long lll = 123456789;
* char * sss;
* char fff[] PROGMEM = "MyMemory";
*
* sss[0] = 'G';
* sss[1] = 'P';
* sss[2] = 'L';
* sss[3] = 0;
* buf.emit_p( PSTR("ddd=$D\n"), ddd ); // "ddd=123\n"
* buf.emit_p( PSTR("ttt=$T\n"), ttt ); // "ttt=1.23\n" **TO CHECK**
* buf.emit_p( PSTR("hhh=$H\n"), hhh ); // "hhh=a4\n"
* buf.emit_p( PSTR("lll=$L\n"), lll ); // "lll=123456789\n"
* buf.emit_p( PSTR("sss=$S\n"), sss ); // "sss=GPL\n"
* buf.emit_p( PSTR("fff=$F\n"), fff ); // "fff=MyMemory\n"
* ~~~~~~~~~~~~~
*
*/
class BufferFiller : public Print {
uint8_t *start; //!< Pointer to start of buffer
uint8_t *ptr; //!< Pointer to cursor position
public:
/** @brief Empty constructor
*/
BufferFiller () {}
/** @brief Constructor
* @param buf Pointer to the ethernet data buffer
*/
BufferFiller (uint8_t* buf) : start (buf), ptr (buf) {}
/** @brief Add formatted text to buffer
* @param fmt Format string (see Class description)
* @param ... parameters for format string
*/
void emit_p (PGM_P fmt, ...);
/** @brief Add data to buffer from main memory
* @param s Pointer to data
* @param n Number of characters to copy
*/
void emit_raw (const char* s, uint16_t n) { memcpy(ptr, s, n); ptr += n; }
/** @brief Add data to buffer from program space string
* @param p Program space string pointer
* @param n Number of characters to copy
*/
void emit_raw_p (PGM_P p, uint16_t n) { memcpy_P(ptr, p, n); ptr += n; }
/** @brief Get pointer to start of buffer
* @return <i>uint8_t*</i> Pointer to start of buffer
*/
uint8_t* buffer () const { return start; }
/** @brief Get cursor position
* @return <i>uint16_t</i> Cursor postion
*/
uint16_t position () const { return ptr - start; }
/** @brief Write one byte to buffer
* @param v Byte to add to buffer
*/
virtual WRITE_RESULT write (uint8_t v) { *ptr++ = v; WRITE_RETURN }
};
/** This class provides the main interface to a ENC28J60 based network interface card and is the class most users will use.
* @note All TCP/IP client (outgoing) connections are made from source port in range 2816-3071. Do not use these source ports for other purposes.
*/
class EtherCard : public Ethernet {
public:
static uint8_t mymac[6]; ///< MAC address
static uint8_t myip[4]; ///< IP address
static uint8_t netmask[4]; ///< Netmask
static uint8_t broadcastip[4]; ///< Subnet broadcast address
static uint8_t gwip[4]; ///< Gateway
static uint8_t dhcpip[4]; ///< DHCP server IP address
static uint8_t dnsip[4]; ///< DNS server IP address
static uint8_t hisip[4]; ///< DNS lookup result
static uint16_t hisport; ///< TCP port to connect to (default 80)
static bool using_dhcp; ///< True if using DHCP
static bool persist_tcp_connection; ///< False to break connections on first packet received
static uint16_t delaycnt; ///< Counts number of cycles of packetLoop when no packet received - used to trigger periodic gateway ARP request
// EtherCard.cpp
/** @brief Initialise the network interface
* @param size Size of data buffer
* @param macaddr Hardware address to assign to the network interface (6 bytes)
* @param csPin Arduino pin number connected to chip select. Default = 8
* @return <i>uint8_t</i> Firmware version or zero on failure.
*/
static uint8_t begin (const uint16_t size, const uint8_t* macaddr,
uint8_t csPin =PA8);
/** @brief Configure network interface with static IP
* @param my_ip IP address (4 bytes). 0 for no change.
* @param gw_ip Gateway address (4 bytes). 0 for no change. Default = 0
* @param dns_ip DNS address (4 bytes). 0 for no change. Default = 0
* @param mask Subnet mask (4 bytes). 0 for no change. Default = 0
* @return <i>bool</i> Returns true on success - actually always true
*/
static bool staticSetup (const uint8_t* my_ip,
const uint8_t* gw_ip = 0,
const uint8_t* dns_ip = 0,
const uint8_t* mask = 0);
// tcpip.cpp
/** @brief Sends a UDP packet to the IP address of last processed received packet
* @param data Pointer to data payload
* @param len Size of data payload (max 220)
* @param port Source IP port
*/
static void makeUdpReply (const char *data, uint8_t len, uint16_t port);
/** @brief Parse received data
* @param plen Size of data to parse (e.g. return value of packetReceive()).
* @return <i>uint16_t</i> Offset of TCP payload data in data buffer or zero if packet processed
* @note Data buffer is shared by receive and transmit functions
* @note Only handles ARP and IP
*/
static uint16_t packetLoop (uint16_t plen);
/** @brief Accept a TCP/IP connection
* @param port IP port to accept on - do nothing if wrong port
* @param plen Number of bytes in packet
* @return <i>uint16_t</i> Offset within packet of TCP payload. Zero for no data.
*/
static uint16_t accept (uint16_t port, uint16_t plen);
/** @brief Send a response to a HTTP request
* @param dlen Size of the HTTP (TCP) payload
*/
static void httpServerReply (uint16_t dlen);
/** @brief Send a response to a HTTP request
* @param dlen Size of the HTTP (TCP) payload
* @param flags TCP flags
*/
static void httpServerReply_with_flags (uint16_t dlen , uint8_t flags);
/** @brief Acknowledge TCP message
* @todo Is this / should this be private?
*/
static void httpServerReplyAck ();
/** @brief Set the gateway address
* @param gwipaddr Gateway address (4 bytes)
*/
static void setGwIp (const uint8_t *gwipaddr);
/** @brief Updates the broadcast address based on current IP address and subnet mask
*/
static void updateBroadcastAddress();
/** @brief Check if got gateway hardware address (ARP lookup)
* @return <i>unit8_t</i> True if gateway found
*/
static uint8_t clientWaitingGw ();
/** @brief Check if got gateway DNS address (ARP lookup)
* @return <i>unit8_t</i> True if DNS found
*/
static uint8_t clientWaitingDns ();
/** @brief Prepare a TCP request
* @param result_cb Pointer to callback function that handles TCP result
* @param datafill_cb Pointer to callback function that handles TCP data payload
* @param port Remote TCP/IP port to connect to
* @return <i>unit8_t</i> ID of TCP/IP session (0-7)
* @note Return value provides id of the request to allow up to 7 concurrent requests
*/
static uint8_t clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t),
uint16_t (*datafill_cb)(uint8_t),uint16_t port);
/** @brief Prepare HTTP request
* @param urlbuf Pointer to c-string URL folder
* @param urlbuf_varpart Pointer to c-string URL file
* @param hoststr Pointer to c-string hostname
* @param additionalheaderline Pointer to c-string with additional HTTP header info
* @param callback Pointer to callback function to handle response
* @note Request sent in main packetloop
*/
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
const char *hoststr, const char *additionalheaderline,
void (*callback)(uint8_t,uint16_t,uint16_t));
/** @brief Prepare HTTP request
* @param urlbuf Pointer to c-string URL folder
* @param urlbuf_varpart Pointer to c-string URL file
* @param hoststr Pointer to c-string hostname
* @param callback Pointer to callback function to handle response
* @note Request sent in main packetloop
*/
static void browseUrl (const char *urlbuf, const char *urlbuf_varpart,
const char *hoststr,
void (*callback)(uint8_t,uint16_t,uint16_t));
/** @brief Prepare HTTP post message
* @param urlbuf Pointer to c-string URL folder
* @param hoststr Pointer to c-string hostname
* @param additionalheaderline Pointer to c-string with additional HTTP header info
* @param postval Pointer to c-string HTML Post value
* @param callback Pointer to callback function to handle response
* @note Request sent in main packetloop
*/
static void httpPost (const char *urlbuf, const char *hoststr,
const char *additionalheaderline, const char *postval,
void (*callback)(uint8_t,uint16_t,uint16_t));
/** @brief Send NTP request
* @param ntpip IP address of NTP server
* @param srcport IP port to send from
*/
static void ntpRequest (uint8_t *ntpip,uint8_t srcport);
/** @brief Process network time protocol response
* @param time Pointer to integer to hold result
* @param dstport_l Destination port to expect response. Set to zero to accept on any port
* @return <i>uint8_t</i> True (1) on success
*/
static uint8_t ntpProcessAnswer (uint32_t *time, uint8_t dstport_l);
/** @brief Prepare a UDP message for transmission
* @param sport Source port
* @param dip Pointer to 4 byte destination IP address
* @param dport Destination port
*/
static void udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport);
/** @brief Transmit UDP packet
* @param len Size of payload
*/
static void udpTransmit (uint16_t len);
/** @brief Sends a UDP packet
* @param data Pointer to data
* @param len Size of payload (maximum 220 octets / bytes)
* @param sport Source port
* @param dip Pointer to 4 byte destination IP address
* @param dport Destination port
*/
static void sendUdp (const char *data, uint8_t len, uint16_t sport,
const uint8_t *dip, uint16_t dport);
/** @brief Resister the function to handle ping events
* @param cb Pointer to function
*/
static void registerPingCallback (void (*cb)(uint8_t*));
/** @brief Send ping
* @param destip Ponter to 4 byte destination IP address
*/
static void clientIcmpRequest (const uint8_t *destip);
/** @brief Check for ping response
* @param ip_monitoredhost Pointer to 4 byte IP address of host to check
* @return <i>uint8_t</i> True (1) if ping response from specified host
*/
static uint8_t packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost);
/** @brief Send a wake on lan message
* @param wolmac Pointer to 6 byte hardware (MAC) address of host to send message to
*/
static void sendWol (uint8_t *wolmac);
// new stash-based API
/** @brief Send TCP request
*/
static uint8_t tcpSend ();
/** @brief Get TCP reply
* @return <i>char*</i> Pointer to TCP reply payload. NULL if no data.
*/
static const char* tcpReply (uint8_t fd);
/** @brief Configure TCP connections to be persistent or not
* @param persist True to maintain TCP connection. False to finish TCP connection after first packet.
*/
static void persistTcpConnection(bool persist);
//udpserver.cpp
/** @brief Register function to handle incomint UDP events
* @param callback Function to handle event
* @param port Port to listen on
*/
static void udpServerListenOnPort(UdpServerCallback callback, uint16_t port);
/** @brief Pause listing on UDP port
* @brief port Port to pause
*/
static void udpServerPauseListenOnPort(uint16_t port);
/** @brief Resume listing on UDP port
* @brief port Port to pause
*/
static void udpServerResumeListenOnPort(uint16_t port);
/** @brief Check if UDP server is listening on any ports
* @return <i>bool</i> True if listening on any ports
*/
static bool udpServerListening(); //called by tcpip, in packetLoop
/** @brief Passes packet to UDP Server
* @param len Not used
* @return <i>bool</i> True if packet processed
*/
static bool udpServerHasProcessedPacket(uint16_t len); //called by tcpip, in packetLoop
// dhcp.cpp
/** @brief Update DHCP state
* @param len Length of received data packet
*/
static void DhcpStateMachine(uint16_t len);
/** @brief Not implemented
* @todo Implement dhcpStartTime or remove declaration
*/
static uint32_t dhcpStartTime ();
/** @brief Not implemented
* @todo Implement dhcpLeaseTime or remove declaration
*/
static uint32_t dhcpLeaseTime ();
/** @brief Not implemented
* @todo Implement dhcpLease or remove declaration
*/
static bool dhcpLease ();
/** @brief Configure network interface with DHCP
* @return <i>bool</i> True if DHCP successful
* @note Blocks until DHCP complete or timeout after 60 seconds
*/
static bool dhcpSetup (const char *hname = NULL, bool fromRam =false);
/** @brief Register a callback for a specific DHCP option number
* @param option The option number to request from the DHCP server
* @param callback The function to be call when the option is received
*/
static void dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback);
// dns.cpp
/** @brief Perform DNS lookup
* @param name Host name to lookup
* @param fromRam Set true to look up cached name. Default = false
* @return <i>bool</i> True on success.
* @note Result is stored in <i>hisip</i> member
*/
static bool dnsLookup (const char* name, bool fromRam =false);
// webutil.cpp
/** @brief Copies an IP address
* @param dst Pointer to the 4 byte destination
* @param src Pointer to the 4 byte source
* @note There is no check of source or destination size. Ensure both are 4 bytes
*/
static void copyIp (uint8_t *dst, const uint8_t *src);
/** @brief Copies a hardware address
* @param dst Pointer to the 6 byte destination
* @param src Pointer to the 6 byte destination
* @note There is no check of source or destination size. Ensure both are 6 bytes
*/
static void copyMac (uint8_t *dst, const uint8_t *src);
/** @brief Output to serial port in dotted decimal IP format
* @param buf Pointer to 4 byte IP address
* @note There is no check of source or destination size. Ensure both are 4 bytes
*/
static void printIp (const uint8_t *buf);
/** @brief Output message and IP address to serial port in dotted decimal IP format
* @param msg Pointer to null terminated string
* @param buf Pointer to 4 byte IP address
* @note There is no check of source or destination size. Ensure both are 4 bytes
*/
static void printIp (const char* msg, const uint8_t *buf);
/** @brief Output Flash String Helper and IP address to serial port in dotted decimal IP format
* @param ifsh Pointer to Flash String Helper
* @param buf Pointer to 4 byte IP address
* @note There is no check of source or destination size. Ensure both are 4 bytes
* @todo What is a FlashStringHelper?
*/
static void printIp (const __FlashStringHelper *ifsh, const uint8_t *buf);
/** @brief Search for a string of the form key=value in a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\\r\\n
* @param str Pointer to the null terminated string to search
* @param strbuf Pointer to buffer to hold null terminated result string
* @param maxlen Maximum length of result
* @param key Pointer to null terminated string holding the key to search for
* @return <i>unit_t</i> Length of the value. 0 if not found
* @note Ensure strbuf has memory allocated of at least maxlen + 1 (to accomodate result plus terminating null)
*/
static uint8_t findKeyVal(const char *str,char *strbuf,
uint8_t maxlen, const char *key);
/** @brief Decode a URL string e.g "hello%20joe" or "hello+joe" becomes "hello joe"
* @param urlbuf Pointer to the null terminated URL
* @note urlbuf is modified
*/
static void urlDecode(char *urlbuf);
/** @brief Encode a URL, replacing illegal charaters like ' '
* @param str Pointer to the null terminated string to encode
* @param urlbuf Pointer to a buffer to contain the null terminated encoded URL
* @note There must be enough space in urlbuf. In the worst case that is 3 times the length of str
*/
static void urlEncode(char *str,char *urlbuf);
/** @brief Convert an IP address from dotted decimal formated string to 4 bytes
* @param bytestr Pointer to the 4 byte array to store IP address
* @param str Pointer to string to parse
* @return <i>uint8_t</i> 0 on success
*/
static uint8_t parseIp(uint8_t *bytestr,char *str);
/** @brief Convert a byte array to a human readable display string
* @param resultstr Pointer to a buffer to hold the resulting null terminated string
* @param bytestr Pointer to the byte array containing the address to convert
* @param len Length of the array (4 for IP address, 6 for hardware (MAC) address)
* @param separator Delimiter character (typically '.' for IP address and ':' for hardware (MAC) address)
* @param base Base for numerical representation (typically 10 for IP address and 16 for hardware (MAC) address
*/
static void makeNetStr(char *resultstr,uint8_t *bytestr,uint8_t len,
char separator,uint8_t base);
};
extern EtherCard ether; //!< Global presentation of EtherCard class
#endif

View File

@ -0,0 +1,397 @@
// DHCP look-up functions based on the udp client
// http://www.ietf.org/rfc/rfc2131.txt
//
// Author: Andrew Lindsay
// Rewritten and optimized by Jean-Claude Wippler, http://jeelabs.org/
//
// Rewritten dhcpStateMachine by Chris van den Hooven
// as to implement dhcp-renew when lease expires (jun 2012)
//
// Various modifications and bug fixes contributed by Victor Aprea (oct 2012)
//
// Copyright: GPL V2
// See http://www.gnu.org/licenses/gpl.html
//#define DHCPDEBUG
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//-----------------------------------------------------------------
#include "EtherCard_STM.h"
#include "net.h"
#define gPB ether.buffer
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTRESPONSE 2
// DHCP Message Type (option 53) (ref RFC 2132)
#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
// DHCP States for access in applications (ref RFC 2131)
enum {
DHCP_STATE_INIT,
DHCP_STATE_SELECTING,
DHCP_STATE_REQUESTING,
DHCP_STATE_BOUND,
DHCP_STATE_RENEWING,
};
/*
op 1 Message op code / message type.
1 = BOOTREQUEST, 2 = BOOTREPLY
htype 1 Hardware address type, see ARP section in "Assigned
Numbers" RFC; e.g., '1' = 10mb ethernet.
hlen 1 Hardware address length (e.g. '6' for 10mb
ethernet).
hops 1 Client sets to zero, optionally used by relay agents
when booting via a relay agent.
xid 4 Transaction ID, a random number chosen by the
client, used by the client and server to associate
messages and responses between a client and a
server.
secs 2 Filled in by client, seconds elapsed since client
began address acquisition or renewal process.
flags 2 Flags (see figure 2).
ciaddr 4 Client IP address; only filled in if client is in
BOUND, RENEW or REBINDING state and can respond
to ARP requests.
yiaddr 4 'your' (client) IP address.
siaddr 4 IP address of next server to use in bootstrap;
returned in DHCPOFFER, DHCPACK by server.
giaddr 4 Relay agent IP address, used in booting via a
relay agent.
chaddr 16 Client hardware address.
sname 64 Optional server host name, null terminated string.
file 128 Boot file name, null terminated string; "generic"
name or null in DHCPDISCOVER, fully qualified
directory-path name in DHCPOFFER.
options var Optional parameters field. See the options
documents for a list of defined options.
*/
// size 236
typedef struct {
byte op, htype, hlen, hops;
uint32_t xid;
uint16_t secs, flags;
byte ciaddr[4], yiaddr[4], siaddr[4], giaddr[4];
byte chaddr[16], sname[64], file[128];
// options
} DHCPdata;
#define DHCP_SRC_PORT 67
#define DHCP_DEST_PORT 68
// timeouts im ms
#define DHCP_REQUEST_TIMEOUT 10000
#define DHCP_HOSTNAME_MAX_LEN 32
static byte dhcpState = DHCP_STATE_INIT;
static char hostname[DHCP_HOSTNAME_MAX_LEN] = "Arduino-00";
static uint32_t currentXid;
static uint32_t stateTimer;
static uint32_t leaseStart;
static uint32_t leaseTime;
static byte* bufPtr;
static uint8_t dhcpCustomOptionNum = 0;
static DhcpOptionCallback dhcpCustomOptionCallback = NULL;
// static uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
static void addToBuf (byte b) {
*bufPtr++ = b;
}
static void addBytes (byte len, const byte* data) {
while (len-- > 0)
addToBuf(*data++);
}
// Main DHCP sending function
// implemented
// state / msgtype
// INIT / DHCPDISCOVER
// SELECTING / DHCPREQUEST
// BOUND (RENEWING) / DHCPREQUEST
// ----------------------------------------------------------
// | |SELECTING |RENEWING |INIT |
// ----------------------------------------------------------
// |broad/unicast |broadcast |unicast |broadcast |
// |server-ip |MUST |MUST NOT |MUST NOT | option 54
// |requested-ip |MUST |MUST NOT |MUST NOT | option 50
// |ciaddr |zero |IP address |zero |
// ----------------------------------------------------------
// options used (both send/receive)
// 12 Host Name Option
// 50 Requested IP Address
// 51 IP Address Lease Time
// 53 DHCP message type
// 54 Server-identifier
// 55 Parameter request list
// 58 Renewal (T1) Time Value
// 61 Client-identifier
// 255 End
static void send_dhcp_message (void) {
uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
memset(gPB, 0, UDP_DATA_P + sizeof( DHCPdata ));
EtherCard::udpPrepare(DHCP_DEST_PORT,
(dhcpState == DHCP_STATE_BOUND ? EtherCard::dhcpip : allOnes),
DHCP_SRC_PORT); // SRC<->DST ??
if (dhcpState != DHCP_STATE_BOUND)
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes); //force broadcast mac
// Build DHCP Packet from buf[UDP_DATA_P]
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
dhcpPtr->op = DHCP_BOOTREQUEST;
dhcpPtr->htype = 1;
dhcpPtr->hlen = 6;
dhcpPtr->xid = currentXid;
if (dhcpState == DHCP_STATE_BOUND) {
EtherCard::copyIp(dhcpPtr->ciaddr, EtherCard::myip);
}
EtherCard::copyMac(dhcpPtr->chaddr, EtherCard::mymac);
// options defined as option, length, value
bufPtr = gPB + UDP_DATA_P + sizeof( DHCPdata );
// DHCP magic cookie, followed by message type
static byte cookie[] = { 99, 130, 83, 99, 53, 1 };
addBytes(sizeof cookie, cookie);
// addToBuf(53); // DHCP_STATE_SELECTING, DHCP_STATE_REQUESTING
// addToBuf(1); // Length
addToBuf(dhcpState == DHCP_STATE_INIT ? DHCP_DISCOVER : DHCP_REQUEST);
// Client Identifier Option, this is the client mac address
addToBuf(61); // Client identifier
addToBuf(7); // Length
addToBuf(0x01); // Ethernet
addBytes(6, EtherCard::mymac);
addToBuf(12); // Host name Option
addToBuf(10);
addBytes(10, (byte*) hostname);
if( dhcpState == DHCP_STATE_SELECTING) {
addToBuf(50); // Request IP address
addToBuf(4);
addBytes(4, EtherCard::myip);
// Request using server ip address
addToBuf(54); // Server IP address
addToBuf(4);
addBytes(4, EtherCard::dhcpip);
}
// Additional info in parameter list - minimal list for what we need
byte len = 3;
if (dhcpCustomOptionNum)
len++;
addToBuf(55); // Parameter request list
addToBuf(len); // Length
addToBuf(1); // Subnet mask
addToBuf(3); // Route/Gateway
addToBuf(6); // DNS Server
if (dhcpCustomOptionNum)
addToBuf(dhcpCustomOptionNum); // Custom option
addToBuf(255); // end option
// packet size will be under 300 bytes
EtherCard::udpTransmit((bufPtr - gPB) - UDP_DATA_P);
}
static void process_dhcp_offer (uint16_t len) {
// Map struct onto payload
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
// Offered IP address is in yiaddr
EtherCard::copyIp(EtherCard::myip, dhcpPtr->yiaddr);
// Scan through variable length option list identifying options we want
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
bool done = false;
do {
byte option = *ptr++;
byte optionLen = *ptr++;
switch (option) {
case 1: EtherCard::copyIp(EtherCard::netmask, ptr);
break;
case 3: EtherCard::copyIp(EtherCard::gwip, ptr);
break;
case 6: EtherCard::copyIp(EtherCard::dnsip, ptr);
break;
case 51:
case 58: leaseTime = 0; // option 58 = Renewal Time, 51 = Lease Time
for (byte i = 0; i<4; i++)
leaseTime = (leaseTime << 8) + ptr[i];
leaseTime *= 1000; // milliseconds
break;
case 54: EtherCard::copyIp(EtherCard::dhcpip, ptr);
break;
case 255: done = true;
break;
default: {
// Is is a custom configured option?
if (dhcpCustomOptionCallback && option == dhcpCustomOptionNum) {
dhcpCustomOptionCallback(option, ptr, optionLen);
}
}
}
ptr += optionLen;
} while (!done && ptr < gPB + len);
}
static bool dhcp_received_message_type (uint16_t len, byte msgType) {
// Map struct onto payload
DHCPdata *dhcpPtr = (DHCPdata*) (gPB + UDP_DATA_P);
if (len >= 70 && gPB[UDP_SRC_PORT_L_P] == DHCP_SRC_PORT &&
dhcpPtr->xid == currentXid ) {
byte *ptr = (byte*) (dhcpPtr + 1) + 4;
do {
byte option = *ptr++;
byte optionLen = *ptr++;
if(option == 53 && *ptr == msgType ) {
// DHCP Message type match found
return true;
}
ptr += optionLen;
} while (ptr < gPB + len);
}
return false;
}
bool EtherCard::dhcpSetup (const char *hname, bool fromRam) {
// Use during setup, as this discards all incoming requests until it returns.
// That shouldn't be a problem, because we don't have an IP-address yet.
// Will try 60 secs to obtain DHCP-lease.
using_dhcp = true;
if(hname != NULL){
if(fromRam){
strncpy(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
}
else{
strncpy(hostname, hname, DHCP_HOSTNAME_MAX_LEN);
}
}
else{
// Set a unique hostname, use Arduino-?? with last octet of mac address
hostname[8] = '0' + (mymac[5] >> 4);
hostname[9] = '0' + (mymac[5] & 0x0F);
}
dhcpState = DHCP_STATE_INIT;
uint16_t start = millis();
while (dhcpState != DHCP_STATE_BOUND && (uint16_t) (millis() - start) < 60000) {
if (isLinkUp()) DhcpStateMachine(packetReceive());
}
updateBroadcastAddress();
delaycnt = 0;
return dhcpState == DHCP_STATE_BOUND ;
}
void EtherCard::dhcpAddOptionCallback(uint8_t option, DhcpOptionCallback callback)
{
dhcpCustomOptionNum = option;
dhcpCustomOptionCallback = callback;
}
void EtherCard::DhcpStateMachine (uint16_t len) {
#ifdef DHCPDEBUG
if (dhcpState != DHCP_STATE_BOUND) {
Serial.print(millis());
Serial.print(" State: ");
}
switch (dhcpState) {
case DHCP_STATE_INIT:
Serial.println("Init");
break;
case DHCP_STATE_SELECTING:
Serial.println("Selecting");
break;
case DHCP_STATE_REQUESTING:
Serial.println("Requesting");
break;
case DHCP_STATE_RENEWING:
Serial.println("Renew");
break;
}
#endif
switch (dhcpState) {
case DHCP_STATE_BOUND:
//!@todo Due to millis() 49 day wrap-around, DHCP renewal may not work as expected
if (millis() >= leaseStart + leaseTime) {
send_dhcp_message();
dhcpState = DHCP_STATE_RENEWING;
stateTimer = millis();
}
break;
case DHCP_STATE_INIT:
currentXid = millis();
memset(myip,0,4); // force ip 0.0.0.0
send_dhcp_message();
enableBroadcast(true); //Temporarily enable broadcasts
dhcpState = DHCP_STATE_SELECTING;
stateTimer = millis();
break;
case DHCP_STATE_SELECTING:
if (dhcp_received_message_type(len, DHCP_OFFER)) {
process_dhcp_offer(len);
send_dhcp_message();
dhcpState = DHCP_STATE_REQUESTING;
stateTimer = millis();
} else {
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
dhcpState = DHCP_STATE_INIT;
}
}
break;
case DHCP_STATE_REQUESTING:
case DHCP_STATE_RENEWING:
if (dhcp_received_message_type(len, DHCP_ACK)) {
disableBroadcast(true); //Disable broadcast after temporary enable
leaseStart = millis();
if (gwip[0] != 0) setGwIp(gwip); // why is this? because it initiates an arp request
dhcpState = DHCP_STATE_BOUND;
} else {
if (millis() > stateTimer + DHCP_REQUEST_TIMEOUT) {
dhcpState = DHCP_STATE_INIT;
}
}
break;
}
}

View File

@ -0,0 +1,117 @@
// DNS look-up functions based on the udp client
// Author: Guido Socher
// Copyright: GPL V2
//
// 2010-05-20 <jc@wippler.nl>
#include "EtherCard_STM.h"
#include "net.h"
#define gPB ether.buffer
static byte dnstid_l; // a counter for transaction ID
#define DNSCLIENT_SRC_PORT_H 0xE0
static void dnsRequest (const char *hostname, bool fromRam) {
++dnstid_l; // increment for next request, finally wrap
if (ether.dnsip[0] == 0)
memset(ether.dnsip, 8, 4); // use 8.8.8.8 Google DNS as default
ether.udpPrepare((DNSCLIENT_SRC_PORT_H << 8) | dnstid_l, ether.dnsip, 53);
memset(gPB + UDP_DATA_P, 0, 12);
byte *p = gPB + UDP_DATA_P + 12;
char c;
do {
byte n = 0;
for(;;) {
c = fromRam ? *hostname : pgm_read_byte(hostname);
++hostname;
if (c == '.' || c == 0)
break;
p[++n] = c;
}
*p++ = n;
p += n;
} while (c != 0);
*p++ = 0; // terminate with zero, means root domain.
*p++ = 0;
*p++ = 1; // type A
*p++ = 0;
*p++ = 1; // class IN
byte i = p - gPB - UDP_DATA_P;
gPB[UDP_DATA_P] = i;
gPB[UDP_DATA_P+1] = dnstid_l;
gPB[UDP_DATA_P+2] = 1; // flags, standard recursive query
gPB[UDP_DATA_P+5] = 1; // 1 question
ether.udpTransmit(i);
}
/** @brief Check if packet is DNS response.
@param plen Size of packet
@return <i>bool</i> True if DNS response has error. False if not DNS response or DNS response OK.
@note hisip contains IP address of requested host or 0.0.0.0 on failure
*/
static bool checkForDnsAnswer (uint16_t plen) {
byte *p = gPB + UDP_DATA_P; //start of UDP payload
if (plen < 70 || gPB[UDP_SRC_PORT_L_P] != 53 || //from DNS source port
gPB[UDP_DST_PORT_H_P] != DNSCLIENT_SRC_PORT_H || //response to same port as we sent from (MSB)
gPB[UDP_DST_PORT_L_P] != dnstid_l || //response to same port as we sent from (LSB)
p[1] != dnstid_l) //message id same as we sent
return false; //not our DNS response
if((p[3] & 0x0F) != 0)
return true; //DNS response recieved with error
p += *p; // we encoded the query len into tid
for (;;) {
if (*p & 0xC0)
p += 2;
else
while (++p < gPB + plen) {
if (*p == 0) {
++p;
break;
}
}
if (p + 14 > gPB + plen)
break;
if (p[1] == 1 && p[9] == 4) { // type "A" and IPv4
ether.copyIp(ether.hisip, p + 10);
break;
}
p += p[9] + 10;
}
return false; //No error
}
// use during setup, as this discards all incoming requests until it returns
bool EtherCard::dnsLookup (const char* name, bool fromRam) {
uint16_t start = millis();
while(!isLinkUp())
{
if ((uint16_t) (millis() - start) >= 30000)
return false; //timeout waiting for link
}
while(clientWaitingGw())
{
packetLoop(packetReceive());
if ((uint16_t) (millis() - start) >= 30000)
return false; //timeout waiting for gateway ARP
}
memset(hisip, 0, 4);
dnsRequest(name, fromRam);
start = millis();
while (hisip[0] == 0) {
if ((uint16_t) (millis() - start) >= 30000)
return false; //timout waiting for dns response
uint16_t len = packetReceive();
if (len > 0 && packetLoop(len) == 0) //packet not handled by tcp/ip packet loop
if(checkForDnsAnswer(len))
return false; //DNS response recieved with error
}
return true;
}

View File

@ -0,0 +1,624 @@
// Microchip ENC28J60 Ethernet Interface Driver
// Author: Guido Socher
// Copyright: GPL V2
//
// Based on the enc28j60.c file from the AVRlib library by Pascal Stang.
// For AVRlib See http://www.procyonengineering.com/
// Used with explicit permission of Pascal Stang.
//
// 2010-05-20 <jc@wippler.nl>
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//-----------------------------------------------------------------
#if ARDUINO >= 100
#include <Arduino.h> // Arduino 1.0
#else
#include <Wprogram.h> // Arduino 0022
#endif
#include "enc28j60.h"
#include <SPI.h> // Using library SPI in folder: D:\Documents\Arduino\hardware\STM32\STM32F1XX\libraries\SPI
uint16_t ENC28J60::bufferSize;
bool ENC28J60::broadcast_enabled = false;
// 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 ERDPT (0x00|0x00)
#define EWRPT (0x02|0x00)
#define ETXST (0x04|0x00)
#define ETXND (0x06|0x00)
#define ERXST (0x08|0x00)
#define ERXND (0x0A|0x00)
#define ERXRDPT (0x0C|0x00)
// #define ERXWRPT (0x0E|0x00)
#define EDMAST (0x10|0x00)
#define EDMAND (0x12|0x00)
// #define EDMADST (0x14|0x00)
#define EDMACS (0x16|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 EPMCS (0x10|0x20)
// #define EPMO (0x14|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 MAIPG (0x06|0x40|0x80)
#define MACLCON1 (0x08|0x40|0x80)
#define MACLCON2 (0x09|0x40|0x80)
#define MAMXFL (0x0A|0x40|0x80)
#define MAPHSUP (0x0D|0x40|0x80)
#define MICON (0x11|0x40|0x80)
#define MICMD (0x12|0x40|0x80)
#define MIREGADR (0x14|0x40|0x80)
#define MIWR (0x16|0x40|0x80)
#define MIRD (0x18|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 EBSTCS (0x08|0x60)
#define MISTAT (0x0A|0x60|0x80)
#define EREVID (0x12|0x60)
#define ECOCON (0x15|0x60)
#define EFLOCON (0x17|0x60)
#define EPAUS (0x18|0x60)
// 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 EBSTCON Register Bit Definitions
#define EBSTCON_PSV2 0x80
#define EBSTCON_PSV1 0x40
#define EBSTCON_PSV0 0x20
#define EBSTCON_PSEL 0x10
#define EBSTCON_TMSEL1 0x08
#define EBSTCON_TMSEL0 0x04
#define EBSTCON_TME 0x02
#define EBSTCON_BISTST 0x01
// 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 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 must be zero. See Rev. B4 Silicon Errata point 5.
// Buffer boundaries applied to internal 8K ram
// the entire available packet buffer space is allocated
#define RXSTART_INIT 0x0000 // start of RX buffer, room for 2 packets
#define RXSTOP_INIT 0x0BFF // end of RX buffer
#define TXSTART_INIT 0x0C00 // start of TX buffer, room for 1 packet
#define TXSTOP_INIT 0x11FF // end of TX buffer
#define SCRATCH_START 0x1200 // start of scratch area
#define SCRATCH_LIMIT 0x2000 // past end of area, i.e. 3.5 Kb
#define SCRATCH_PAGE_SHIFT 6 // addressing is in pages of 64 bytes
#define SCRATCH_PAGE_SIZE (1 << SCRATCH_PAGE_SHIFT)
// max frame length which the conroller will accept:
// (note: maximum ethernet frame length would be 1518)
#define MAX_FRAMELEN 1500
#define FULL_SPEED 1 // switch to full-speed SPI for bulk transfers
static byte Enc28j60Bank;
static int gNextPacketPtr;
static byte selectPin;
void ENC28J60::initSPI () {
SPI.begin();
SPI.setBitOrder(MSBFIRST);
//SPI.setDataMode(SPI_MODE0);
//SPI.setClockDivider(SPI_CLOCK_DIV16);
}
static void enableChip () {
//cli();
digitalWrite(selectPin, LOW);
}
static void disableChip () {
digitalWrite(selectPin, HIGH);
//sei();
}
//static void xferSPI (byte data) {
//SPDR = data;
//while (!(SPSR&(1<<SPIF)))
//}
static byte readOp (byte op, byte address) {
enableChip();
byte result;
//xferSPI(op | (address & ADDR_MASK));
//xferSPI(0x00);
//if (address & 0x80)
// xferSPI(0x00);
//byte result = SPDR;
SPI.transfer(op | (address & ADDR_MASK));
result = SPI.transfer(0x00);
if (address & 0x80)
result = SPI.transfer(0x00);
disableChip();
return result;
}
static void writeOp (byte op, byte address, byte data) {
enableChip();
//xferSPI(op | (address & ADDR_MASK));
//xferSPI(data);
SPI.transfer(op | (address & ADDR_MASK));
SPI.transfer(data);
disableChip();
}
static void readBuf(uint16_t len, byte* data) {
enableChip();
//xferSPI(ENC28J60_READ_BUF_MEM);
SPI.transfer(ENC28J60_READ_BUF_MEM);
while (len--) {
//xferSPI(0x00);
//*data++ = SPDR;
*data++ = SPI.transfer(0x00);
}
disableChip();
}
static void writeBuf(uint16_t len, const byte* data) {
enableChip();
//xferSPI(ENC28J60_WRITE_BUF_MEM);
SPI.transfer(ENC28J60_WRITE_BUF_MEM);
//while (len--)
// xferSPI(*data++);
while (len--)
SPI.transfer(*data++);
disableChip();
}
static void SetBank (byte address) {
if ((address & BANK_MASK) != Enc28j60Bank) {
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_BSEL1|ECON1_BSEL0);
Enc28j60Bank = address & BANK_MASK;
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, Enc28j60Bank>>5);
}
}
static byte readRegByte (byte address) {
SetBank(address);
return readOp(ENC28J60_READ_CTRL_REG, address);
}
static uint16_t readReg(byte address) {
return readRegByte(address) + (readRegByte(address+1) << 8);
}
static void writeRegByte (byte address, byte data) {
SetBank(address);
writeOp(ENC28J60_WRITE_CTRL_REG, address, data);
}
static void writeReg(byte address, uint16_t data) {
writeRegByte(address, data);
writeRegByte(address + 1, data >> 8);
}
static uint16_t readPhyByte (byte address) {
writeRegByte(MIREGADR, address);
writeRegByte(MICMD, MICMD_MIIRD);
while (readRegByte(MISTAT) & MISTAT_BUSY)
;
writeRegByte(MICMD, 0x00);
return readRegByte(MIRD+1);
}
static void writePhy (byte address, uint16_t data) {
writeRegByte(MIREGADR, address);
writeReg(MIWR, data);
while (readRegByte(MISTAT) & MISTAT_BUSY)
;
}
byte ENC28J60::initialize (uint16_t size, const byte* macaddr, byte csPin) {
bufferSize = size;
//if (bitRead(SPCR, SPE) == 0)
initSPI();
selectPin = csPin;
pinMode(selectPin, OUTPUT);
disableChip();
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
delay(2); // errata B7/2
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY)
;
gNextPacketPtr = RXSTART_INIT;
writeReg(ERXST, RXSTART_INIT);
writeReg(ERXRDPT, RXSTART_INIT);
writeReg(ERXND, RXSTOP_INIT);
writeReg(ETXST, TXSTART_INIT);
writeReg(ETXND, TXSTOP_INIT);
enableBroadcast(); // change to add ERXFCON_BCEN recommended by epam
writeReg(EPMM0, 0x303f);
writeReg(EPMCS, 0xf7f9);
writeRegByte(MACON1, MACON1_MARXEN|MACON1_TXPAUS|MACON1_RXPAUS);
writeRegByte(MACON2, 0x00);
writeOp(ENC28J60_BIT_FIELD_SET, MACON3,
MACON3_PADCFG0|MACON3_TXCRCEN|MACON3_FRMLNEN);
writeReg(MAIPG, 0x0C12);
writeRegByte(MABBIPG, 0x12);
writeReg(MAMXFL, MAX_FRAMELEN);
writeRegByte(MAADR5, macaddr[0]);
writeRegByte(MAADR4, macaddr[1]);
writeRegByte(MAADR3, macaddr[2]);
writeRegByte(MAADR2, macaddr[3]);
writeRegByte(MAADR1, macaddr[4]);
writeRegByte(MAADR0, macaddr[5]);
writePhy(PHCON2, PHCON2_HDLDIS);
SetBank(ECON1);
writeOp(ENC28J60_BIT_FIELD_SET, EIE, EIE_INTIE|EIE_PKTIE);
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
byte rev = readRegByte(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;
return rev;
}
bool ENC28J60::isLinkUp() {
return (readPhyByte(PHSTAT2) >> 2) & 1;
}
void ENC28J60::packetSend(uint16_t len) {
while (readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_TXRTS)
if (readRegByte(EIR) & EIR_TXERIF) {
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRST);
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_TXRST);
}
writeReg(EWRPT, TXSTART_INIT);
writeReg(ETXND, TXSTART_INIT+len);
writeOp(ENC28J60_WRITE_BUF_MEM, 0, 0x00);
writeBuf(len, buffer);
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_TXRTS);
}
uint16_t ENC28J60::packetReceive() {
uint16_t len = 0;
if (readRegByte(EPKTCNT) > 0) {
writeReg(ERDPT, gNextPacketPtr);
struct {
uint16_t nextPacket;
uint16_t byteCount;
uint16_t status;
} header;
readBuf(sizeof header, (byte*) &header);
gNextPacketPtr = header.nextPacket;
len = header.byteCount - 4; //remove the CRC count
if (len>bufferSize-1)
len=bufferSize-1;
if ((header.status & 0x80)==0)
len = 0;
else
readBuf(len, buffer);
buffer[len] = 0;
if (gNextPacketPtr - 1 > RXSTOP_INIT)
writeReg(ERXRDPT, RXSTOP_INIT);
else
writeReg(ERXRDPT, gNextPacketPtr - 1);
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PKTDEC);
}
return len;
}
void ENC28J60::copyout (byte page, const byte* data) {
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
return;
writeReg(EWRPT, destPos);
writeBuf(SCRATCH_PAGE_SIZE, data);
}
void ENC28J60::copyin (byte page, byte* data) {
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT);
if (destPos < SCRATCH_START || destPos > SCRATCH_LIMIT - SCRATCH_PAGE_SIZE)
return;
writeReg(ERDPT, destPos);
readBuf(SCRATCH_PAGE_SIZE, data);
}
byte ENC28J60::peekin (byte page, byte off) {
byte result = 0;
uint16_t destPos = SCRATCH_START + (page << SCRATCH_PAGE_SHIFT) + off;
if (SCRATCH_START <= destPos && destPos < SCRATCH_LIMIT) {
writeReg(ERDPT, destPos);
readBuf(1, &result);
}
return result;
}
// Contributed by Alex M. Based on code from: http://blog.derouineau.fr
// /2011/07/putting-enc28j60-ethernet-controler-in-sleep-mode/
void ENC28J60::powerDown() {
writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN);
while(readRegByte(ESTAT) & ESTAT_RXBUSY);
while(readRegByte(ECON1) & ECON1_TXRTS);
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS);
writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV);
}
void ENC28J60::powerUp() {
writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV);
while(!readRegByte(ESTAT) & ESTAT_CLKRDY);
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN);
}
void ENC28J60::enableBroadcast (bool temporary) {
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_BCEN);
if(!temporary)
broadcast_enabled = true;
}
void ENC28J60::disableBroadcast (bool temporary) {
if(!temporary)
broadcast_enabled = false;
if(!broadcast_enabled)
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_BCEN);
}
void ENC28J60::enableMulticast () {
writeRegByte(ERXFCON, readRegByte(ERXFCON) | ERXFCON_MCEN);
}
void ENC28J60::disableMulticast () {
writeRegByte(ERXFCON, readRegByte(ERXFCON) & ~ERXFCON_MCEN);
}
uint8_t ENC28J60::doBIST ( byte csPin) {
#define RANDOM_FILL 0b0000
#define ADDRESS_FILL 0b0100
#define PATTERN_SHIFT 0b1000
#define RANDOM_RACE 0b1100
// init
//if (bitRead(SPCR, SPE) == 0)
// initSPI();
selectPin = csPin;
pinMode(selectPin, OUTPUT);
disableChip();
writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
delay(2); // errata B7/2
while (!readOp(ENC28J60_READ_CTRL_REG, ESTAT) & ESTAT_CLKRDY) ;
// now we can start the memory test
uint16_t macResult;
uint16_t bitsResult;
// clear some of the registers registers
writeRegByte(ECON1, 0);
writeReg(EDMAST, 0);
// Set up necessary pointers for the DMA to calculate over the entire memory
writeReg(EDMAND, 0x1FFFu);
writeReg(ERXND, 0x1FFFu);
// Enable Test Mode and do an Address Fill
SetBank(EBSTCON);
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_BISTST | ADDRESS_FILL);
// wait for BISTST to be reset, only after that are we actually ready to
// start the test
// this was undocumented :(
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
// now start the actual reading an calculating the checksum until the end is
// reached
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
SetBank(EDMACS);
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
macResult = readReg(EDMACS);
bitsResult = readReg(EBSTCS);
// Compare the results
// 0xF807 should always be generated in Address fill mode
if ((macResult != bitsResult) || (bitsResult != 0xF807)) {
return 0;
}
// reset test flag
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
// Now start the BIST with random data test, and also keep on swapping the
// DMA/BIST memory ports.
writeRegByte(EBSTSD, 0b10101010 | millis());
writeRegByte(EBSTCON, EBSTCON_TME | EBSTCON_PSEL | EBSTCON_BISTST | RANDOM_FILL);
// wait for BISTST to be reset, only after that are we actually ready to
// start the test
// this was undocumented :(
while (readOp(ENC28J60_READ_CTRL_REG, EBSTCON) & EBSTCON_BISTST);
writeOp(ENC28J60_BIT_FIELD_CLR, EBSTCON, EBSTCON_TME);
// now start the actual reading an calculating the checksum until the end is
// reached
writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_DMAST | ECON1_CSUMEN);
SetBank(EDMACS);
while(readOp(ENC28J60_READ_CTRL_REG, ECON1) & ECON1_DMAST);
macResult = readReg(EDMACS);
bitsResult = readReg(EBSTCS);
// The checksum should be equal
return macResult == bitsResult;
}

View File

@ -0,0 +1,129 @@
// Microchip ENC28J60 Ethernet Interface Driver
// Author: Pascal Stang
// Modified by: Guido Socher
// 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.
//
// 2010-05-20 <jc@wippler.nl>
//
//-----------------------------------------------------------------
// Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
// Home: http://www.serasidis.gr
// email: avrsite@yahoo.gr
//
// PIN Connections (Using STM32F103):
//
// ENC28J60 - STM32F103
// VCC - 3.3V
// GND - GND
// SCK - Pin PA5
// SO - Pin PA6
// SI - Pin PA7
// CS - Pin PA8
//-----------------------------------------------------------------
#ifndef ENC28J60_H
#define ENC28J60_H
/** This class provide low-level interfacing with the ENC28J60 network interface. This is used by the EtherCard class and not intended for use by (normal) end users. */
class ENC28J60 {
public:
static uint8_t buffer[]; //!< Data buffer (shared by recieve and transmit)
static uint16_t bufferSize; //!< Size of data buffer
static bool broadcast_enabled; //!< True if broadcasts enabled (used to allow temporary disable of broadcast for DHCP or other internal functions)
static uint8_t* tcpOffset () { return buffer + 0x36; } //!< Pointer to the start of TCP payload
/** @brief Initialise SPI interface
* @note Configures Arduino pins as input / output, etc.
*/
static void initSPI ();
/** @brief Initialise network interface
* @param size Size of data buffer
* @param macaddr Pointer to 6 byte hardware (MAC) address
* @param csPin Arduino pin used for chip select (enable network interface SPI bus). Default = 8 = PA9
* @return <i>uint8_t</i> ENC28J60 firmware version or zero on failure.
*/
static uint8_t initialize (const uint16_t size, const uint8_t* macaddr,
uint8_t csPin = PA8);
/** @brief Check if network link is connected
* @return <i>bool</i> True if link is up
*/
static bool isLinkUp ();
/** @brief Sends data to network interface
* @param len Size of data to send
* @note Data buffer is shared by recieve and transmit functions
*/
static void packetSend (uint16_t len);
/** @brief Copy recieved packets to data buffer
* @return <i>uint16_t</i> Size of recieved data
* @note Data buffer is shared by recieve and transmit functions
*/
static uint16_t packetReceive ();
/** @brief Copy data from ENC28J60 memory
* @param page Data page of memory
* @param data Pointer to buffer to copy data to
*/
static void copyout (uint8_t page, const uint8_t* data);
/** @brief Copy data to ENC28J60 memory
* @param page Data page of memory
* @param data Pointer to buffer to copy data from
*/
static void copyin (uint8_t page, uint8_t* data);
/** @brief Get single byte of data from ENC28J60 memory
* @param page Data page of memory
* @param off Offset of data within page
* @return Data value
*/
static uint8_t peekin (uint8_t page, uint8_t off);
/** @brief Put ENC28J60 in sleep mode
*/
static void powerDown(); // contrib by Alex M.
/** @brief Wake ENC28J60 from sleep mode
*/
static void powerUp(); // contrib by Alex M.
/** @brief Enable reception of broadcast messages
* @param temporary Set true to temporarily enable broadcast
* @note This will increase load on recieved data handling
*/
static void enableBroadcast(bool temporary = false);
/** @brief Disable reception of broadcast messages
* @param temporary Set true to only disable if temporarily enabled
* @note This will reduce load on recieved data handling
*/
static void disableBroadcast(bool temporary = false);
/** @brief Enables reception of mulitcast messages
* @note This will increase load on recieved data handling
*/
static void enableMulticast ();
/** @brief Disable reception of mulitcast messages
* @note This will reduce load on recieved data handling
*/
static void disableMulticast();
/** @brief Reset and fully initialise ENC28J60
* @param csPin Arduino pin used for chip select (enable SPI bus)
* @return <i>uint8_t</i> 0 on failure
*/
static uint8_t doBIST(uint8_t csPin = PA8);
};
typedef ENC28J60 Ethernet; //!< Define alias Ethernet for ENC28J60
#endif

View File

@ -0,0 +1,123 @@
// Based on the net.h file from the AVRlib library by Pascal Stang.
// Author: Guido Socher
// Copyright: GPL V2
//
// For AVRlib See http://www.procyonengineering.com/
// Used with explicit permission of Pascal Stang.
//
// 2010-05-20 <jc@wippler.nl>
// notation: _P = position of a field
// _V = value of a field
#ifndef NET_H
#define NET_H
// ******* ETH *******
#define ETH_HEADER_LEN 14
// values of certain bytes:
#define ETHTYPE_ARP_H_V 0x08
#define ETHTYPE_ARP_L_V 0x06
#define ETHTYPE_IP_H_V 0x08
#define ETHTYPE_IP_L_V 0x00
// byte positions in the ethernet frame:
//
// Ethernet type field (2bytes):
#define ETH_TYPE_H_P 12
#define ETH_TYPE_L_P 13
//
#define ETH_DST_MAC 0
#define ETH_SRC_MAC 6
// ******* ARP *******
#define ETH_ARP_OPCODE_REPLY_H_V 0x0
#define ETH_ARP_OPCODE_REPLY_L_V 0x02
#define ETH_ARP_OPCODE_REQ_H_V 0x0
#define ETH_ARP_OPCODE_REQ_L_V 0x01
// start of arp header:
#define ETH_ARP_P 0xe
//
#define ETHTYPE_ARP_L_V 0x06
// arp.dst.ip
#define ETH_ARP_DST_IP_P 0x26
// arp.opcode
#define ETH_ARP_OPCODE_H_P 0x14
#define ETH_ARP_OPCODE_L_P 0x15
// arp.src.mac
#define ETH_ARP_SRC_MAC_P 0x16
#define ETH_ARP_SRC_IP_P 0x1c
#define ETH_ARP_DST_MAC_P 0x20
#define ETH_ARP_DST_IP_P 0x26
// ******* IP *******
#define IP_HEADER_LEN 20
// ip.src
#define IP_SRC_P 0x1a
#define IP_DST_P 0x1e
#define IP_HEADER_LEN_VER_P 0xe
#define IP_CHECKSUM_P 0x18
#define IP_TTL_P 0x16
#define IP_FLAGS_P 0x14
#define IP_P 0xe
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11
#define IP_PROTO_P 0x17
#define IP_PROTO_ICMP_V 1
#define IP_PROTO_TCP_V 6
// 17=0x11
#define IP_PROTO_UDP_V 17
// ******* ICMP *******
#define ICMP_TYPE_ECHOREPLY_V 0
#define ICMP_TYPE_ECHOREQUEST_V 8
//
#define ICMP_TYPE_P 0x22
#define ICMP_CHECKSUM_P 0x24
#define ICMP_CHECKSUM_H_P 0x24
#define ICMP_CHECKSUM_L_P 0x25
#define ICMP_IDENT_H_P 0x26
#define ICMP_IDENT_L_P 0x27
#define ICMP_DATA_P 0x2a
// ******* UDP *******
#define UDP_HEADER_LEN 8
//
#define UDP_SRC_PORT_H_P 0x22
#define UDP_SRC_PORT_L_P 0x23
#define UDP_DST_PORT_H_P 0x24
#define UDP_DST_PORT_L_P 0x25
//
#define UDP_LEN_H_P 0x26
#define UDP_LEN_L_P 0x27
#define UDP_CHECKSUM_H_P 0x28
#define UDP_CHECKSUM_L_P 0x29
#define UDP_DATA_P 0x2a
// ******* TCP *******
#define TCP_SRC_PORT_H_P 0x22
#define TCP_SRC_PORT_L_P 0x23
#define TCP_DST_PORT_H_P 0x24
#define TCP_DST_PORT_L_P 0x25
// the tcp seq number is 4 bytes 0x26-0x29
#define TCP_SEQ_H_P 0x26
#define TCP_SEQACK_H_P 0x2a
// flags: SYN=2
#define TCP_FLAGS_P 0x2f
#define TCP_FLAGS_SYN_V 2
#define TCP_FLAGS_FIN_V 1
#define TCP_FLAGS_RST_V 4
#define TCP_FLAGS_PUSH_V 8
#define TCP_FLAGS_SYNACK_V 0x12
#define TCP_FLAGS_ACK_V 0x10
#define TCP_FLAGS_PSHACK_V 0x18
// plain len without the options:
#define TCP_HEADER_LEN_PLAIN 20
#define TCP_HEADER_LEN_P 0x2e
#define TCP_WIN_SIZE 0x30
#define TCP_CHECKSUM_H_P 0x32
#define TCP_CHECKSUM_L_P 0x33
#define TCP_OPTIONS_P 0x36
//
#endif

View File

@ -0,0 +1,803 @@
// IP, ARP, UDP and TCP functions.
// Author: Guido Socher
// Copyright: GPL V2
//
// The TCP implementation uses some size optimisations which are valid
// only if all data can be sent in one single packet. This is however
// not a big limitation for a microcontroller as you will anyhow use
// small web-pages. The web server must send the entire web page in one
// packet. The client "web browser" as implemented here can also receive
// large pages.
//
// 2010-05-20 <jc@wippler.nl>
#include "EtherCard_STM.h"
#include "net.h"
#undef word // arduino nonsense
#define gPB ether.buffer
#define PINGPATTERN 0x42
// Avoid spurious pgmspace warnings - http://forum.jeelabs.net/node/327
// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
//#undef PROGMEM
//#define PROGMEM __attribute__(( section(".progmem.data") ))
//#undef PSTR
//#define PSTR(s) (__extension__({static prog_char c[] PROGMEM = (s); &c[0];}))
#define TCPCLIENT_SRC_PORT_H 11 //Source port (MSB) for TCP/IP client connections - hardcode all TCP/IP client connection from ports in range 2816-3071
static uint8_t tcpclient_src_port_l=1; // Source port (LSB) for tcp/ip client connections - increments on each TCP/IP request
static uint8_t tcp_fd; // a file descriptor, will be encoded into the port
static uint8_t tcp_client_state; //TCP connection state: 1=Send SYN, 2=SYN sent awaiting SYN+ACK, 3=Established, 4=Not used, 5=Closing, 6=Closed
static uint8_t tcp_client_port_h; // Destination port (MSB) of TCP/IP client connection
static uint8_t tcp_client_port_l; // Destination port (LSB) of TCP/IP client connection
static uint8_t (*client_tcp_result_cb)(uint8_t,uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle response to current TCP/IP request
static uint16_t (*client_tcp_datafill_cb)(uint8_t); //Pointer to callback function to handle payload data in response to current TCP/IP request
static uint8_t www_fd; // ID of current http request (only one http request at a time - one of the 8 possible concurrent TCP/IP connections)
static void (*client_browser_cb)(uint8_t,uint16_t,uint16_t); // Pointer to callback function to handle result of current HTTP request
static const char *client_additionalheaderline; // Pointer to c-string additional http request header info
static const char *client_postval;
static const char *client_urlbuf; // Pointer to c-string path part of HTTP request URL
static const char *client_urlbuf_var; // Pointer to c-string filename part of HTTP request URL
static const char *client_hoststr; // Pointer to c-string hostname of current HTTP request
static void (*icmp_cb)(uint8_t *ip); // Pointer to callback function for ICMP ECHO response handler (triggers when localhost recieves ping respnse (pong))
static uint8_t destmacaddr[6]; // storing both dns server and destination mac addresses, but at different times because both are never needed at same time.
static boolean waiting_for_dns_mac = false; //might be better to use bit flags and bitmask operations for these conditions
static boolean has_dns_mac = false;
static boolean waiting_for_dest_mac = false;
static boolean has_dest_mac = false;
static uint8_t gwmacaddr[6]; // Hardware (MAC) address of gateway router
static uint8_t waitgwmac; // Bitwise flags of gateway router status - see below for states
//Define gatweay router ARP statuses
#define WGW_INITIAL_ARP 1 // First request, no answer yet
#define WGW_HAVE_GW_MAC 2 // Have gateway router MAC
#define WGW_REFRESHING 4 // Refreshing but already have gateway MAC
#define WGW_ACCEPT_ARP_REPLY 8 // Accept an ARP reply
static uint16_t info_data_len; // Length of TCP/IP payload
static uint8_t seqnum = 0xa; // My initial tcp sequence number
static uint8_t result_fd = 123; // Session id of last reply
static const char* result_ptr; // Pointer to TCP/IP data
static unsigned long SEQ; // TCP/IP sequence number
#define CLIENTMSS 550
#define TCP_DATA_START ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4) // Get offset of TCP/IP payload data
const unsigned char arpreqhdr[] PROGMEM = { 0,1,8,0,6,4,0,1 }; // ARP request header
const unsigned char iphdr[] PROGMEM = { 0x45,0,0,0x82,0,0,0x40,0,0x20 }; //IP header
const unsigned char ntpreqhdr[] PROGMEM = { 0xE3,0,4,0xFA,0,1,0,0,0,1 }; //NTP request header
const uint8_t allOnes[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // Used for hardware (MAC) and IP broadcast addresses
static void fill_checksum(uint8_t dest, uint8_t off, uint16_t len,uint8_t type) {
const uint8_t* ptr = gPB + off;
uint32_t sum = type==1 ? IP_PROTO_UDP_V+len-8 :
type==2 ? IP_PROTO_TCP_V+len-8 : 0;
while(len >1) {
sum += (uint16_t) (((uint32_t)*ptr<<8)|*(ptr+1));
ptr+=2;
len-=2;
}
if (len)
sum += ((uint32_t)*ptr)<<8;
while (sum>>16)
sum = (uint16_t) sum + (sum >> 16);
uint16_t ck = ~ (uint16_t) sum;
gPB[dest] = ck>>8;
gPB[dest+1] = ck;
}
static void setMACs (const uint8_t *mac) {
EtherCard::copyMac(gPB + ETH_DST_MAC, mac);
EtherCard::copyMac(gPB + ETH_SRC_MAC, EtherCard::mymac);
}
static void setMACandIPs (const uint8_t *mac, const uint8_t *dst) {
setMACs(mac);
EtherCard::copyIp(gPB + IP_DST_P, dst);
EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip);
}
static uint8_t check_ip_message_is_from(const uint8_t *ip) {
return memcmp(gPB + IP_SRC_P, ip, 4) == 0;
}
static boolean is_lan(const uint8_t source[4], const uint8_t destination[4]) {
if(source[0] == 0 || destination[0] == 0) {
return false;
}
for(int i = 0; i < 4; i++)
if((source[i] & EtherCard::netmask[i]) != (destination[i] & EtherCard::netmask[i])) {
return false;
}
return true;
}
static uint8_t eth_type_is_arp_and_my_ip(uint16_t len) {
return len >= 41 && gPB[ETH_TYPE_H_P] == ETHTYPE_ARP_H_V &&
gPB[ETH_TYPE_L_P] == ETHTYPE_ARP_L_V &&
memcmp(gPB + ETH_ARP_DST_IP_P, EtherCard::myip, 4) == 0;
}
static uint8_t eth_type_is_ip_and_my_ip(uint16_t len) {
return len >= 42 && gPB[ETH_TYPE_H_P] == ETHTYPE_IP_H_V &&
gPB[ETH_TYPE_L_P] == ETHTYPE_IP_L_V &&
gPB[IP_HEADER_LEN_VER_P] == 0x45 &&
(memcmp(gPB + IP_DST_P, EtherCard::myip, 4) == 0 //not my IP
|| (memcmp(gPB + IP_DST_P, EtherCard::broadcastip, 4) == 0) //not subnet broadcast
|| (memcmp(gPB + IP_DST_P, allOnes, 4) == 0)); //not global broadcasts
//!@todo Handle multicast
}
static void fill_ip_hdr_checksum() {
gPB[IP_CHECKSUM_P] = 0;
gPB[IP_CHECKSUM_P+1] = 0;
gPB[IP_FLAGS_P] = 0x40; // don't fragment
gPB[IP_FLAGS_P+1] = 0; // fragement offset
gPB[IP_TTL_P] = 64; // ttl
fill_checksum(IP_CHECKSUM_P, IP_P, IP_HEADER_LEN,0);
}
static void make_eth_ip() {
setMACs(gPB + ETH_SRC_MAC);
EtherCard::copyIp(gPB + IP_DST_P, gPB + IP_SRC_P);
EtherCard::copyIp(gPB + IP_SRC_P, EtherCard::myip);
fill_ip_hdr_checksum();
}
static void step_seq(uint16_t rel_ack_num,uint8_t cp_seq) {
uint8_t i;
uint8_t tseq;
i = 4;
while(i>0) {
rel_ack_num = gPB[TCP_SEQ_H_P+i-1]+rel_ack_num;
tseq = gPB[TCP_SEQACK_H_P+i-1];
gPB[TCP_SEQACK_H_P+i-1] = rel_ack_num;
if (cp_seq)
gPB[TCP_SEQ_H_P+i-1] = tseq;
else
gPB[TCP_SEQ_H_P+i-1] = 0; // some preset value
rel_ack_num = rel_ack_num>>8;
i--;
}
}
static void make_tcphead(uint16_t rel_ack_num,uint8_t cp_seq) {
uint8_t i = gPB[TCP_DST_PORT_H_P];
gPB[TCP_DST_PORT_H_P] = gPB[TCP_SRC_PORT_H_P];
gPB[TCP_SRC_PORT_H_P] = i;
uint8_t j = gPB[TCP_DST_PORT_L_P];
gPB[TCP_DST_PORT_L_P] = gPB[TCP_SRC_PORT_L_P];
gPB[TCP_SRC_PORT_L_P] = j;
step_seq(rel_ack_num,cp_seq);
gPB[TCP_CHECKSUM_H_P] = 0;
gPB[TCP_CHECKSUM_L_P] = 0;
gPB[TCP_HEADER_LEN_P] = 0x50;
}
static void make_arp_answer_from_request() {
setMACs(gPB + ETH_SRC_MAC);
gPB[ETH_ARP_OPCODE_H_P] = ETH_ARP_OPCODE_REPLY_H_V;
gPB[ETH_ARP_OPCODE_L_P] = ETH_ARP_OPCODE_REPLY_L_V;
EtherCard::copyMac(gPB + ETH_ARP_DST_MAC_P, gPB + ETH_ARP_SRC_MAC_P);
EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac);
EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, gPB + ETH_ARP_SRC_IP_P);
EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip);
EtherCard::packetSend(42);
}
static void make_echo_reply_from_request(uint16_t len) {
make_eth_ip();
gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREPLY_V;
if (gPB[ICMP_CHECKSUM_P] > (0xFF-0x08))
gPB[ICMP_CHECKSUM_P+1]++;
gPB[ICMP_CHECKSUM_P] += 0x08;
EtherCard::packetSend(len);
}
void EtherCard::makeUdpReply (const char *data,uint8_t datalen,uint16_t port) {
if (datalen>220)
datalen = 220;
gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >>8;
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
make_eth_ip();
gPB[UDP_DST_PORT_H_P] = gPB[UDP_SRC_PORT_H_P];
gPB[UDP_DST_PORT_L_P] = gPB[UDP_SRC_PORT_L_P];
gPB[UDP_SRC_PORT_H_P] = port>>8;
gPB[UDP_SRC_PORT_L_P] = port;
gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >> 8;
gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen;
gPB[UDP_CHECKSUM_H_P] = 0;
gPB[UDP_CHECKSUM_L_P] = 0;
memcpy(gPB + UDP_DATA_P, data, datalen);
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1);
packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen);
}
static void make_tcp_synack_from_syn() {
gPB[IP_TOTLEN_H_P] = 0;
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4;
make_eth_ip();
gPB[TCP_FLAGS_P] = TCP_FLAGS_SYNACK_V;
make_tcphead(1,0);
gPB[TCP_SEQ_H_P+0] = 0;
gPB[TCP_SEQ_H_P+1] = 0;
gPB[TCP_SEQ_H_P+2] = seqnum;
gPB[TCP_SEQ_H_P+3] = 0;
seqnum += 3;
gPB[TCP_OPTIONS_P] = 2;
gPB[TCP_OPTIONS_P+1] = 4;
gPB[TCP_OPTIONS_P+2] = 0x05;
gPB[TCP_OPTIONS_P+3] = 0x0;
gPB[TCP_HEADER_LEN_P] = 0x60;
gPB[TCP_WIN_SIZE] = 0x5; // 1400=0x578
gPB[TCP_WIN_SIZE+1] = 0x78;
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+4,2);
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+4+ETH_HEADER_LEN);
}
static uint16_t get_tcp_data_len() {
int16_t i = (((int16_t)gPB[IP_TOTLEN_H_P])<<8)|gPB[IP_TOTLEN_L_P];
i -= IP_HEADER_LEN;
i -= (gPB[TCP_HEADER_LEN_P]>>4)*4; // generate len in bytes;
if (i<=0)
i = 0;
return (uint16_t)i;
}
static void make_tcp_ack_from_any(int16_t datlentoack,uint8_t addflags) {
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|addflags;
if (addflags!=TCP_FLAGS_RST_V && datlentoack==0)
datlentoack = 1;
make_tcphead(datlentoack,1); // no options
uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN;
gPB[IP_TOTLEN_H_P] = j>>8;
gPB[IP_TOTLEN_L_P] = j;
make_eth_ip();
gPB[TCP_WIN_SIZE] = 0x4; // 1024=0x400, 1280=0x500 2048=0x800 768=0x300
gPB[TCP_WIN_SIZE+1] = 0;
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN,2);
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN);
}
static void make_tcp_ack_with_data_noflags(uint16_t dlen) {
uint16_t j = IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen;
gPB[IP_TOTLEN_H_P] = j>>8;
gPB[IP_TOTLEN_L_P] = j;
fill_ip_hdr_checksum();
gPB[TCP_CHECKSUM_H_P] = 0;
gPB[TCP_CHECKSUM_L_P] = 0;
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8+TCP_HEADER_LEN_PLAIN+dlen,2);
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+dlen+ETH_HEADER_LEN);
}
void EtherCard::httpServerReply (uint16_t dlen) {
make_tcp_ack_from_any(info_data_len,0); // send ack for http get
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V;
make_tcp_ack_with_data_noflags(dlen); // send data
}
static void get_seq() { //get the sequence number of packets after an ack from GET
SEQ =(((unsigned long)gPB[TCP_SEQ_H_P]*256+gPB[TCP_SEQ_H_P+1])*256+gPB[TCP_SEQ_H_P+2])*256+gPB[TCP_SEQ_H_P+3];
} //thanks to mstuetz for the missing (unsigned long)
static void set_seq() { //set the correct sequence number and calculate the next with the lenght of current packet
gPB[TCP_SEQ_H_P]= (SEQ & 0xff000000 ) >> 24;
gPB[TCP_SEQ_H_P+1]= (SEQ & 0xff0000 ) >> 16;
gPB[TCP_SEQ_H_P+2]= (SEQ & 0xff00 ) >> 8;
gPB[TCP_SEQ_H_P+3]= (SEQ & 0xff );
}
void EtherCard::httpServerReplyAck () {
make_tcp_ack_from_any(info_data_len,0); // send ack for http get
get_seq(); //get the sequence number of packets after an ack from GET
}
void EtherCard::httpServerReply_with_flags (uint16_t dlen , uint8_t flags) {
set_seq();
gPB[TCP_FLAGS_P] = flags; // final packet
make_tcp_ack_with_data_noflags(dlen); // send data
SEQ=SEQ+dlen;
}
void EtherCard::clientIcmpRequest(const uint8_t *destip) {
if(is_lan(EtherCard::myip, destip)) {
setMACandIPs(destmacaddr, destip);
} else
setMACandIPs(gwmacaddr, destip);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_L_P] = 0x54;
gPB[IP_PROTO_P] = IP_PROTO_ICMP_V;
fill_ip_hdr_checksum();
gPB[ICMP_TYPE_P] = ICMP_TYPE_ECHOREQUEST_V;
gPB[ICMP_TYPE_P+1] = 0; // code
gPB[ICMP_CHECKSUM_H_P] = 0;
gPB[ICMP_CHECKSUM_L_P] = 0;
gPB[ICMP_IDENT_H_P] = 5; // some number
gPB[ICMP_IDENT_L_P] = EtherCard::myip[3]; // last byte of my IP
gPB[ICMP_IDENT_L_P+1] = 0; // seq number, high byte
gPB[ICMP_IDENT_L_P+2] = 1; // seq number, low byte, we send only 1 ping at a time
memset(gPB + ICMP_DATA_P, PINGPATTERN, 56);
fill_checksum(ICMP_CHECKSUM_H_P, ICMP_TYPE_P, 56+8,0);
packetSend(98);
}
void EtherCard::ntpRequest (uint8_t *ntpip,uint8_t srcport) {
if(is_lan(myip, ntpip)) {
setMACandIPs(destmacaddr, ntpip);
} else
setMACandIPs(gwmacaddr, ntpip);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_L_P] = 0x4c;
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
fill_ip_hdr_checksum();
gPB[UDP_DST_PORT_H_P] = 0;
gPB[UDP_DST_PORT_L_P] = 0x7b; // ntp = 123
gPB[UDP_SRC_PORT_H_P] = 10;
gPB[UDP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port
gPB[UDP_LEN_H_P] = 0;
gPB[UDP_LEN_L_P] = 56; // fixed len
gPB[UDP_CHECKSUM_H_P] = 0;
gPB[UDP_CHECKSUM_L_P] = 0;
memset(gPB + UDP_DATA_P, 0, 48);
memcpy_P(gPB + UDP_DATA_P,ntpreqhdr,10);
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 48,1);
packetSend(90);
}
uint8_t EtherCard::ntpProcessAnswer (uint32_t *time,uint8_t dstport_l) {
if ((dstport_l && gPB[UDP_DST_PORT_L_P]!=dstport_l) || gPB[UDP_LEN_H_P]!=0 ||
gPB[UDP_LEN_L_P]!=56 || gPB[UDP_SRC_PORT_L_P]!=0x7b)
return 0;
((uint8_t*) time)[3] = gPB[0x52];
((uint8_t*) time)[2] = gPB[0x53];
((uint8_t*) time)[1] = gPB[0x54];
((uint8_t*) time)[0] = gPB[0x55];
return 1;
}
void EtherCard::udpPrepare (uint16_t sport, const uint8_t *dip, uint16_t dport) {
if(is_lan(myip, dip)) // this works because both dns mac and destinations mac are stored in same variable - destmacaddr
setMACandIPs(destmacaddr, dip); // at different times. The program could have separate variable for dns mac, then here should be
else // checked if dip is dns ip and separately if dip is hisip and then use correct mac.
setMACandIPs(gwmacaddr, dip);
// see http://tldp.org/HOWTO/Multicast-HOWTO-2.html
// multicast or broadcast address, https://github.com/jcw/ethercard/issues/59
if ((dip[0] & 0xF0) == 0xE0 || *((unsigned long*) dip) == 0xFFFFFFFF)
EtherCard::copyMac(gPB + ETH_DST_MAC, allOnes);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_H_P] = 0;
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
gPB[UDP_DST_PORT_H_P] = (dport>>8);
gPB[UDP_DST_PORT_L_P] = dport;
gPB[UDP_SRC_PORT_H_P] = (sport>>8);
gPB[UDP_SRC_PORT_L_P] = sport;
gPB[UDP_LEN_H_P] = 0;
gPB[UDP_CHECKSUM_H_P] = 0;
gPB[UDP_CHECKSUM_L_P] = 0;
}
void EtherCard::udpTransmit (uint16_t datalen) {
gPB[IP_TOTLEN_H_P] = (IP_HEADER_LEN+UDP_HEADER_LEN+datalen) >> 8;
gPB[IP_TOTLEN_L_P] = IP_HEADER_LEN+UDP_HEADER_LEN+datalen;
fill_ip_hdr_checksum();
gPB[UDP_LEN_H_P] = (UDP_HEADER_LEN+datalen) >>8;
gPB[UDP_LEN_L_P] = UDP_HEADER_LEN+datalen;
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + datalen,1);
packetSend(UDP_HEADER_LEN+IP_HEADER_LEN+ETH_HEADER_LEN+datalen);
}
void EtherCard::sendUdp (const char *data, uint8_t datalen, uint16_t sport,
const uint8_t *dip, uint16_t dport) {
udpPrepare(sport, dip, dport);
if (datalen>220)
datalen = 220;
memcpy(gPB + UDP_DATA_P, data, datalen);
udpTransmit(datalen);
}
void EtherCard::sendWol (uint8_t *wolmac) {
setMACandIPs(allOnes, allOnes);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_L_P] = 0x82;
gPB[IP_PROTO_P] = IP_PROTO_UDP_V;
fill_ip_hdr_checksum();
gPB[UDP_DST_PORT_H_P] = 0;
gPB[UDP_DST_PORT_L_P] = 0x9; // wol = normally 9
gPB[UDP_SRC_PORT_H_P] = 10;
gPB[UDP_SRC_PORT_L_P] = 0x42; // source port does not matter
gPB[UDP_LEN_H_P] = 0;
gPB[UDP_LEN_L_P] = 110; // fixed len
gPB[UDP_CHECKSUM_H_P] = 0;
gPB[UDP_CHECKSUM_L_P] = 0;
copyMac(gPB + UDP_DATA_P, allOnes);
uint8_t pos = UDP_DATA_P;
for (uint8_t m = 0; m < 16; ++m) {
pos += 6;
copyMac(gPB + pos, wolmac);
}
fill_checksum(UDP_CHECKSUM_H_P, IP_SRC_P, 16 + 102,1);
packetSend(pos + 6);
}
// make a arp request
static void client_arp_whohas(uint8_t *ip_we_search) {
setMACs(allOnes);
gPB[ETH_TYPE_H_P] = ETHTYPE_ARP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_ARP_L_V;
memcpy_P(gPB + ETH_ARP_P,arpreqhdr,8);
memset(gPB + ETH_ARP_DST_MAC_P, 0, 6);
EtherCard::copyMac(gPB + ETH_ARP_SRC_MAC_P, EtherCard::mymac);
EtherCard::copyIp(gPB + ETH_ARP_DST_IP_P, ip_we_search);
EtherCard::copyIp(gPB + ETH_ARP_SRC_IP_P, EtherCard::myip);
EtherCard::packetSend(42);
}
uint8_t EtherCard::clientWaitingGw () {
return !(waitgwmac & WGW_HAVE_GW_MAC);
}
static uint8_t client_store_mac(uint8_t *source_ip, uint8_t *mac) {
if (memcmp(gPB + ETH_ARP_SRC_IP_P, source_ip, 4) != 0)
return 0;
EtherCard::copyMac(mac, gPB + ETH_ARP_SRC_MAC_P);
return 1;
}
// static void client_gw_arp_refresh() {
// if (waitgwmac & WGW_HAVE_GW_MAC)
// waitgwmac |= WGW_REFRESHING;
// }
void EtherCard::setGwIp (const uint8_t *gwipaddr) {
delaycnt = 0; //request gateway ARP lookup
waitgwmac = WGW_INITIAL_ARP; // causes an arp request in the packet loop
copyIp(gwip, gwipaddr);
}
void EtherCard::updateBroadcastAddress()
{
for(uint8_t i=0; i<4; i++)
broadcastip[i] = myip[i] | ~netmask[i];
}
static void client_syn(uint8_t srcport,uint8_t dstport_h,uint8_t dstport_l) {
if(is_lan(EtherCard::myip, EtherCard::hisip)) {
setMACandIPs(destmacaddr, EtherCard::hisip);
} else
setMACandIPs(gwmacaddr, EtherCard::hisip);
gPB[ETH_TYPE_H_P] = ETHTYPE_IP_H_V;
gPB[ETH_TYPE_L_P] = ETHTYPE_IP_L_V;
memcpy_P(gPB + IP_P,iphdr,9);
gPB[IP_TOTLEN_L_P] = 44; // good for syn
gPB[IP_PROTO_P] = IP_PROTO_TCP_V;
fill_ip_hdr_checksum();
gPB[TCP_DST_PORT_H_P] = dstport_h;
gPB[TCP_DST_PORT_L_P] = dstport_l;
gPB[TCP_SRC_PORT_H_P] = TCPCLIENT_SRC_PORT_H;
gPB[TCP_SRC_PORT_L_P] = srcport; // lower 8 bit of src port
memset(gPB + TCP_SEQ_H_P, 0, 8);
gPB[TCP_SEQ_H_P+2] = seqnum;
seqnum += 3;
gPB[TCP_HEADER_LEN_P] = 0x60; // 0x60=24 len: (0x60>>4) * 4
gPB[TCP_FLAGS_P] = TCP_FLAGS_SYN_V;
gPB[TCP_WIN_SIZE] = 0x3; // 1024 = 0x400 768 = 0x300, initial window
gPB[TCP_WIN_SIZE+1] = 0x0;
gPB[TCP_CHECKSUM_H_P] = 0;
gPB[TCP_CHECKSUM_L_P] = 0;
gPB[TCP_CHECKSUM_L_P+1] = 0;
gPB[TCP_CHECKSUM_L_P+2] = 0;
gPB[TCP_OPTIONS_P] = 2;
gPB[TCP_OPTIONS_P+1] = 4;
gPB[TCP_OPTIONS_P+2] = (CLIENTMSS>>8);
gPB[TCP_OPTIONS_P+3] = (uint8_t) CLIENTMSS;
fill_checksum(TCP_CHECKSUM_H_P, IP_SRC_P, 8 +TCP_HEADER_LEN_PLAIN+4,2);
// 4 is the tcp mss option:
EtherCard::packetSend(IP_HEADER_LEN+TCP_HEADER_LEN_PLAIN+ETH_HEADER_LEN+4);
}
uint8_t EtherCard::clientTcpReq (uint8_t (*result_cb)(uint8_t,uint8_t,uint16_t,uint16_t),
uint16_t (*datafill_cb)(uint8_t),uint16_t port) {
client_tcp_result_cb = result_cb;
client_tcp_datafill_cb = datafill_cb;
tcp_client_port_h = port>>8;
tcp_client_port_l = port;
tcp_client_state = 1; // Flag to packetloop to initiate a TCP/IP session by send a syn
tcp_fd = (tcp_fd + 1) & 7;
return tcp_fd;
}
static uint16_t www_client_internal_datafill_cb(uint8_t fd) {
BufferFiller bfill = EtherCard::tcpOffset();
if (fd==www_fd) {
if (client_postval == 0) {
bfill.emit_p(PSTR("GET $F$S HTTP/1.0\r\n"
"Host: $F\r\n"
"$F\r\n"
"\r\n"), client_urlbuf,
client_urlbuf_var,
client_hoststr, client_additionalheaderline);
} else {
const char* ahl = client_additionalheaderline;
bfill.emit_p(PSTR("POST $F HTTP/1.0\r\n"
"Host: $F\r\n"
"$F$S"
"Accept: */*\r\n"
"Content-Length: $D\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n"
"$S"), client_urlbuf,
client_hoststr,
ahl != 0 ? ahl : PSTR(""),
ahl != 0 ? "\r\n" : "",
strlen(client_postval),
client_postval);
}
}
return bfill.position();
}
static uint8_t www_client_internal_result_cb(uint8_t fd, uint8_t statuscode, uint16_t datapos, uint16_t len_of_data) {
if (fd!=www_fd)
(*client_browser_cb)(4,0,0);
else if (statuscode==0 && len_of_data>12 && client_browser_cb) {
uint8_t f = strncmp("200",(char *)&(gPB[datapos+9]),3) != 0;
(*client_browser_cb)(f, ((uint16_t)TCP_SRC_PORT_H_P+(gPB[TCP_HEADER_LEN_P]>>4)*4),len_of_data);
}
return 0;
}
void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, void (*callback)(uint8_t,uint16_t,uint16_t)) {
browseUrl(urlbuf, urlbuf_varpart, hoststr, PSTR("Accept: text/html"), callback);
}
void EtherCard::browseUrl (const char *urlbuf, const char *urlbuf_varpart, const char *hoststr, const char *additionalheaderline, void (*callback)(uint8_t,uint16_t,uint16_t)) {
client_urlbuf = urlbuf;
client_urlbuf_var = urlbuf_varpart;
client_hoststr = hoststr;
client_additionalheaderline = additionalheaderline;
client_postval = 0;
client_browser_cb = callback;
www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport);
}
void EtherCard::httpPost (const char *urlbuf, const char *hoststr, const char *additionalheaderline, const char *postval, void (*callback)(uint8_t,uint16_t,uint16_t)) {
client_urlbuf = urlbuf;
client_hoststr = hoststr;
client_additionalheaderline = additionalheaderline;
client_postval = postval;
client_browser_cb = callback;
www_fd = clientTcpReq(&www_client_internal_result_cb,&www_client_internal_datafill_cb,hisport);
}
static uint16_t tcp_datafill_cb(uint8_t fd) {
uint16_t len = Stash::length();
Stash::extract(0, len, EtherCard::tcpOffset());
Stash::cleanup();
EtherCard::tcpOffset()[len] = 0;
#if SERIAL
Serial.print("REQUEST: ");
Serial.println(len);
Serial.println((char*) EtherCard::tcpOffset());
#endif
result_fd = 123; // bogus value
return len;
}
static uint8_t tcp_result_cb(uint8_t fd, uint8_t status, uint16_t datapos, uint16_t datalen) {
if (status == 0) {
result_fd = fd; // a valid result has been received, remember its session id
result_ptr = (char*) ether.buffer + datapos;
// result_ptr[datalen] = 0;
}
return 1;
}
uint8_t EtherCard::tcpSend () {
www_fd = clientTcpReq(&tcp_result_cb, &tcp_datafill_cb, hisport);
return www_fd;
}
const char* EtherCard::tcpReply (uint8_t fd) {
if (result_fd != fd)
return 0;
result_fd = 123; // set to a bogus value to prevent future match
return result_ptr;
}
void EtherCard::registerPingCallback (void (*callback)(uint8_t *srcip)) {
icmp_cb = callback;
}
uint8_t EtherCard::packetLoopIcmpCheckReply (const uint8_t *ip_monitoredhost) {
return gPB[IP_PROTO_P]==IP_PROTO_ICMP_V &&
gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREPLY_V &&
gPB[ICMP_DATA_P]== PINGPATTERN &&
check_ip_message_is_from(ip_monitoredhost);
}
uint16_t EtherCard::accept(const uint16_t port, uint16_t plen) {
uint16_t pos;
if (gPB[TCP_DST_PORT_H_P] == (port >> 8) &&
gPB[TCP_DST_PORT_L_P] == ((uint8_t) port))
{ //Packet targetted at specified port
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V)
make_tcp_synack_from_syn(); //send SYN+ACK
else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
{ //This is an acknowledgement to our SYN+ACK so let's start processing that payload
info_data_len = get_tcp_data_len();
if (info_data_len > 0)
{ //Got some data
pos = TCP_DATA_START; // TCP_DATA_START is a formula
if (pos <= plen - 8)
return pos;
}
else if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V)
make_tcp_ack_from_any(0,0); //No data so close connection
}
}
return 0;
}
uint16_t EtherCard::packetLoop (uint16_t plen) {
uint16_t len;
if(using_dhcp){
ether.DhcpStateMachine(plen);
}
if (plen==0) {
//Check every 65536 (no-packet) cycles whether we need to retry ARP request for gateway
if ((waitgwmac & WGW_INITIAL_ARP || waitgwmac & WGW_REFRESHING) &&
delaycnt==0 && isLinkUp()) {
client_arp_whohas(gwip);
waitgwmac |= WGW_ACCEPT_ARP_REPLY;
}
delaycnt++;
//Initiate TCP/IP session if pending
if (tcp_client_state==1 && (waitgwmac & WGW_HAVE_GW_MAC)) { // send a syn
tcp_client_state = 2;
tcpclient_src_port_l++; // allocate a new port
client_syn(((tcp_fd<<5) | (0x1f & tcpclient_src_port_l)),tcp_client_port_h,tcp_client_port_l);
}
//!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed.
if(is_lan(myip, dnsip) && !has_dns_mac && !waiting_for_dns_mac) {
client_arp_whohas(dnsip);
waiting_for_dns_mac = true;
}
//!@todo this is trying to find mac only once. Need some timeout to make another call if first one doesn't succeed.
if(is_lan(myip, hisip) && !has_dest_mac && !waiting_for_dest_mac) {
client_arp_whohas(hisip);
waiting_for_dest_mac = true;
}
return 0;
}
if (eth_type_is_arp_and_my_ip(plen))
{ //Service ARP request
if (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REQ_L_V)
make_arp_answer_from_request();
if (waitgwmac & WGW_ACCEPT_ARP_REPLY && (gPB[ETH_ARP_OPCODE_L_P]==ETH_ARP_OPCODE_REPLY_L_V) && client_store_mac(gwip, gwmacaddr))
waitgwmac = WGW_HAVE_GW_MAC;
if (!has_dns_mac && waiting_for_dns_mac && client_store_mac(dnsip, destmacaddr)) {
has_dns_mac = true;
waiting_for_dns_mac = false;
}
if (!has_dest_mac && waiting_for_dest_mac && client_store_mac(hisip, destmacaddr)){
has_dest_mac = true;
waiting_for_dest_mac = false;
}
return 0;
}
if (eth_type_is_ip_and_my_ip(plen)==0)
{ //Not IP so ignoring
//!@todo Add other protocols (and make each optional at compile time)
return 0;
}
if (gPB[IP_PROTO_P]==IP_PROTO_ICMP_V && gPB[ICMP_TYPE_P]==ICMP_TYPE_ECHOREQUEST_V)
{ //Service ICMP echo request (ping)
if (icmp_cb)
(*icmp_cb)(&(gPB[IP_SRC_P]));
make_echo_reply_from_request(plen);
return 0;
}
if (ether.udpServerListening() && gPB[IP_PROTO_P]==IP_PROTO_UDP_V)
{ //Call UDP server handler (callback) if one is defined for this packet
if(ether.udpServerHasProcessedPacket(plen))
return 0; //An UDP server handler (callback) has processed this packet
}
if (plen<54 && gPB[IP_PROTO_P]!=IP_PROTO_TCP_V )
return 0; //Packet flagged as TCP but shorter than minimum TCP packet length
if (gPB[TCP_DST_PORT_H_P]==TCPCLIENT_SRC_PORT_H)
{ //Source port is in range reserved (by EtherCard) for client TCP/IP connections
if (check_ip_message_is_from(hisip)==0)
return 0; //Not current TCP/IP connection (only handle one at a time)
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_RST_V)
{ //TCP reset flagged
if (client_tcp_result_cb)
(*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,3,0,0);
tcp_client_state = 5;
return 0;
}
len = get_tcp_data_len();
if (tcp_client_state==2)
{ //Waiting for SYN-ACK
if ((gPB[TCP_FLAGS_P] & TCP_FLAGS_SYN_V) && (gPB[TCP_FLAGS_P] &TCP_FLAGS_ACK_V))
{ //SYN and ACK flags set so this is an acknowledgement to our SYN
make_tcp_ack_from_any(0,0);
gPB[TCP_FLAGS_P] = TCP_FLAGS_ACK_V|TCP_FLAGS_PUSH_V;
if (client_tcp_datafill_cb)
len = (*client_tcp_datafill_cb)((gPB[TCP_SRC_PORT_L_P]>>5)&0x7);
else
len = 0;
tcp_client_state = 3;
make_tcp_ack_with_data_noflags(len);
}
else
{ //Expecting SYN+ACK so reset and resend SYN
tcp_client_state = 1; // retry
len++;
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_ACK_V)
len = 0;
make_tcp_ack_from_any(len,TCP_FLAGS_RST_V);
}
return 0;
}
if (tcp_client_state==3 && len>0)
{ //TCP connection established so read data
if (client_tcp_result_cb) {
uint16_t tcpstart = TCP_DATA_START; // TCP_DATA_START is a formula
if (tcpstart>plen-8)
tcpstart = plen-8; // dummy but save
uint16_t save_len = len;
if (tcpstart+len>plen)
save_len = plen-tcpstart;
(*client_tcp_result_cb)((gPB[TCP_DST_PORT_L_P]>>5)&0x7,0,tcpstart,save_len); //Call TCP handler (callback) function
if(persist_tcp_connection)
{ //Keep connection alive by sending ACK
make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V);
}
else
{ //Close connection
make_tcp_ack_from_any(len,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
tcp_client_state = 6;
}
return 0;
}
}
if (tcp_client_state != 5)
{ //
if (gPB[TCP_FLAGS_P] & TCP_FLAGS_FIN_V) {
if(tcp_client_state == 3) {
return 0; // In some instances FIN is received *before* DATA. If that is the case, we just return here and keep looking for the data packet
}
make_tcp_ack_from_any(len+1,TCP_FLAGS_PUSH_V|TCP_FLAGS_FIN_V);
tcp_client_state = 6; // connection terminated
} else if (len>0) {
make_tcp_ack_from_any(len,0);
}
}
return 0;
}
//If we are here then this is a TCP/IP packet targetted at us and not related to out client connection so accept
return accept(hisport, plen);
}
void EtherCard::persistTcpConnection(bool persist){
persist_tcp_connection = persist;
}

View File

@ -0,0 +1,73 @@
// Simple UDP listening server
//
// Author: Brian Lee
//
// Copyright: GPL V2
// See http://www.gnu.org/licenses/gpl.html
#include "EtherCard_STM.h"
#include "net.h"
#define gPB ether.buffer
#define UDPSERVER_MAXLISTENERS 8 //the maximum number of port listeners.
typedef struct {
UdpServerCallback callback;
uint16_t port;
bool listening;
} UdpServerListener;
UdpServerListener listeners[UDPSERVER_MAXLISTENERS];
byte numListeners = 0;
void EtherCard::udpServerListenOnPort(UdpServerCallback callback, uint16_t port) {
if(numListeners < UDPSERVER_MAXLISTENERS)
{
listeners[numListeners] = (UdpServerListener) {
callback, port, true
};
numListeners++;
}
}
void EtherCard::udpServerPauseListenOnPort(uint16_t port) {
for(int i = 0; i < numListeners; i++)
{
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) {
listeners[i].listening = false;
}
}
}
void EtherCard::udpServerResumeListenOnPort(uint16_t port) {
for(int i = 0; i < numListeners; i++)
{
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port)) {
listeners[i].listening = true;
}
}
}
bool EtherCard::udpServerListening() {
return numListeners > 0;
}
bool EtherCard::udpServerHasProcessedPacket(uint16_t plen) {
bool packetProcessed = false;
for(int i = 0; i < numListeners; i++)
{
if(gPB[UDP_DST_PORT_H_P] == (listeners[i].port >> 8) && gPB[UDP_DST_PORT_L_P] == ((byte) listeners[i].port) && listeners[i].listening)
{
uint16_t datalen = (uint16_t) (gPB[UDP_LEN_H_P] << 8) + gPB[UDP_LEN_L_P] - UDP_HEADER_LEN;
listeners[i].callback(
listeners[i].port,
gPB + IP_SRC_P,
(gPB[UDP_SRC_PORT_H_P] << 8) | gPB[UDP_SRC_PORT_L_P],
(const char *) (gPB + UDP_DATA_P),
datalen);
packetProcessed = true;
}
}
return packetProcessed;
}

View File

@ -0,0 +1,200 @@
// Some common utilities needed for IP and web applications
// Author: Guido Socher
// Copyright: GPL V2
//
// 2010-05-20 <jc@wippler.nl>
#include "EtherCard_STM.h"
void EtherCard::copyIp (uint8_t *dst, const uint8_t *src) {
memcpy(dst, src, 4);
}
void EtherCard::copyMac (uint8_t *dst, const uint8_t *src) {
memcpy(dst, src, 6);
}
void EtherCard::printIp (const char* msg, const uint8_t *buf) {
Serial.print(msg);
EtherCard::printIp(buf);
Serial.println();
}
void EtherCard::printIp (const __FlashStringHelper *ifsh, const uint8_t *buf) {
Serial.print(ifsh);
EtherCard::printIp(buf);
Serial.println();
}
void EtherCard::printIp (const uint8_t *buf) {
for (uint8_t i = 0; i < 4; ++i) {
Serial.print( buf[i], DEC );
if (i < 3)
Serial.print('.');
}
}
// search for a string of the form key=value in
// a string that looks like q?xyz=abc&uvw=defgh HTTP/1.1\r\n
//
// The returned value is stored in strbuf. You must allocate
// enough storage for strbuf, maxlen is the size of strbuf.
// I.e the value it is declated with: strbuf[5]-> maxlen=5
uint8_t EtherCard::findKeyVal (const char *str,char *strbuf, uint8_t maxlen,const char *key)
{
uint8_t found=0;
uint8_t i=0;
const char *kp;
kp=key;
while(*str && *str!=' ' && *str!='\n' && found==0){
if (*str == *kp){
kp++;
if (*kp == '\0'){
str++;
kp=key;
if (*str == '='){
found=1;
}
}
}else{
kp=key;
}
str++;
}
if (found==1){
// copy the value to a buffer and terminate it with '\0'
while(*str && *str!=' ' && *str!='\n' && *str!='&' && i<maxlen-1){
*strbuf=*str;
i++;
str++;
strbuf++;
}
*strbuf='\0';
}
// return the length of the value
return(i);
}
// convert a single hex digit character to its integer value
unsigned char h2int(char c)
{
if (c >= '0' && c <='9'){
return((unsigned char)c - '0');
}
if (c >= 'a' && c <='f'){
return((unsigned char)c - 'a' + 10);
}
if (c >= 'A' && c <='F'){
return((unsigned char)c - 'A' + 10);
}
return(0);
}
// decode a url string e.g "hello%20joe" or "hello+joe" becomes "hello joe"
void EtherCard::urlDecode (char *urlbuf)
{
char c;
char *dst = urlbuf;
while ((c = *urlbuf) != 0) {
if (c == '+') c = ' ';
if (c == '%') {
c = *++urlbuf;
c = (h2int(c) << 4) | h2int(*++urlbuf);
}
*dst++ = c;
urlbuf++;
}
*dst = '\0';
}
// convert a single character to a 2 digit hex str
// a terminating '\0' is added
void int2h(char c, char *hstr)
{
hstr[1]=(c & 0xf)+'0';
if ((c & 0xf) >9){
hstr[1]=(c & 0xf) - 10 + 'a';
}
c=(c>>4)&0xf;
hstr[0]=c+'0';
if (c > 9){
hstr[0]=c - 10 + 'a';
}
hstr[2]='\0';
}
// there must be enough space in urlbuf. In the worst case that is
// 3 times the length of str
void EtherCard::urlEncode (char *str,char *urlbuf)
{
char c;
while ((c = *str) != 0) {
if (c == ' '||isalnum(c)){
if (c == ' '){
c = '+';
}
*urlbuf=c;
str++;
urlbuf++;
continue;
}
*urlbuf='%';
urlbuf++;
int2h(c,urlbuf);
urlbuf++;
urlbuf++;
str++;
}
*urlbuf='\0';
}
// parse a string and extract the IP to bytestr
uint8_t EtherCard::parseIp (uint8_t *bytestr,char *str)
{
char *sptr;
uint8_t i=0;
sptr=NULL;
while(i<4){
bytestr[i]=0;
i++;
}
i=0;
while(*str && i<4){
// if a number then start
if (sptr==NULL && isdigit(*str)){
sptr=str;
}
if (*str == '.'){
*str ='\0';
bytestr[i]=(atoi(sptr)&0xff);
i++;
sptr=NULL;
}
str++;
}
*str ='\0';
if (i==3){
bytestr[i]=(atoi(sptr)&0xff);
return(0);
}
return(1);
}
// take a byte string and convert it to a human readable display string (base is 10 for ip and 16 for mac addr), len is 4 for IP addr and 6 for mac.
void EtherCard::makeNetStr (char *resultstr,uint8_t *bytestr,uint8_t len,char separator,uint8_t base)
{
uint8_t i=0;
uint8_t j=0;
while(i<len){
//itoa((int)bytestr[i],&resultstr[j],base);
// search end of str:
while(resultstr[j]){j++;}
resultstr[j]=separator;
j++;
i++;
}
j--;
resultstr[j]='\0';
}
// end of webutil.c

View File

@ -1,7 +1,8 @@
Description
---
That library is for VS1003B / VS10053B WAV/MP3/AAC audio decoder. The library has been ported to work with STM32 micro-controllers.
That library is for VS1003B / VS10053B WAV/MP3/AAC audio decoder.
The library has been ported to work with STM32 micro-controllers.
A short Youtube video demonstration of the library can be found [here][A].
In that video I used an **STM32F103C8T** development board and a **VS1053B** mp3 decoder module.

View File

@ -8,6 +8,10 @@
Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
Home: http://www.serasidis.gr
email: avrsite@yahoo.gr
06 Jun 2015 - Roger Clark, added support for SPI 2 and SPI 3
29 May 2015 - Added a fix for booting the VS1053B boards into
mp3 decoding instead of booting into MID (modeSwitch function).
*/
#include <VS1003_STM.h>
@ -27,9 +31,8 @@
* GND - GND -
* 5V - 5V -
*/
VS1003_STM player(PC14, PB10, PA8, PA9); // cs_pin, dcs_pin, dreq_pin, reset_pin
unsigned char HelloMP3[] = {
static const unsigned char HelloMP3[] = {
0xFF,0xF2,0x40,0xC0,0x19,0xB7,0x00,0x14,0x02,0xE6,0x5C, /* ..@.......\ */
0x01,0x92,0x68,0x01,0xF1,0x5E,0x03,0x08,0xF0,0x24,0x80, /* ..h..^...$. */
0x05,0x9E,0x20,0xC6,0xFC,0x12,0x32,0x5C,0xBF,0xF9,0xB9, /* .. ...2\... */
@ -184,24 +187,29 @@ unsigned char HelloMP3[] = {
0x20,0x20,0x20,0x4D,0x50,0x33,0x20,0x48,0x65,0x6C,0x6C, /* MP3 Hell */
0x6F,0x2C,0x20,0x57,0x6F,0x72,0x6C,0x64,0x21,0x20,0x20, /* o, World! */
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, /* */
0x00, /* . */
0x00
};
void setup () {
VS1003 player(PC14, PB10, PA8, PA9); // cs_pin, dcs_pin, dreq_pin, reset_pin, SPI channel - defaults to SPI
/* Example of how to use the VS21003 attached to SPI 2
VS1003 player(PC14, PB10, PA8, PA9,SPIClass(2)); // cs_pin, dcs_pin, dreq_pin, reset_pin, use SPI 2
*/
/* Example of how to use the VS21003 attached to SPI 2
VS1003 player(PC14, PB10, PA8, PA9,SPIClass(3)); // cs_pin, dcs_pin, dreq_pin, reset_pin, use SPI 3
*/
void setup ()
{
Serial.begin(9600);
while (!Serial) {
; //Give some time to Serial port to be initiallized.
}
Serial.println("VS1003 test");
// initiate a player
Serial.println("VS1003 HelloMP3");
player.begin();
// set maximum output volume
player.setVolume(0x00);
player.modeSwitch(); //Change mode from MIDI to MP3 decoding (Vassilis Serasidis).
player.setVolume(0x00); // set maximum output volume
}
void loop() {
// play hellomp3 flow each 0.5s ;)
player.playChunk(HelloMP3, sizeof(HelloMP3));
delay(500);
}
player.playChunk(HelloMP3, sizeof(HelloMP3)); // play hellomp3 - this blocks until the player is ready to receive more data
delay(1000);
}

View File

@ -0,0 +1,30 @@
#######################################
# Syntax Coloring Map For VS1003
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
VS1003 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
startSong KEYWORD2
playChunk KEYWORD2
stopSong KEYWORD2
printDetails KEYWORD2
modeSwitch KEYWORD2
setVolume KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
#######################################
# Constants (LITERAL1)
#######################################

View File

@ -0,0 +1,8 @@
name=Serasidis_VS1003B_STM
version=1.0
author=Andy Karpov - ported to STM by Vasillis Serasidis. Updated by Roger Clark
email=
sentence=VS1003 and VS1053 MP3, MP3 player and recorder
paragraph=VS1003 and VS1053 MP3, MP3 player and recorder
url=
architectures=STM32F1

View File

@ -8,31 +8,14 @@
Ported to STM32F103 by Vassilis Serasidis on 21 May 2015
Home: http://www.serasidis.gr
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).
*/
// STL headers
// C headers
#include <avr/pgmspace.h>
// Framework headers
// Library headers
#include <avr/pgmspace.h>
#include <limits.h>
#include <libmaple/dma.h>
#include "pins_arduino.h"
#include "wiring_private.h"
#include <SPI.h>
// Project headers
// This component's header
//#include <my_SPI.h>
#include <VS1003_STM.h>
const uint8_t vs1003_chunk_size = 32;
#undef PROGMEM
#define PROGMEM __attribute__ ((section (".progmem.data")))
#undef PSTR
#define PSTR(s) (__extension__({static char __c[] PROGMEM = (s); &__c[0];}))
#define vs1003_chunk_size 32
/****************************************************************************/
// VS1003 SCI Write Command byte is 0x02
@ -81,24 +64,24 @@ const uint8_t SM_LINE_IN = 14;
// Register names
char reg_name_MODE[] PROGMEM = "MODE";
char reg_name_STATUS[] PROGMEM = "STATUS";
char reg_name_BASS[] PROGMEM = "BASS";
char reg_name_CLOCKF[] PROGMEM = "CLOCKF";
char reg_name_DECODE_TIME[] PROGMEM = "DECODE_TIME";
char reg_name_AUDATA[] PROGMEM = "AUDATA";
char reg_name_WRAM[] PROGMEM = "WRAM";
char reg_name_WRAMADDR[] PROGMEM = "WRAMADDR";
char reg_name_HDAT0[] PROGMEM = "HDAT0";
char reg_name_HDAT1[] PROGMEM = "HDAT1";
char reg_name_AIADDR[] PROGMEM = "AIADDR";
char reg_name_VOL[] PROGMEM = "VOL";
char reg_name_AICTRL0[] PROGMEM = "AICTRL0";
char reg_name_AICTRL1[] PROGMEM = "AICTRL1";
char reg_name_AICTRL2[] PROGMEM = "AICTRL2";
char reg_name_AICTRL3[] PROGMEM = "AICTRL3";
const char reg_name_MODE[] = "MODE";
const char reg_name_STATUS[] = "STATUS";
const char reg_name_BASS[] = "BASS";
const char reg_name_CLOCKF[] = "CLOCKF";
const char reg_name_DECODE_TIME[] = "DECODE_TIME";
const char reg_name_AUDATA[] = "AUDATA";
const char reg_name_WRAM[] = "WRAM";
const char reg_name_WRAMADDR[] = "WRAMADDR";
const char reg_name_HDAT0[] = "HDAT0";
const char reg_name_HDAT1[] = "HDAT1";
const char reg_name_AIADDR[] = "AIADDR";
const char reg_name_VOL[] = "VOL";
const char reg_name_AICTRL0[] = "AICTRL0";
const char reg_name_AICTRL1[] = "AICTRL1";
const char reg_name_AICTRL2[] = "AICTRL2";
const char reg_name_AICTRL3[] = "AICTRL3";
static PGM_P register_names[] PROGMEM =
static PGM_P const register_names[] =
{
reg_name_MODE,
reg_name_STATUS,
@ -127,15 +110,15 @@ inline void DMA1_CH3_Event() {
/****************************************************************************/
uint16_t VS1003_STM::read_register(uint8_t _reg) const
uint16_t VS1003::read_register(uint8_t _reg) const
{
uint16_t result;
control_mode_on();
delayMicroseconds(1); // tXCSS
SPI.transfer(VS_READ_COMMAND); // Read operation
SPI.transfer(_reg); // Which register
result = SPI.transfer(0xff) << 8; // read high byte
result |= SPI.transfer(0xff); // read low byte
my_SPI.transfer(VS_READ_COMMAND); // Read operation
my_SPI.transfer(_reg); // Which register
result = my_SPI.transfer(0xff) << 8; // read high byte
result |= my_SPI.transfer(0xff); // read low byte
delayMicroseconds(1); // tXCSH
await_data_request();
control_mode_off();
@ -144,14 +127,14 @@ uint16_t VS1003_STM::read_register(uint8_t _reg) const
/****************************************************************************/
void VS1003_STM::write_register(uint8_t _reg,uint16_t _value) const
void VS1003::write_register(uint8_t _reg,uint16_t _value) const
{
control_mode_on();
delayMicroseconds(1); // tXCSS
SPI.transfer(VS_WRITE_COMMAND); // Write operation
SPI.transfer(_reg); // Which register
SPI.transfer(_value >> 8); // Send hi byte
SPI.transfer(_value & 0xff); // Send lo byte
my_SPI.transfer(VS_WRITE_COMMAND); // Write operation
my_SPI.transfer(_reg); // Which register
my_SPI.transfer(_value >> 8); // Send hi byte
my_SPI.transfer(_value & 0xff); // Send lo byte
delayMicroseconds(1); // tXCSH
await_data_request();
control_mode_off();
@ -159,7 +142,7 @@ void VS1003_STM::write_register(uint8_t _reg,uint16_t _value) const
/****************************************************************************/
void VS1003_STM::sdi_send_buffer(const uint8_t* data, size_t len)
void VS1003::sdi_send_buffer(const uint8_t* data, size_t len)
{
data_mode_on();
while ( len )
@ -170,14 +153,14 @@ void VS1003_STM::sdi_send_buffer(const uint8_t* data, size_t len)
size_t chunk_length = min(len,vs1003_chunk_size);
len -= chunk_length;
while ( chunk_length-- )
SPI.transfer(*data++);
my_SPI.transfer(*data++);
}
data_mode_off();
}
/****************************************************************************/
void VS1003_STM::sdi_send_zeroes(size_t len)
void VS1003::sdi_send_zeroes(size_t len)
{
data_mode_on();
while ( len )
@ -187,21 +170,21 @@ void VS1003_STM::sdi_send_zeroes(size_t len)
size_t chunk_length = min(len,vs1003_chunk_size);
len -= chunk_length;
while ( chunk_length-- )
SPI.transfer(0);
my_SPI.transfer(0);
}
data_mode_off();
}
/****************************************************************************/
VS1003_STM::VS1003_STM( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin):
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin), reset_pin(_reset_pin)
VS1003::VS1003( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin, SPIClass _spiChan):
cs_pin(_cs_pin), dcs_pin(_dcs_pin), dreq_pin(_dreq_pin), reset_pin(_reset_pin), my_SPI(_spiChan)
{
}
/****************************************************************************/
void VS1003_STM::begin(void)
void VS1003::begin(void)
{
// Keep the chip in reset until we are ready
@ -217,17 +200,19 @@ void VS1003_STM::begin(void)
// DREQ is an input
pinMode(dreq_pin,INPUT);
// Boot VS1003
//Serial.println(PSTR("Booting VS1003...\r\n"));
//printf(("Booting VS1003...\r\n"));
delay(1);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
my_SPI.begin();
my_SPI.setBitOrder(MSBFIRST);
my_SPI.setDataMode(SPI_MODE0);
// init SPI slow mode
SPI.setClockDivider(SPI_CLOCK_DIV64); // Slow!
my_SPI.setClockDivider(SPI_CLOCK_DIV64); // Slow!
// release from reset
digitalWrite(reset_pin,HIGH);
@ -242,7 +227,7 @@ void VS1003_STM::begin(void)
/* Switch on the analog parts */
write_register(SCI_VOL,0xfefe); // VOL
//printf_P(PSTR("VS1003 still booting\r\n"));
//printf(("VS1003 still booting\r\n"));
write_register(SCI_AUDATA,44101); // 44.1kHz stereo
@ -259,17 +244,17 @@ void VS1003_STM::begin(void)
// Now you can set high speed SPI clock
// 72 MHz / 16 = 4.5 MHz max is practically allowed by VS1003 SPI interface.
SPI.setClockDivider(SPI_CLOCK_DIV16);
my_SPI.setClockDivider(SPI_CLOCK_DIV16);
//printf_P(PSTR("VS1003 Set\r\n"));
//printf(("VS1003 Set\r\n"));
//printDetails();
//printf_P(PSTR("VS1003 OK\r\n"));
//printf(("VS1003 OK\r\n"));
}
/****************************************************************************/
void VS1003_STM::setVolume(uint8_t vol) const
void VS1003::setVolume(uint8_t vol) const
{
uint16_t value = vol;
value <<= 8;
@ -280,47 +265,61 @@ void VS1003_STM::setVolume(uint8_t vol) const
/****************************************************************************/
void VS1003_STM::startSong(void)
void VS1003::startSong(void)
{
sdi_send_zeroes(10);
}
/****************************************************************************/
void VS1003_STM::playChunk(const uint8_t* data, size_t len)
void VS1003::playChunk(const uint8_t* data, size_t len)
{
sdi_send_buffer(data,len);
}
/****************************************************************************/
void VS1003_STM::stopSong(void)
void VS1003::stopSong(void)
{
sdi_send_zeroes(2048);
}
/****************************************************************************/
void VS1003_STM::print_byte_register(uint8_t reg) const
void VS1003::print_byte_register(uint8_t reg) const
{
const char *name = reinterpret_cast<const char*>(pgm_read_word( register_names + reg ));
char extra_tab = strlen_P(name) < 5 ? '\t' : 0;
//printf_P(PSTR("%02x %S\t%c = 0x%02x\r\n"),reg,name,extra_tab,read_register(reg));
//printf(("%02x %S\t%c = 0x%02x\r\n"),reg,name,extra_tab,read_register(reg));
}
/****************************************************************************/
void VS1003_STM::printDetails(void) const
void VS1003::printDetails(void) const
{
//printf_P(PSTR("VS1003 Configuration:\r\n"));
//printf(("VS1003 Configuration:\r\n"));
int i = 0;
while ( i <= SCI_num_registers )
print_byte_register(i++);
}
/****************************************************************************/
void VS1003::modeSwitch(void)
{
//GPIO_DDR
write_register(SCI_WRAMADDR, 0xc017);
write_register(SCI_WRAM, 0x0003);
//GPIO_ODATA
write_register(SCI_WRAMADDR, 0xc019);
write_register(SCI_WRAM, 0x0000);
delay(100);
write_register(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
delay(100);
}
/****************************************************************************/
void VS1003_STM::loadUserCode(const uint16_t* buf, size_t len) const
void VS1003::loadUserCode(const uint16_t* buf, size_t len) const
{
while (len)
{
@ -330,13 +329,13 @@ void VS1003_STM::loadUserCode(const uint16_t* buf, size_t len) const
n &= 0x7FFF;
uint16_t val = pgm_read_word(buf++); len--;
while (n--) {
//printf_P(PSTR("W %02x: %04x\r\n"),addr,val);
//printf(("W %02x: %04x\r\n"),addr,val);
write_register(addr, val);
}
} else { /* Copy run, copy n samples */
while (n--) {
uint16_t val = pgm_read_word(buf++); len--;
//printf_P(PSTR("W %02x: %04x\r\n"),addr,val);
//printf(("W %02x: %04x\r\n"),addr,val);
write_register(addr, val);
}
}

View File

@ -9,27 +9,26 @@
Home: http://www.serasidis.gr
email: avrsite@yahoo.gr
29 May 2015 - Added a fix for booting the VS1053B boards into mp3 decoding instead of booting into MIDI.
*/
//This is an additional test line
#ifndef __VS1003_STM_H__
#define __VS1003_STM_H__
// STL headers
// C headers
// Framework headers
#if ARDUINO < 100
#include <WProgram.h>
#else
#include <Arduino.h>
#endif
#include <Arduino.h>
#include <SPI.h>
/**
* Driver for VS1003 - MP3 / WMA / MIDI Audio Codec Chip
*
* See http://www.vlsi.fi/en/products/vs1003.html
*/
class VS1003_STM
class VS1003
{
private:
uint8_t cs_pin; /**< Pin where CS line is connected */
@ -38,7 +37,8 @@ private:
uint8_t reset_pin; /**< Pin where RESET line is connected */
uint8_t my_SPCR; /**< Value of the SPCR register how we like it. */
uint8_t my_SPSR; /**< Value of the SPSR register how we like it. */
protected:
SPIClass my_SPI;
inline void await_data_request(void) const
{
while ( !digitalRead(dreq_pin) );
@ -87,7 +87,7 @@ public:
*
* Only sets pin values. Doesn't do touch the chip. Be sure to call begin()!
*/
VS1003_STM( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin);
VS1003( uint8_t _cs_pin, uint8_t _dcs_pin, uint8_t _dreq_pin, uint8_t _reset_pin, SPIClass _spi = SPIClass(1));
/**
* Begin operation
@ -125,6 +125,12 @@ public:
* (see fdevopen() in avr/io.h).
*/
void printDetails(void) const;
/**
*
*
*/
void modeSwitch(void);
/**
* Set the player volume

View File

@ -91,8 +91,8 @@ recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mcpu={b
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}"
## Combine gc-sections, archives, and objects
#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.path}/{archive_file}" -Wl,--end-group
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{build.path}/{archive_file}" -Wl,--no-whole-archive -Wl,--end-group
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} "{build.path}/{archive_file}" -Wl,--end-group
#recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mcpu={build.mcu} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" "-L{build.path}" -lm -lgcc -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols -Wl,--start-group {object_files} -Wl,--whole-archive "{build.path}/{archive_file}" -Wl,--no-whole-archive -Wl,--end-group
## Create eeprom
recipe.objcopy.eep.pattern=

View File

@ -38,10 +38,11 @@
* in the series support files, which need dma_irq_handler().) */
#ifdef DMA_GET_HANDLER
static __always_inline void dma_irq_handler(dma_dev *dev, dma_tube tube) {
dma_clear_isr_bits(dev, tube); /* in case handler doesn't */
void (*handler)(void) = DMA_GET_HANDLER(dev, tube);
if (handler) {
handler();
dma_clear_isr_bits(dev, tube); /* in case handler doesn't */
}
}
#endif

View File

@ -71,7 +71,7 @@ void gpio_init(gpio_dev *dev);
void gpio_init_all(void);
/* TODO flags argument version? */
void gpio_set_mode(gpio_dev *dev, uint8 pin, gpio_pin_mode mode);
gpio_pin_mode gpio_get_mode(gpio_dev *dev, uint8 pin);
/**
* @brief Get a GPIO port's corresponding EXTI port configuration.
* @param dev GPIO port whose exti_cfg to return.

View File

@ -38,14 +38,21 @@
#include <libmaple/usart.h>
static __always_inline void usart_irq(ring_buffer *rb, usart_reg_map *regs) {
/* We can get RXNE and ORE interrupts here. Only RXNE signifies
* availability of a byte in DR.
*
* See table 198 (sec 27.4, p809) in STM document RM0008 rev 15.
* We enable RXNEIE. */
if (regs->SR & USART_SR_RXNE) {
#ifdef USART_SAFE_INSERT
/* If the buffer is full and the user defines USART_SAFE_INSERT,
* ignore new bytes. */
rb_safe_insert(rb, (uint8)regs->DR);
/* If the buffer is full and the user defines USART_SAFE_INSERT,
* ignore new bytes. */
rb_safe_insert(rb, (uint8)regs->DR);
#else
/* By default, push bytes around in the ring buffer. */
rb_push_insert(rb, (uint8)regs->DR);
/* By default, push bytes around in the ring buffer. */
rb_push_insert(rb, (uint8)regs->DR);
#endif
}
}
uint32 _usart_clock_freq(usart_dev *dev);

View File

@ -35,6 +35,10 @@
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_debug.h>
#include <wirish_types.h>
@ -109,3 +113,27 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
USB_DP, USB_DM
};
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*/
#ifdef SERIAL_USB
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
#else
DEFINE_HWSERIAL(Serial, 1);
DEFINE_HWSERIAL(Serial1, 2);
DEFINE_HWSERIAL(Serial2, 3);
#endif

View File

@ -32,6 +32,11 @@
#include <board/board.h> // For this board's header file
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_types.h> // For stm32_pin_info and its contents
// (these go into PIN_MAP).
@ -148,3 +153,19 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
BOARD_JTMS_SWDIO_PIN,
BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
};
#ifdef SERIAL_USB
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
DEFINE_HWSERIAL_UART(Serial4, 4);
DEFINE_HWSERIAL_UART(Serial5, 5);
#else
DEFINE_HWSERIAL(Serial, 1);
DEFINE_HWSERIAL(Serial1, 2);
DEFINE_HWSERIAL(Serial2, 3);
DEFINE_HWSERIAL_UART(Serial3, 4);
DEFINE_HWSERIAL_UART(Serial4, 5);
#endif

View File

@ -32,6 +32,10 @@
#include <board/board.h> // For this board's header file
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_types.h> // For stm32_pin_info and its contents
// (these go into PIN_MAP).
@ -178,3 +182,18 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
BOARD_LED_PIN, BOARD_BUTTON_PIN, BOARD_JTMS_SWDIO_PIN,
BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
};
#ifdef SERIAL_USB
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
DEFINE_HWSERIAL_UART(Serial4, 4);
DEFINE_HWSERIAL_UART(Serial5, 5);
#else
DEFINE_HWSERIAL(Serial, 1);
DEFINE_HWSERIAL(Serial1, 2);
DEFINE_HWSERIAL(Serial2, 3);
DEFINE_HWSERIAL_UART(Serial3, 4);
DEFINE_HWSERIAL_UART(Serial4, 5);
#endif

View File

@ -46,20 +46,22 @@
#define BOARD_LED_PIN PE5
#define BOARD_LED_PIN2 PE6
/* Note: UART4 and UART5 have pins which aren't broken out :( */
#define BOARD_NR_USARTS 3
// USARTS
#define BOARD_NR_USARTS 5
#define BOARD_USART1_TX_PIN PA9
#define BOARD_USART1_RX_PIN PA10
#define BOARD_USART2_TX_PIN PA2
#define BOARD_USART2_RX_PIN PA3
#define BOARD_USART3_TX_PIN PB10
#define BOARD_USART3_RX_PIN PB11
/*
#define BOARD_USART4_TX_PIN PC10
#define BOARD_USART4_RX_PIN PC11
#define BOARD_USART5_TX_PIN PC12
#define BOARD_USART5_RX_PIN PD2
*/

View File

@ -32,6 +32,10 @@
#include <board/board.h> // For this board's header file
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_types.h> // For stm32_pin_info and its contents
// (these go into PIN_MAP).
@ -213,3 +217,18 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
BOARD_JTMS_SWDIO_PIN,
BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
};
#ifdef SERIAL_USB
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
DEFINE_HWSERIAL_UART(Serial4, 4);
DEFINE_HWSERIAL_UART(Serial5, 5);
#else
DEFINE_HWSERIAL(Serial, 1);
DEFINE_HWSERIAL(Serial1, 2);
DEFINE_HWSERIAL(Serial2, 3);
DEFINE_HWSERIAL_UART(Serial3, 4);
DEFINE_HWSERIAL_UART(Serial4, 5);
#endif

View File

@ -32,6 +32,10 @@
#include <board/board.h> // For this board's header file
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_types.h> // For stm32_pin_info and its contents
// (these go into PIN_MAP).
@ -141,3 +145,19 @@ extern const uint8 boardUsedPins[] __FLASH__ = {
13, 33, BOARD_JTMS_SWDIO_PIN,
BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
};
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*
* Note. Maple always has SERIAL USB, so there is no need for the #fidef for this
* As its a Medium Density device (F103RB), it only has 3 hardware serial devices.
*/
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);

View File

@ -35,6 +35,10 @@
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_debug.h>
#include <wirish_types.h>
@ -103,3 +107,22 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
32, 32, USB_DP, USB_DM
};
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*
* Note. Maple mini always has SERIAL USB, so there is no need for the #fidef for this
* As its a Medium Density device, it only has 3 hardware serial devices.
*/
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);

View File

@ -32,6 +32,10 @@
#include <board/board.h> // For this board's header file
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_types.h> // For stm32_pin_info and its contents
// (these go into PIN_MAP).
@ -155,3 +159,20 @@ extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
BOARD_JTMS_SWDIO_PIN,
BOARD_JTCK_SWCLK_PIN, BOARD_JTDI_PIN, BOARD_JTDO_PIN, BOARD_NJTRST_PIN
};
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*
* Note. Maple Ret always has SERIAL USB, so there is no need for the #fidef for this
* As its a High Density device (F103RE), it has 6 hardware serial devices.
*/
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
DEFINE_HWSERIAL_UART(Serial4, 4);
DEFINE_HWSERIAL_UART(Serial5, 5);

View File

@ -33,6 +33,10 @@
#include <board/board.h>
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
@ -95,3 +99,19 @@ extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
extern const uint8 boardUsedPins[BOARD_NR_USED_PINS] __FLASH__ = {
4, 24, USB_DP, USB_DM
};
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*
* Note. I think a microduino is a Maple mini clone in another form factor,
*/
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);

View File

@ -47,6 +47,11 @@
#include <libmaple/gpio.h>
#include <libmaple/timer.h>
/* Roger Clark. Added next to includes for changes to Serial */
#include <libmaple/usart.h>
#include <HardwareSerial.h>
#include <wirish_debug.h>
#include <wirish_types.h>
// boardInit(): NUCLEO rely on some remapping
@ -230,4 +235,25 @@ MOSI alternate functions on the GPIO ports.
1: Remap (NSS/PA15, SCK/PB3, MISO/PB4, MOSI/PB5)
*/
*/
/*
* Roger Clark
*
* 2015/05/28
*
* Moved definitions for Hardware Serial devices from HardwareSerial.cpp so that each board can define which Arduino "Serial" instance
* Maps to which hardware serial port on the microprocessor
*/
#ifdef SERIAL_USB
DEFINE_HWSERIAL(Serial1, 1);
DEFINE_HWSERIAL(Serial2, 2);
DEFINE_HWSERIAL(Serial3, 3);
#else
DEFINE_HWSERIAL(Serial, 3);// Use HW Serial 2 as "Serial"
DEFINE_HWSERIAL(Serial1, 2);
DEFINE_HWSERIAL(Serial2, 1);
#endif

1
STM32duino-bootloader Submodule

@ -0,0 +1 @@
Subproject commit f883a676c42e2c264e00021173e7bbbf82772f95

View File

@ -1,6 +0,0 @@
.dep
TAGS
tags
cscope.out
build
*~

View File

@ -1,12 +0,0 @@
This is at least a partial credits-file of people that have
contributed to the Maple bootloader. It is formatted the same way the
Linux kernel CREDITS file is structured: sorted by name and formatted
for easy processing.
The fields are: name (N), email (E), web-address (W), description (D).
----------
N: Tormod Volden
E: debian.tormod@gmail.com
D: Fixes for DFU compliance

View File

@ -1,265 +0,0 @@
# Makefile skeleton adapted from Peter Harrison's - www.micromouse.com
# MCU name and submodel
MCU = cortex-m3
SUBMDL = stm32f103
# toolchain (using code sourcery now)
TCHAIN = arm-none-eabi
THUMB = -mthumb
THUMB_IW = -mthumb-interwork
# Target file name (without extension).
BUILDDIR = build
TARGET = $(BUILDDIR)/maple_boot
ST_LIB = stm32_lib
ST_USB = usb_lib
# Optimization level [0,1,2,3,s]
OPT ?= s
DEBUG =
#DEBUG = dwarf-2
INCDIRS = ./$(ST_LIB) ./$(ST_USB)
CFLAGS = $(DEBUG)
CFLAGS += -O$(OPT)
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -Wall -Wimplicit
CFLAGS += -Wcast-align
CFLAGS += -Wpointer-arith -Wswitch
CFLAGS += -Wredundant-decls -Wreturn-type -Wshadow -Wunused
CFLAGS += -Wa,-adhlns=$(BUILDDIR)/$(subst $(suffix $<),.lst,$<)
CFLAGS += $(patsubst %,-I%,$(INCDIRS))
# Aeembler Flags
ASFLAGS = -Wa,-adhlns=$(BUILDDIR)/$(<:.s=.lst)#,--g$(DEBUG)
LDFLAGS = -nostartfiles -Wl,-Map=$(TARGET).map,--cref,--gc-sections
LDFLAGS += -lc -lgcc
# Set the linker script
LDFLAGS +=-T$(ST_LIB)/c_only_md.ld
# Define programs and commands.
SHELL = sh
CC = $(TCHAIN)-gcc
CPP = $(TCHAIN)-g++
AR = $(TCHAIN)-ar
OBJCOPY = $(TCHAIN)-objcopy
OBJDUMP = $(TCHAIN)-objdump
SIZE = $(TCHAIN)-size
NM = $(TCHAIN)-nm
REMOVE = rm -f
REMOVEDIR = rm -r
COPY = cp
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = "-------- begin --------"
MSG_ETAGS = Created TAGS File
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_FLASH = Creating load file for Flash:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
# Combine all necessary flags and optional flags.
# Add target processor to flags.
GENDEPFLAGS = -MD -MP -MF .dep/$(@F).d
ALL_CFLAGS = -mcpu=$(MCU) $(THUMB_IW) -I. $(CFLAGS) $(TARGETFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mcpu=$(MCU) $(THUMB_IW) -I. -x assembler-with-cpp $(ASFLAGS)
# --------------------------------------------- #
# file management
ASRC = $(ST_LIB)/c_only_startup.s $(ST_LIB)/cortexm3_macro.s
STM32SRCS =
_STM32USBSRCS = usb_regs.c \
usb_int.c \
usb_init.c \
usb_core.c \
usb_mem.c
STM32USBSRCS = $(patsubst %, $(ST_USB)/%,$(_STM32USBSRCS))
SRCS = usb.c usb_callbacks.c usb_descriptor.c main.c hardware.c dfu.c
SRC = $(SRCS) $(STM32SRCS) $(STM32USBSRCS)
# Define all object files.
_COBJ = $(SRC:.c=.o)
_AOBJ = $(ASRC:.s=.o)
COBJ = $(patsubst %, $(BUILDDIR)/%,$(_COBJ))
AOBJ = $(patsubst %, $(BUILDDIR)/%,$(_AOBJ))
# Define all listing files.
_LST = $(ASRC:.s=.lst)
_LST += $(SRC:.c=.lst)
LST = $(patsubst %, $(BUILDDIR)/%,$(_LST))
# Display size of file.
HEXSIZE = $(SIZE) --target=binary $(TARGET).hex
ELFSIZE = $(SIZE) -A $(TARGET).elf
# go!
all: begin gccversion build sizeafter finished end
maple-mini: begin gccversion build_maple-mini sizeafter finished copy_maple_mini end
maple-rev3: begin gccversion build_maple-rev3 sizeafter finished end
build: elf bin lss sym
build_maple-mini: TARGETFLAGS= -DTARGET_MAPLE_MINI
build_maple-mini: elf bin lss sym
copy_maple_mini:
@echo
@echo "Copying to binaries folder"
@echo
cp $(TARGET).bin binaries/maple_mini_boot20.bin
@echo
build_maple-rev3: TARGETFLAGS= -DTARGET_MAPLE_REV3
build_maple-rev3: elf bin lss sym
bin: $(TARGET).bin
elf: $(TARGET).elf
lss: $(TARGET).lss
sym: $(TARGET).sym
dfu: $(TARGET).bin
sudo dfu-util -d 0110:1001 -a 0 -D $(TARGET).bin
begin:
mkdir -p build/stm32_lib
mkdir -p build/usb_lib
@echo --
@echo $(MSG_BEGIN)
@echo $(COBJ)
finished:
@echo $(MSG_ERRORS_NONE)
tags:
etags `find . -name "*.c" -o -name "*.cpp" -o -name "*.h"`
@echo $(MSG_ETAGS)
end:
@echo $(MSG_END)
@echo
sizeafter:
@if [ -f $(TARGET).elf ]; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); echo; fi
gccversion:
@$(CC) --version
program:
@echo "Flash-programming with OpenOCD"
cp $(TARGET).bin flash/tmpflash.bin
cd flash && openocd -f flash.cfg
program_serial:
@echo "Flash-programming with stm32loader.py"
./flash/stm32loader.py -p /dev/ttyUSB0 -evw build/maple_boot.bin
debug: $(TARGET).bin
@echo "Flash-programming with OpenOCD - DEBUG"
cp $(TARGET).bin flash/tmpflash.bin
cd flash && openocd -f debug.cfg
install: $(TARGET).bin
cp $(TARGET).bin build/main.bin
openocd -f flash/perry_flash.cfg
run: $(TARGET).bin
openocd -f flash/run.cfg
# Create final output file (.hex) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O binary $< $@
# Create final output file (.bin) from ELF output file.
%.bin: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O binary $< $@
# Create extended listing file from ELF output file.
# testing: option -C
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -D $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(COBJ) $(AOBJ)
%.elf: $(COBJ) $(AOBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(THUMB) $(ALL_CFLAGS) $(AOBJ) $(COBJ) --output $@ $(LDFLAGS)
# Compile: create object files from C source files. ARM/Thumb
$(COBJ) : $(BUILDDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(THUMB) $(ALL_CFLAGS) $< -o $@
# Assemble: create object files from assembler source files. ARM/Thumb
$(AOBJ) : $(BUILDDIR)/%.o : %.s
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(THUMB) $(ALL_ASFLAGS) $< -o $@
clean: begin clean_list finished end
clean_list :
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).bin
$(REMOVE) $(TARGET).obj
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).obj
$(REMOVE) $(TARGET).a90
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lnk
$(REMOVE) $(TARGET).lss
$(REMOVE) $(COBJ)
$(REMOVE) $(AOBJ)
$(REMOVE) $(LST)
$(REMOVE) flash/tmpflash.bin
# $(REMOVE) $(SRC:.c=.s)
# $(REMOVE) $(SRC:.c=.d)
$(REMOVE) .dep/*
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all begin finish tags end sizeafter gccversion \
build elf hex bin lss sym clean clean_list program cscope
cscope:
rm -rf *.cscope
find . -iname "*.[hcs]" | grep -v examples | xargs cscope -R -b

View File

@ -1,35 +0,0 @@
FILES -------------------------------------------------------------------------
stm32lib/*
- all the (possibly consolidated) stm32 lib and usb example code
usb.c
- USB-specific hardware setup. Interrupts, clocks, etc. handling USB when
not "Attached". some low-level callbacks (low power mode, init, reset,
resume, etc).
usb_callbacks.c
- aka endpoints: handling data transfer when "Configured". calls out to
application specific callbacks (i.e. DFU).
usb_descriptor.c
- aka application descriptor; big static struct and callbacks for sending
the descriptor.
main.c
- main loop and calling any hardware init stuff. timing hacks for EEPROM
writes not to block usb interrupts. logic to handle 2 second timeout then
jump to user code.
hardware.c
- init routines to setup clocks, interrupts, also destructor functions.
does not include USB stuff. EEPROM read/write functions.
dfu.c
- mostly the giant FSM case switch, also some USB endpoint callbacks
TODO --------------------------------------------------------------------------
* pack the structs
* use sizeof() for usb application descriptor once structs are packed

View File

@ -1,44 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file common.h
*
* @brief toplevel include for bootloader source files
*
*
*/
#ifndef __COMMON_H
#define __COMMON_H
#include "config.h"
#include "hardware.h"
#include "stm32f10x_type.h"
#include "cortexm3_macro.h"
#include "usb.h"
typedef void (*FuncPtr)(void);
#endif

View File

@ -1,78 +0,0 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
*****************************************************************************/
/**
* @file config.h
*
* @brief bootloader settings and macro defines
*
*
*/
#ifndef __CONFIG_H
#define __CONFIG_H
#include "common.h"
/* Speed controls for strobing the LED pin */
#define BLINK_FAST 0x50000
#define BLINK_SLOW 0x100000
/* On the Mini, LED is PB1 */
#if defined(TARGET_MAPLE_MINI)
#define LED_BANK GPIOB
#define LED 1
#define LED_BANK_CR GPIO_CRL(LED_BANK)
#define LED_CR_MASK 0xFFFFFF0F
#define LED_CR_MODE 0x00000010
#define RCC_APB2ENR_LED 0x00000008 /* enable PB */
/* On the Mini, BUT is PB8 */
#define BUTTON_BANK GPIOB
#define BUTTON 8
#define BUT_BANK_CR GPIO_CRH(BUTTON_BANK)
#define BUT_CR_MASK 0xFFFFFFF0
#define BUT_CR_OUTPUT_IN 0x00000004
#define RCC_APB2ENR_BUT 0x00000008 /* enable PB */
#else
#error "No config for this target"
#endif
#define STARTUP_BLINKS 5
#define BOOTLOADER_WAIT 6
#define USER_CODE_RAM ((u32)0x20000C00)
#define RAM_END ((u32)0x20005000)
#define USER_CODE_FLASH0X8005000 ((u32)0x08005000)
#define USER_CODE_FLASH0X8002000 ((u32)0x08002000)
#define FLASH_END ((u32)0x08020000)
#define VEND_ID0 0xAF
#define VEND_ID1 0x1E
#define PROD_ID0 0x03
#define PROD_ID1 0x00
#endif

View File

@ -1,475 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file dfu.c
*
* @brief The principle dfu state machine as well as the data
* transfer callbacks accessed by the usb library
*
*
*/
#include "dfu.h"
#include "usb.h"
/* DFU globals */
static volatile u32 userAppAddr = USER_CODE_RAM; /* default RAM user code location */
static volatile u32 userAppEnd = RAM_END;
static volatile DFUStatus dfuAppStatus; /* includes state */
volatile dfuUploadTypes_t userUploadType = DFU_UPLOAD_NONE;
volatile bool dfuBusy = FALSE;
static volatile u8 recvBuffer[wTransferSize] __attribute__((aligned(4)));
static volatile u32 userFirmwareLen = 0;
static volatile u16 thisBlockLen = 0;
static volatile u16 uploadBlockLen = 0;
volatile PLOT code_copy_lock;
/* todo: force dfu globals to be singleton to avoid re-inits? */
void dfuInit(void) {
dfuAppStatus.bStatus = OK;
dfuAppStatus.bwPollTimeout0 = 0x00;
dfuAppStatus.bwPollTimeout1 = 0x00;
dfuAppStatus.bwPollTimeout2 = 0x00;
dfuAppStatus.bState = dfuIDLE;
dfuAppStatus.iString = 0x00; /* all strings must be 0x00 until we make them! */
userFirmwareLen = 0;
thisBlockLen = 0;;
userAppAddr = USER_CODE_RAM; /* default RAM user code location */
userAppEnd = RAM_END;
userUploadType=DFU_UPLOAD_NONE;
code_copy_lock = WAIT;
dfuBusy = FALSE;
}
bool dfuUpdateByRequest(void) {
/* were using the global pInformation struct from usb_lib here,
see comment in maple_dfu.h around DFUEvent struct */
dfuBusy = TRUE;
u8 startState = dfuAppStatus.bState;
dfuAppStatus.bStatus = OK;
/* often leaner to nest if's then embed a switch/case */
if (startState == dfuIDLE) {
/* device running inside DFU mode */
dfuBusy = TRUE; // signals the main loop to defer to the dfu write-loop
if (pInformation->USBbRequest == DFU_DNLOAD) {
if (pInformation->USBwLengths.w > 0) {
userFirmwareLen = 0;
dfuAppStatus.bState = dfuDNLOAD_SYNC;
switch(pInformation->Current_AlternateSetting)
{
/*
Roger Clark. removed upload to RAM option
case 0:
userAppAddr = USER_CODE_RAM;
userUploadType = DFU_UPLOAD_RAM;
break;
*/
case 1:
userAppAddr = USER_CODE_FLASH0X8005000;
userUploadType = DFU_UPLOAD_FLASH_0X8005000;
/* make sure the flash is setup properly, unlock it */
setupFLASH();
flashUnlock();
// Clear lower memory so that we can check on cold boot, whether the last upload was to 0x8002000 or 0x8005000
flashErasePage((u32)USER_CODE_FLASH0X8002000);
break;
case 2:
userUploadType = DFU_UPLOAD_FLASH_0X8002000;
userAppAddr = USER_CODE_FLASH0X8002000;
/* make sure the flash is setup properly, unlock it */
setupFLASH();
flashUnlock();
break;
default:
// Roger Clark. Report error
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errWRITE;
break;
}
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errNOTDONE;
}
} else if (pInformation->USBbRequest == DFU_UPLOAD) {
dfuAppStatus.bState = dfuUPLOAD_IDLE;
/* record length of first block for calculating target
address from wValue in consecutive blocks */
uploadBlockLen = pInformation->USBwLengths.w;
thisBlockLen = uploadBlockLen; /* for this first block as well */
/* calculate where the data should be copied from */
userFirmwareLen = uploadBlockLen * pInformation->USBwValue;
switch(pInformation->Current_AlternateSetting)
{
/*
case 0:
userAppAddr = USER_CODE_RAM;
userAppEnd = RAM_END;
*/
case 1:
userAppAddr = USER_CODE_FLASH0X8005000;
userAppEnd = FLASH_END;
break;
case 2:
userAppAddr = USER_CODE_FLASH0X8002000;
userAppEnd = FLASH_END;
break;
default:
// Roger Clark.
// Changed this to report error that its unable to write to this memory
// However the code should never get here as only AlternateSetting 1 and 2 are allowed (see above)
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errWRITE;
break;
}
} else if (pInformation->USBbRequest == DFU_ABORT) {
dfuAppStatus.bState = dfuIDLE;
dfuAppStatus.bStatus = OK; /* are we really ok? we were just aborted */
} else if (pInformation->USBbRequest == DFU_GETSTATUS) {
dfuAppStatus.bState = dfuIDLE;
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuIDLE;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else if (startState == dfuDNLOAD_SYNC) {
/* device received block, waiting for DFU_GETSTATUS request */
if (pInformation->USBbRequest == DFU_GETSTATUS) {
/* todo, add routine to wait for last block write to finish */
/* Roger Clark. Commented out code associated with RAM upload
if (userUploadType == DFU_UPLOAD_RAM)
{
if (code_copy_lock == WAIT) {
code_copy_lock = BEGINNING;
dfuAppStatus.bwPollTimeout0 = 0x20; // 32 ms
dfuAppStatus.bwPollTimeout1 = 0x00;
dfuAppStatus.bState = dfuDNBUSY;
} else if (code_copy_lock == BEGINNING) {
dfuAppStatus.bState = dfuDNLOAD_SYNC;
} else if (code_copy_lock == MIDDLE) {
dfuAppStatus.bState = dfuDNLOAD_SYNC;
} else if (code_copy_lock == END) {
dfuAppStatus.bwPollTimeout0 = 0x00;
code_copy_lock = WAIT;
dfuAppStatus.bState = dfuDNLOAD_IDLE;
}
}
else
*/
{
dfuAppStatus.bState = dfuDNLOAD_IDLE;
dfuCopyBufferToExec();
}
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuDNLOAD_SYNC;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else if (startState == dfuDNBUSY) {
/* if were actually done writing, goto sync, else stay busy */
if (code_copy_lock == END) {
dfuAppStatus.bwPollTimeout0 = 0x00;
code_copy_lock = WAIT;
dfuAppStatus.bState = dfuDNLOAD_IDLE;
} else {
dfuAppStatus.bState = dfuDNBUSY;
}
} else if (startState == dfuDNLOAD_IDLE) {
/* device is expecting dfu_dnload requests */
if (pInformation->USBbRequest == DFU_DNLOAD) {
if (pInformation->USBwLengths.w > 0) {
dfuAppStatus.bState = dfuDNLOAD_SYNC;
} else {
/* todo, support "disagreement" if device expects more data than this */
dfuAppStatus.bState = dfuMANIFEST_SYNC;
/* relock the flash */
flashLock();
}
} else if (pInformation->USBbRequest == DFU_ABORT) {
dfuAppStatus.bState = dfuIDLE;
} else if (pInformation->USBbRequest == DFU_GETSTATUS) {
dfuAppStatus.bState = dfuIDLE;
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuIDLE;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else if (startState == dfuMANIFEST_SYNC) {
/* device has received last block, waiting DFU_GETSTATUS request */
if (pInformation->USBbRequest == DFU_GETSTATUS) {
dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET;
dfuAppStatus.bStatus = OK;
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuMANIFEST_SYNC;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else if (startState == dfuMANIFEST) {
/* device is in manifestation phase */
/* should never receive request while in manifest! */
dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET;
dfuAppStatus.bStatus = OK;
} else if (startState == dfuMANIFEST_WAIT_RESET) {
/* device has programmed new firmware but needs external
usb reset or power on reset to run the new code */
/* consider timing out and self-resetting */
dfuAppStatus.bState = dfuMANIFEST_WAIT_RESET;
} else if (startState == dfuUPLOAD_IDLE) {
/* device expecting further dfu_upload requests */
if (pInformation->USBbRequest == DFU_UPLOAD) {
if (pInformation->USBwLengths.w > 0) {
/* check that this is not the last possible block */
userFirmwareLen = uploadBlockLen * pInformation->USBwValue;
if (userAppAddr + userFirmwareLen + uploadBlockLen <= userAppEnd) {
thisBlockLen = uploadBlockLen;
dfuAppStatus.bState = dfuUPLOAD_IDLE;
} else {
/* if above comparison was just equal, thisBlockLen becomes zero
next time when USBWValue has been increased by one */
thisBlockLen = userAppEnd - userAppAddr - userFirmwareLen;
/* check for overflow due to USBwValue out of range */
if (thisBlockLen >= pInformation->USBwLengths.w) {
thisBlockLen = 0;
}
dfuAppStatus.bState = dfuIDLE;
}
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errNOTDONE;
}
} else if (pInformation->USBbRequest == DFU_ABORT) {
dfuAppStatus.bState = dfuIDLE;
} else if (pInformation->USBbRequest == DFU_GETSTATUS) {
dfuAppStatus.bState = dfuUPLOAD_IDLE;
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuUPLOAD_IDLE;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else if (startState == dfuERROR) {
/* status is in error, awaiting DFU_CLRSTATUS request */
if (pInformation->USBbRequest == DFU_GETSTATUS) {
/* todo, add routine to wait for last block write to finish */
dfuAppStatus.bState = dfuERROR;
} else if (pInformation->USBbRequest == DFU_GETSTATE) {
dfuAppStatus.bState = dfuERROR;
} else if (pInformation->USBbRequest == DFU_CLRSTATUS) {
/* todo handle any cleanup we need here */
dfuAppStatus.bState = dfuIDLE;
dfuAppStatus.bStatus = OK;
} else {
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
} else {
/* some kind of error... */
dfuAppStatus.bState = dfuERROR;
dfuAppStatus.bStatus = errSTALLEDPKT;
}
if (dfuAppStatus.bStatus == OK) {
return TRUE;
} else {
return FALSE;
}
}
void dfuUpdateByReset(void) {
u8 startState = dfuAppStatus.bState;
userFirmwareLen = 0;
if (startState == appDETACH) {
dfuAppStatus.bState = dfuIDLE;
dfuAppStatus.bStatus = OK;
nvicDisableInterrupts();
usbEnbISR();
} else if (startState == appIDLE || startState == dfuIDLE) {
/* do nothing...might be normal usb bus activity */
} else {
/* we reset from the dfu, reset everything and startover,
which is the correct operation if this is an erroneous
event or properly following a MANIFEST */
dfuAppStatus.bState = dfuIDLE;
dfuAppStatus.bStatus = OK;
systemHardReset();
}
}
void dfuUpdateByTimeout(void) {
}
u8 *dfuCopyState(u16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = 1;
return NULL;
} else {
return (&(dfuAppStatus.bState));
}
}
u8 *dfuCopyStatus(u16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = 6;
return NULL;
} else {
return (u8*)(&dfuAppStatus);
}
}
u8 *dfuCopyDNLOAD(u16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = pInformation->USBwLengths.w - pInformation->Ctrl_Info.Usb_wOffset;
thisBlockLen = pInformation->USBwLengths.w;
return NULL;
} else {
return ((u8 *)recvBuffer + pInformation->Ctrl_Info.Usb_wOffset);
}
}
u8 *dfuCopyUPLOAD(u16 length) {
if (length == 0) {
pInformation->Ctrl_Info.Usb_wLength = thisBlockLen - pInformation->Ctrl_Info.Usb_wOffset;
return NULL;
} else {
return((u8*) userAppAddr + userFirmwareLen + pInformation->Ctrl_Info.Usb_wOffset);
}
}
void dfuCopyBufferToExec() {
int i;
u32 *userSpace;
/* Roger Clark.
Commented out code associated with upload to RAM
if (userUploadType == DFU_UPLOAD_RAM)
{
userSpace = (u32 *)(USER_CODE_RAM + userFirmwareLen);
// we dont need to handle when thisBlock len is not divisible by 4,
// since the linker will align everything to 4B anyway
for (i = 0; i < thisBlockLen; i = i + 4) {
*userSpace++ = *(u32 *)(recvBuffer + i);
}
}
else
*/
{
if (userUploadType == DFU_UPLOAD_FLASH_0X8005000)
{
userSpace = (u32 *)(USER_CODE_FLASH0X8005000 + userFirmwareLen);
}
else
{
userSpace = (u32 *)(USER_CODE_FLASH0X8002000 + userFirmwareLen);
}
flashErasePage((u32)(userSpace));
for (i = 0; i < thisBlockLen; i = i + 4) {
flashWriteWord((u32)(userSpace++), *(u32 *)(recvBuffer +i));
}
}
userFirmwareLen += thisBlockLen;
thisBlockLen = 0;
}
u8 dfuGetState(void) {
return dfuAppStatus.bState;
}
void dfuSetState(u8 newState) {
dfuAppStatus.bState = newState;
}
bool dfuUploadStarted() {
return dfuBusy;
}
void dfuFinishUpload() {
while (1)
{
__asm("nop");
/* Roger Clark.
Commented out code associated with upload to RAM
if (userUploadType==DFU_UPLOAD_RAM)
{
if (code_copy_lock == BEGINNING) {
code_copy_lock = MIDDLE;
strobePin(LED_BANK, LED, 2, 0x1000);
dfuCopyBufferToExec();
strobePin(LED_BANK, LED, 2, 0x500);
code_copy_lock = END;
}
}
*/
/* otherwise do nothing, dfu state machine resets itself */
}
}

View File

@ -1,128 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
#ifndef __DFU_H
#define __DFU_H
#include "common.h"
/*
#define DFU_UPLOAD_NONE 0
#define DFU_UPLOAD_RAM 1
#define DFU_UPLOAD_FLASH_0X8005000 2
#define DFU_UPLOAD_FLASH_0X8002000 3
*/
typedef enum {DFU_UPLOAD_NONE, DFU_UPLOAD_RAM, DFU_UPLOAD_FLASH_0X8005000,DFU_UPLOAD_FLASH_0X8002000} dfuUploadTypes_t;
/* exposed types */
typedef u8 *(*ClassReqCB)(u16);
/* exposed structs */
typedef struct _DFUStatus {
u8 bStatus;
u8 bwPollTimeout0;
u8 bwPollTimeout1;
u8 bwPollTimeout2;
u8 bState; /* state of device at the time the host receives the message! */
u8 iString;
} DFUStatus;
typedef enum _PLOT {
BEGINNING,
MIDDLE,
END,
WAIT
} PLOT;
/*** DFU bRequest Values ******/
/* bmRequestType, wValue, wIndex, wLength, Data */
#define DFU_DETACH 0x00 /* 0x21, wTimeout, Interface, Zero, None */
#define DFU_DNLOAD 0x01 /* 0x21, wBlockNum, Interface, Length, Firmware */
#define DFU_UPLOAD 0x02 /* 0xA1, Zero, Interface, Length, Firmware */
#define DFU_GETSTATUS 0x03 /* 0xA1, Zero, Interface, 6, Status */
#define DFU_CLRSTATUS 0x04 /* 0x21, Zero, Interface, Zero, None */
#define DFU_GETSTATE 0x05 /* 0xA1, Zero, Interface, 1, State */
#define DFU_ABORT 0x06 /* 0x21, Zero, Interface, Zero, None */
/*** DFU Status Values ******/
#define OK 0x00 /* No error */
#define errTARGET 0x01 /* File is not appropriate for this device */
#define errFILE 0x02 /* File fails some vendor tests */
#define errWRITE 0x03 /* Device is unable to write memory */
#define errERASE 0x04 /* Memory erase failed */
#define errCHECK_ERASED 0x05 /* Memory erase check failed */
#define errPROG 0x06 /* Program memory function failed */
#define errVERIFY 0x07 /* Written program failed verification */
#define errADDRESS 0x08 /* address out of range */
#define errNOTDONE 0x09 /* received DNLOAD with wLength=0, but firmware seems incomplete */
#define errFIRMWARE 0x0A /* Runtime firmware corrupt, cannot return to non-dfu operations! */
#define errVENDOR 0x0B /* vendor specific error */
#define errUSBR 0x0C /* Unexpected usb reset! */
#define errPOR 0x0D /* Unexpected power on reset */
#define errUNKNOWN 0x0E /* Unknown error */
#define errSTALLEDPKT 0x0F /* device stalled unexpected request */
/***************************/
/*** DFU State Values **************/
#define appIDLE 0x00
#define appDETACH 0x01
#define dfuIDLE 0x02
#define dfuDNLOAD_SYNC 0x03
#define dfuDNBUSY 0x04
#define dfuDNLOAD_IDLE 0x05
#define dfuMANIFEST_SYNC 0x06
#define dfuMANIFEST 0x07
#define dfuMANIFEST_WAIT_RESET 0x08
#define dfuUPLOAD_IDLE 0x09
#define dfuERROR 0x0A
/***********************************/
extern volatile bool dfuBusy;
/* exposed functions */
void dfuInit(void); /* singleton dfu initializer */
/* should consume dfuEvent type, but for now we can use pInfo (see comment above) */
bool dfuUpdateByRequest(void); /* returns if new status is OK */
void dfuUpdateByReset(void);
void dfuUpdateByTimeout(void);
/* usb callbacks */
u8 *dfuCopyState(u16);
u8 *dfuCopyStatus(u16);
u8 *dfuCopyDNLOAD(u16);
u8 *dfuCopyUPLOAD(u16);
void dfuCopyBufferToExec(void);
bool checkTestFile(void);
u8 dfuGetState(void);
void dfuSetState(u8);
bool dfuUploadStarted();
void dfuFinishUpload();
#endif

View File

@ -1,83 +0,0 @@
# script for stm32
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG"
ft2232_layout olimex-jtag
ft2232_vid_pid 0x15ba 0x0003
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}
# jtag speed
jtag_khz 600
#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst
#jtag scan chain
if { [info exists CPUTAPID ] } {
set _CPUTAPID $CPUTAPID
} else {
# See STM Document RM0008
# Section 26.6.3
set _CPUTAPID 0x3ba00477
}
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
if { [info exists BSTAPID ] } {
set _BSTAPID $BSTAPID
} else {
# See STM Document RM0008
# Section 26.6.2
# Medium Density RevA
set _BSTAPID 0x06410041
# Rev B and Rev Z
set _BSTAPID 0x16410041
# High Density Devices, Rev A
#set _BSTAPID 0x06414041
}
jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x5000 -work-area-backup 0
#$_TARGETNAME configure -event halted halt_handle
#flash bank stm32x 0 0 0 0 0
#target create cortex_m3 -endian little
#run_and_halt_time 0 30
#working_area 0 0x20000000 0x4000 nobackup
flash bank stm32x 0x08000000 0x00010000 0 0 0
# For more information about the configuration files, take a look at:
# openocd.texi
#script flash.script
proc halt_handle {} {
resume
}
proc flash_test {} {
puts "Entering DEBUG wait"
sleep 100
# reset run
# sleep 500
}
init
flash_test

View File

@ -1,91 +0,0 @@
# script for stm32
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG"
ft2232_layout olimex-jtag
ft2232_vid_pid 0x15ba 0x0003
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}
# jtag speed
jtag_khz 600
#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst
#jtag scan chain
if { [info exists CPUTAPID ] } {
set _CPUTAPID $CPUTAPID
} else {
# See STM Document RM0008
# Section 26.6.3
set _CPUTAPID 0x3ba00477
}
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
if { [info exists BSTAPID ] } {
set _BSTAPID $BSTAPID
} else {
# See STM Document RM0008
# Section 26.6.2
# Medium Density RevA
set _BSTAPID 0x06410041
# Rev B and Rev Z
set _BSTAPID 0x16410041
# High Density Devices, Rev A
#set _BSTAPID 0x06414041
}
jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x5000 -work-area-backup 0
#$_TARGETNAME configure -event halted halt_handle
#flash bank stm32x 0 0 0 0 0
#target create cortex_m3 -endian little
#run_and_halt_time 0 30
#working_area 0 0x20000000 0x4000 nobackup
flash bank stm32x 0x08000000 0x00010000 0 0 0
# For more information about the configuration files, take a look at:
# openocd.texi
#script flash.script
proc halt_handle {} {
resume
}
proc flash_test {} {
puts "Trying to flash"
sleep 100
halt
sleep 300
stm32x mass_erase 0
sleep 20
flash write_bank 0 tmpflash.bin 0
sleep 50
# reset run
# sleep 500
reset run
shutdown
}
init
flash_test

View File

@ -1,73 +0,0 @@
# script for stm32
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG"
ft2232_layout olimex-jtag
ft2232_vid_pid 0x15ba 0x0003
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}
# jtag speed
jtag_khz 500
jtag_nsrst_delay 200
jtag_ntrst_delay 200
#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst
#jtag scan chain
if { [info exists CPUTAPID ] } {
set _CPUTAPID $CPUTAPID
} else {
# See STM Document RM0008
# Section 26.6.3
set _CPUTAPID 0x3ba00477
}
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
if { [info exists BSTAPID ] } {
set _BSTAPID $BSTAPID
} else {
# See STM Document RM0008
# Section 26.6.2
# Medium Density RevA
set _BSTAPID 0x06410041
# Rev B and Rev Z
set _BSTAPID 0x16410041
# High Density Devices, Rev A
#set _BSTAPID 0x06414041
}
jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 0x5000 -work-area-backup 0
flash bank stm32x 0x08000000 0x00010000 0 0 0
init
halt
sleep 1000
stm32x unlock 0
flash erase_sector 0 0 0
sleep 1000
flash write_bank 0 tmpflash.bin 0
sleep 3000
reset
sleep 3000
shutdown

View File

@ -1,72 +0,0 @@
# script for stm32
interface ft2232
ft2232_device_desc "Olimex OpenOCD JTAG"
ft2232_layout olimex-jtag
ft2232_vid_pid 0x15ba 0x0003
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME stm32
}
if { [info exists ENDIAN] } {
set _ENDIAN $ENDIAN
} else {
set _ENDIAN little
}
# jtag speed
jtag_khz 500
jtag_nsrst_delay 100
jtag_ntrst_delay 100
#use combined on interfaces or targets that can't set TRST/SRST separately
reset_config trst_and_srst
#jtag scan chain
if { [info exists CPUTAPID ] } {
set _CPUTAPID $CPUTAPID
} else {
# See STM Document RM0008
# Section 26.6.3
set _CPUTAPID 0x3ba00477
}
jtag newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
if { [info exists BSTAPID ] } {
set _BSTAPID $BSTAPID
} else {
# See STM Document RM0008
# Section 26.6.2
# Medium Density RevA
set _BSTAPID 0x06410041
# Rev B and Rev Z
set _BSTAPID 0x16410041
# High Density Devices, Rev A
#set _BSTAPID 0x06414041
}
jtag newtap $_CHIPNAME bs -irlen 5 -ircapture 0x1 -irmask 0x1 -expected-id $_BSTAPID
set _TARGETNAME [format "%s.cpu" $_CHIPNAME]
target create $_TARGETNAME cortex_m3 -endian $_ENDIAN -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-virt 0 -work-area-phys 0x20000000 -work-area-size 16384 -work-area-backup 0
#flash bank stm32x 0 0 0 0 0
target create cortex_m3 -endian little
#run_and_halt_time 0 30
#working_area 0 0x20000000 0x4000 nobackup
#flash bank stm32x 0x08000000 0x00010000 0 0 0
reset
sleep 3000
shutdown
# For more information about the configuration files, take a look at:
# openocd.texi

View File

@ -1,435 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: sw=4:ts=4:si:et:enc=utf-8
# Author: Ivan A-R <ivan@tuxotronic.org>
# Project page: http://tuxotronic.org/wiki/projects/stm32loader
#
# This file is part of stm32loader.
#
# stm32loader 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, or (at your option) any later
# version.
#
# stm32loader 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 stm32loader; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
import sys, getopt
import serial
import time
try:
from progressbar import *
usepbar = 1
except:
usepbar = 0
# Verbose level
QUIET = 20
def mdebug(level, message):
if(QUIET >= level):
print >> sys.stderr , message
class CmdException(Exception):
pass
class CommandInterface:
def open(self, aport='/dev/tty.usbserial-FTD3TMCH', abaudrate=115200) :
self.sp = serial.Serial(
port=aport,
baudrate=abaudrate, # baudrate
bytesize=8, # number of databits
parity=serial.PARITY_EVEN,
stopbits=1,
xonxoff=0, # enable software flow control
rtscts=0, # disable RTS/CTS flow control
timeout=5 # set a timeout value, None for waiting forever
)
def _wait_for_ask(self, info = ""):
# wait for ask
try:
ask = ord(self.sp.read())
except:
raise CmdException("Can't read port or timeout")
else:
if ask == 0x79:
# ACK
return 1
else:
if ask == 0x1F:
# NACK
raise CmdException("NACK "+info)
else:
# Unknow responce
raise CmdException("Unknow response. "+info+": "+hex(ask))
def reset(self):
self.sp.setDTR(0)
time.sleep(0.1)
self.sp.setDTR(1)
time.sleep(0.5)
def initChip(self):
# Set boot
self.sp.setRTS(0)
self.reset()
self.sp.write("\x7F") # Syncro
return self._wait_for_ask("Syncro")
def releaseChip(self):
self.sp.setRTS(1)
self.reset()
def cmdGeneric(self, cmd):
self.sp.write(chr(cmd))
self.sp.write(chr(cmd ^ 0xFF)) # Control byte
return self._wait_for_ask(hex(cmd))
def cmdGet(self):
if self.cmdGeneric(0x00):
mdebug(10, "*** Get command");
len = ord(self.sp.read())
version = ord(self.sp.read())
mdebug(10, " Bootloader version: "+hex(version))
dat = map(lambda c: hex(ord(c)), self.sp.read(len))
mdebug(10, " Available commands: "+str(dat))
self._wait_for_ask("0x00 end")
return version
else:
raise CmdException("Get (0x00) failed")
def cmdGetVersion(self):
if self.cmdGeneric(0x01):
mdebug(10, "*** GetVersion command")
version = ord(self.sp.read())
self.sp.read(2)
self._wait_for_ask("0x01 end")
mdebug(10, " Bootloader version: "+hex(version))
return version
else:
raise CmdException("GetVersion (0x01) failed")
def cmdGetID(self):
if self.cmdGeneric(0x02):
mdebug(10, "*** GetID command")
len = ord(self.sp.read())
id = self.sp.read(len+1)
self._wait_for_ask("0x02 end")
return id
else:
raise CmdException("GetID (0x02) failed")
def _encode_addr(self, addr):
byte3 = (addr >> 0) & 0xFF
byte2 = (addr >> 8) & 0xFF
byte1 = (addr >> 16) & 0xFF
byte0 = (addr >> 24) & 0xFF
crc = byte0 ^ byte1 ^ byte2 ^ byte3
return (chr(byte0) + chr(byte1) + chr(byte2) + chr(byte3) + chr(crc))
def cmdReadMemory(self, addr, lng):
assert(lng <= 256)
if self.cmdGeneric(0x11):
mdebug(10, "*** ReadMemory command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ask("0x11 address failed")
N = (lng - 1) & 0xFF
crc = N ^ 0xFF
self.sp.write(chr(N) + chr(crc))
self._wait_for_ask("0x11 length failed")
return map(lambda c: ord(c), self.sp.read(lng))
else:
raise CmdException("ReadMemory (0x11) failed")
def cmdGo(self, addr):
if self.cmdGeneric(0x21):
mdebug(10, "*** Go command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ask("0x21 go failed")
else:
raise CmdException("Go (0x21) failed")
def cmdWriteMemory(self, addr, data):
assert(len(data) <= 256)
if self.cmdGeneric(0x31):
mdebug(10, "*** Write memory command")
self.sp.write(self._encode_addr(addr))
self._wait_for_ask("0x31 address failed")
#map(lambda c: hex(ord(c)), data)
lng = (len(data)-1) & 0xFF
mdebug(10, " %s bytes to write" % [lng+1]);
self.sp.write(chr(lng)) # len really
crc = 0xFF
for c in data:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ask("0x31 programming failed")
mdebug(10, " Write memory done")
else:
raise CmdException("Write memory (0x31) failed")
def cmdEraseMemory(self, sectors = None):
if self.cmdGeneric(0x43):
mdebug(10, "*** Erase memory command")
if sectors is None:
# Global erase
self.sp.write(chr(0xFF))
self.sp.write(chr(0x00))
else:
# Sectors erase
self.sp.write(chr((len(sectors)-1) & 0xFF))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ask("0x43 erasing failed")
mdebug(10, " Erase memory done")
else:
raise CmdException("Erase memory (0x43) failed")
def cmdWriteProtect(self, sectors):
if self.cmdGeneric(0x63):
mdebug(10, "*** Write protect command")
self.sp.write(chr((len(sectors)-1) & 0xFF))
crc = 0xFF
for c in sectors:
crc = crc ^ c
self.sp.write(chr(c))
self.sp.write(chr(crc))
self._wait_for_ask("0x63 write protect failed")
mdebug(10, " Write protect done")
else:
raise CmdException("Write Protect memory (0x63) failed")
def cmdWriteUnprotect(self):
if self.cmdGeneric(0x73):
mdebug(10, "*** Write Unprotect command")
self._wait_for_ask("0x73 write unprotect failed")
self._wait_for_ask("0x73 write unprotect 2 failed")
mdebug(10, " Write Unprotect done")
else:
raise CmdException("Write Unprotect (0x73) failed")
def cmdReadoutProtect(self):
if self.cmdGeneric(0x82):
mdebug(10, "*** Readout protect command")
self._wait_for_ask("0x82 readout protect failed")
self._wait_for_ask("0x82 readout protect 2 failed")
mdebug(10, " Read protect done")
else:
raise CmdException("Readout protect (0x82) failed")
def cmdReadoutUnprotect(self):
if self.cmdGeneric(0x92):
mdebug(10, "*** Readout Unprotect command")
self._wait_for_ask("0x92 readout unprotect failed")
self._wait_for_ask("0x92 readout unprotect 2 failed")
mdebug(10, " Read Unprotect done")
else:
raise CmdException("Readout unprotect (0x92) failed")
# Complex commands section
def readMemory(self, addr, lng):
data = []
if usepbar:
widgets = ['Reading: ', Percentage(),', ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets,maxval=lng, term_width=79).start()
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
else:
mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
data = data + self.cmdReadMemory(addr, 256)
addr = addr + 256
lng = lng - 256
if usepbar:
pbar.update(pbar.maxval-lng)
pbar.finish()
else:
mdebug(5, "Read %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
data = data + self.cmdReadMemory(addr, lng)
return data
def writeMemory(self, addr, data):
lng = len(data)
if usepbar:
widgets = ['Writing: ', Percentage(),' ', ETA(), ' ', Bar()]
pbar = ProgressBar(widgets=widgets, maxval=lng, term_width=79).start()
offs = 0
while lng > 256:
if usepbar:
pbar.update(pbar.maxval-lng)
else:
mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
self.cmdWriteMemory(addr, data[offs:offs+256])
offs = offs + 256
addr = addr + 256
lng = lng - 256
if usepbar:
pbar.update(pbar.maxval-lng)
pbar.finish()
else:
mdebug(5, "Write %(len)d bytes at 0x%(addr)X" % {'addr': addr, 'len': 256})
self.cmdWriteMemory(addr, data[offs:offs+lng] + ([0xFF] * (256-lng)) )
def __init__(self) :
pass
def usage():
print """Usage: %s [-hqVewvr] [-l length] [-p port] [-b baud] [-a addr] [file.bin]
-h This help
-q Quiet
-V Verbose
-e Erase
-w Write
-v Verify
-r Read
-l length Length of read
-p port Serial port (default: /dev/tty.usbserial-ftCYPMYJ)
-b baud Baud speed (default: 115200)
-a addr Target address
./stm32loader.py -e -w -v example/main.bin
""" % sys.argv[0]
if __name__ == "__main__":
# Import Psyco if available
try:
import psyco
psyco.full()
print "Using Psyco..."
except ImportError:
pass
conf = {
'port': '/dev/tty.usbserial-FTD3TMCH',
'baud': 115200,
'address': 0x08000000,
'erase': 0,
'write': 0,
'verify': 0,
'read': 0,
'len': 1000,
'fname':'',
}
# http://www.python.org/doc/2.5.2/lib/module-getopt.html
try:
opts, args = getopt.getopt(sys.argv[1:], "hqVewvrp:b:a:l:")
except getopt.GetoptError, err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
QUIET = 5
for o, a in opts:
if o == '-V':
QUIET = 10
elif o == '-q':
QUIET = 0
elif o == '-h':
usage()
sys.exit(0)
elif o == '-e':
conf['erase'] = 1
elif o == '-w':
conf['write'] = 1
elif o == '-v':
conf['verify'] = 1
elif o == '-r':
conf['read'] = 1
elif o == '-p':
conf['port'] = a
elif o == '-b':
conf['baud'] = eval(a)
elif o == '-a':
conf['address'] = eval(a)
elif o == '-l':
conf['len'] = eval(a)
# elif o == '-f':
# conf['fname'] = a
else:
assert False, "unhandled option"
cmd = CommandInterface()
cmd.open(conf['port'], conf['baud'])
mdebug(10, "Open port %(port)s, baud %(baud)d" % {'port':conf['port'], 'baud':conf['baud']})
try:
try:
cmd.initChip()
except:
print "Can't init. Ensure that BOOT0 is enabled and reset device"
bootversion = cmd.cmdGet()
mdebug(0, "Bootloader version %X" % bootversion)
mdebug(0, "Chip id `%s'" % str(map(lambda c: hex(ord(c)), cmd.cmdGetID())))
# cmd.cmdGetVersion()
# cmd.cmdGetID()
# cmd.cmdReadoutUnprotect()
# cmd.cmdWriteUnprotect()
# cmd.cmdWriteProtect([0, 1])
if (conf['write'] or conf['verify']):
data = map(lambda c: ord(c), file(args[0]).read())
if conf['erase']:
cmd.cmdEraseMemory()
if conf['write']:
cmd.writeMemory(conf['address'], data)
if conf['verify']:
verify = cmd.readMemory(conf['address'], len(data))
if(data == verify):
print "Verification OK"
else:
print "Verification FAILED"
print str(len(data)) + ' vs ' + str(len(verify))
for i in xrange(0, len(data)):
if data[i] != verify[i]:
print hex(i) + ': ' + hex(data[i]) + ' vs ' + hex(verify[i])
if not conf['write'] and conf['read']:
rdata = cmd.readMemory(conf['address'], conf['len'])
# file(conf['fname'], 'wb').write(rdata)
file(args[0], 'wb').write(''.join(map(chr,rdata)))
# cmd.cmdGo(addr + 0x04)
finally:
cmd.releaseChip()

View File

@ -1,285 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file hardware.c
*
* @brief init routines to setup clocks, interrupts, also destructor functions.
* does not include USB stuff. EEPROM read/write functions.
*
*/
#include "hardware.h"
void setPin(u32 bank, u8 pin) {
u32 pinMask = 0x1 << (pin);
SET_REG(GPIO_BSRR(bank), pinMask);
}
void resetPin(u32 bank, u8 pin) {
u32 pinMask = 0x1 << (16 + pin);
SET_REG(GPIO_BSRR(bank), pinMask);
}
bool readPin(u32 bank, u8 pin) {
// todo, implement read
if (GET_REG(GPIO_IDR(bank)) & (0x01 << pin)) {
return TRUE;
} else {
return FALSE;
}
}
void strobePin(u32 bank, u8 pin, u8 count, u32 rate) {
resetPin(bank, pin);
u32 c;
while (count-- > 0) {
for (c = rate; c > 0; c--) {
asm volatile("nop");
}
setPin(bank, pin);
for (c = rate; c > 0; c--) {
asm volatile("nop");
}
resetPin(bank, pin);
}
}
void systemReset(void) {
SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00000001);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xF8FF0000);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFEF6FFFF);
SET_REG(RCC_CR, GET_REG(RCC_CR) & 0xFFFBFFFF);
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) & 0xFF80FFFF);
SET_REG(RCC_CIR, 0x00000000); /* disable all RCC interrupts */
}
void setupCLK(void) {
/* enable HSE */
SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x00010001);
while ((GET_REG(RCC_CR) & 0x00020000) == 0); /* for it to come on */
/* enable flash prefetch buffer */
SET_REG(FLASH_ACR, 0x00000012);
/* Configure PLL */
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) | 0x001D0400); /* pll=72Mhz,APB1=36Mhz,AHB=72Mhz */
SET_REG(RCC_CR, GET_REG(RCC_CR) | 0x01000000); /* enable the pll */
while ((GET_REG(RCC_CR) & 0x03000000) == 0); /* wait for it to come on */
/* Set SYSCLK as PLL */
SET_REG(RCC_CFGR, GET_REG(RCC_CFGR) | 0x00000002);
while ((GET_REG(RCC_CFGR) & 0x00000008) == 0); /* wait for it to come on */
}
void setupLED (void) {
/* enable LED pin */
pRCC->APB2ENR |= RCC_APB2ENR_LED;
/* Setup LED pin as output open drain */
SET_REG(LED_BANK_CR,(GET_REG(LED_BANK_CR) & LED_CR_MASK) | LED_CR_MODE);
setPin(LED_BANK, LED);
}
void setupBUTTON (void) {
/* enable button pin */
pRCC->APB2ENR |= RCC_APB2ENR_BUT;
/* Setup button pin as floating input */
SET_REG(BUT_BANK_CR,(GET_REG(BUT_BANK_CR) & BUT_CR_MASK) | BUT_CR_OUTPUT_IN);
setPin(BUTTON_BANK, BUTTON);
}
void setupFLASH() {
/* configure the HSI oscillator */
if ((pRCC->CR & 0x01) == 0x00) {
u32 rwmVal = pRCC->CR;
rwmVal |= 0x01;
pRCC->CR = rwmVal;
}
/* wait for it to come on */
while ((pRCC->CR & 0x02) == 0x00) {}
}
bool checkUserCode(u32 usrAddr) {
u32 sp = *(vu32 *) usrAddr;
if ((sp & 0x2FFE0000) == 0x20000000) {
return (TRUE);
} else {
return (FALSE);
}
}
void jumpToUser(u32 usrAddr) {
typedef void (*funcPtr)(void);
u32 jumpAddr = *(vu32 *)(usrAddr + 0x04); /* reset ptr in vector table */
funcPtr usrMain = (funcPtr) jumpAddr;
/* tear down all the dfu related setup */
// disable usb interrupts, clear them, turn off usb, set the disc pin
// todo pick exactly what we want to do here, now its just a conservative
flashLock();
usbDsbISR();
nvicDisableInterrupts();
setPin(GPIOC, 12); // disconnect usb from host. todo, macroize pin
systemReset(); // resets clocks and periphs, not core regs
__MSR_MSP(*(vu32 *) usrAddr); /* set the users stack ptr */
usrMain(); /* go! */
}
void nvicInit(NVIC_InitTypeDef *NVIC_InitStruct) {
u32 tmppriority = 0x00;
u32 tmpreg = 0x00;
u32 tmpmask = 0x00;
u32 tmppre = 0;
u32 tmpsub = 0x0F;
SCB_TypeDef *rSCB = (SCB_TypeDef *) SCB_BASE;
NVIC_TypeDef *rNVIC = (NVIC_TypeDef *) NVIC_BASE;
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - (rSCB->AIRCR & (u32)0x700)) >> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (u32)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
tmppriority = ((u32)tmppriority) << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg = rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)];
tmpmask = (u32)0xFF << ((NVIC_InitStruct->NVIC_IRQChannel & (u8)0x03) * 0x08);
tmpreg &= ~tmpmask;
tmppriority &= tmpmask;
tmpreg |= tmppriority;
rNVIC->IPR[(NVIC_InitStruct->NVIC_IRQChannel >> 0x02)] = tmpreg;
/* Enable the Selected IRQ Channels --------------------------------------*/
rNVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel >> 0x05)] =
(u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (u8)0x1F);
}
void nvicDisableInterrupts() {
NVIC_TypeDef *rNVIC = (NVIC_TypeDef *) NVIC_BASE;
rNVIC->ICER[0] = 0xFFFFFFFF;
rNVIC->ICER[1] = 0xFFFFFFFF;
rNVIC->ICPR[0] = 0xFFFFFFFF;
rNVIC->ICPR[1] = 0xFFFFFFFF;
SET_REG(STK_CTRL, 0x04); /* disable the systick, which operates separately from nvic */
}
void systemHardReset(void) {
SCB_TypeDef *rSCB = (SCB_TypeDef *) SCB_BASE;
/* Reset */
rSCB->AIRCR = (u32)AIRCR_RESET_REQ;
/* should never get here */
while (1) {
asm volatile("nop");
}
}
bool flashErasePage(u32 pageAddr) {
u32 rwmVal = GET_REG(FLASH_CR);
rwmVal = FLASH_CR_PER;
SET_REG(FLASH_CR, rwmVal);
while (GET_REG(FLASH_SR) & FLASH_SR_BSY) {}
SET_REG(FLASH_AR, pageAddr);
SET_REG(FLASH_CR, FLASH_CR_START | FLASH_CR_PER);
while (GET_REG(FLASH_SR) & FLASH_SR_BSY) {}
/* todo: verify the page was erased */
rwmVal = 0x00;
SET_REG(FLASH_CR, rwmVal);
return TRUE;
}
bool flashErasePages(u32 pageAddr, u16 n) {
while (n-- > 0) {
if (!flashErasePage(pageAddr + 0x400 * n)) {
return FALSE;
}
}
return TRUE;
}
bool flashWriteWord(u32 addr, u32 word) {
vu16 *flashAddr = (vu16 *)addr;
vu32 lhWord = (vu32)word & 0x0000FFFF;
vu32 hhWord = ((vu32)word & 0xFFFF0000) >> 16;
u32 rwmVal = GET_REG(FLASH_CR);
SET_REG(FLASH_CR, FLASH_CR_PG);
/* apparently we need not write to FLASH_AR and can
simply do a native write of a half word */
while (GET_REG(FLASH_SR) & FLASH_SR_BSY) {}
*(flashAddr + 0x01) = (vu16)hhWord;
while (GET_REG(FLASH_SR) & FLASH_SR_BSY) {}
*(flashAddr) = (vu16)lhWord;
while (GET_REG(FLASH_SR) & FLASH_SR_BSY) {}
rwmVal &= 0xFFFFFFFE;
SET_REG(FLASH_CR, rwmVal);
/* verify the write */
if (*(vu32 *)addr != word) {
return FALSE;
}
return TRUE;
}
void flashLock() {
/* take down the HSI oscillator? it may be in use elsewhere */
/* ensure all FPEC functions disabled and lock the FPEC */
SET_REG(FLASH_CR, 0x00000080);
}
void flashUnlock() {
/* unlock the flash */
SET_REG(FLASH_KEYR, FLASH_KEY1);
SET_REG(FLASH_KEYR, FLASH_KEY2);
}

View File

@ -1,190 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
#ifndef __HARDWARE_H
#define __HARDWARE_H
#include "stm32f10x_type.h"
#include "cortexm3_macro.h"
#include "common.h"
/* macro'd register and peripheral definitions */
#define RCC ((u32)0x40021000)
#define FLASH ((u32)0x40022000)
#define GPIOA ((u32)0x40010800)
#define GPIOB ((u32)0x40010C00)
#define GPIOC ((u32)0x40011000)
#define RCC_CR RCC
#define RCC_CFGR (RCC + 0x04)
#define RCC_CIR (RCC + 0x08)
#define RCC_AHBENR (RCC + 0x14)
#define RCC_APB2ENR (RCC + 0x18)
#define RCC_APB1ENR (RCC + 0x1C)
#define FLASH_ACR (FLASH + 0x00)
#define FLASH_KEYR (FLASH + 0x04)
#define FLASH_OPTKEYR (FLASH + 0x08)
#define FLASH_SR (FLASH + 0x0C)
#define FLASH_CR (FLASH + 0x10)
#define FLASH_AR (FLASH + 0x14)
#define FLASH_OBR (FLASH + 0x1C)
#define FLASH_WRPR (FLASH + 0x20)
#define FLASH_KEY1 0x45670123
#define FLASH_KEY2 0xCDEF89AB
#define FLASH_RDPRT 0x00A5
#define FLASH_SR_BSY 0x01
#define FLASH_CR_PER 0x02
#define FLASH_CR_PG 0x01
#define FLASH_CR_START 0x40
#define GPIO_CRL(port) port
#define GPIO_CRH(port) (port+0x04)
#define GPIO_IDR(port) (port+0x08)
#define GPIO_ODR(port) (port+0x0c)
#define GPIO_BSRR(port) (port+0x10)
#define SCS_BASE ((u32)0xE000E000)
#define NVIC_BASE (SCS_BASE + 0x0100)
#define SCB_BASE (SCS_BASE + 0x0D00)
#define SCS 0xE000E000
#define NVIC (SCS+0x100)
#define SCB (SCS+0xD00)
#define STK (SCS+0x10)
#define SCB_VTOR (SCB+0x08)
#define STK_CTRL (STK+0x00)
#define TIM1_APB2_ENB ((u32)0x00000800)
#define TIM1 ((u32)0x40012C00)
#define TIM1_PSC (TIM1+0x28)
#define TIM1_ARR (TIM1+0x2C)
#define TIM1_RCR (TIM1+0x30)
#define TIM1_CR1 (TIM1+0x00)
#define TIM1_CR2 (TIM1+0x04)
#define TIM1_DIER (TIM1+0x0C)
#define TIM1_UP_IRQ_Channel ((u8)0x19)
#define USB_HP_IRQ ((u8)0x13)
#define USB_LP_IRQ ((u8)0x14)
#define TIM2_IRQ ((u8)0x1C)
/* AIRCR */
#define AIRCR_RESET 0x05FA0000
#define AIRCR_RESET_REQ (AIRCR_RESET | (u32)0x04);
/* temporary copyage of example from kiel */
#define __VAL(__TIMCLK, __PERIOD) ((__TIMCLK/1000000UL)*__PERIOD)
#define __PSC(__TIMCLK, __PERIOD) (((__VAL(__TIMCLK, __PERIOD)+49999UL)/50000UL) - 1)
#define __ARR(__TIMCLK, __PERIOD) ((__VAL(__TIMCLK, __PERIOD)/(__PSC(__TIMCLK, __PERIOD)+1)) - 1)
#define SET_REG(addr,val) do { *(vu32*)(addr)=val; } while(0)
#define GET_REG(addr) (*(vu32*)(addr))
/* todo: there must be some major misunderstanding in how we access
regs. The direct access approach (GET_REG) causes the usb init to
fail upon trying to activate RCC_APB1 |= 0x00800000. However, using
the struct approach from ST, it works fine...temporarily switching
to that approach */
typedef struct {
vu32 CR;
vu32 CFGR;
vu32 CIR;
vu32 APB2RSTR;
vu32 APB1RSTR;
vu32 AHBENR;
vu32 APB2ENR;
vu32 APB1ENR;
vu32 BDCR;
vu32 CSR;
} RCC_RegStruct;
#define pRCC ((RCC_RegStruct *) RCC)
typedef struct {
vu32 ISER[2];
u32 RESERVED0[30];
vu32 ICER[2];
u32 RSERVED1[30];
vu32 ISPR[2];
u32 RESERVED2[30];
vu32 ICPR[2];
u32 RESERVED3[30];
vu32 IABR[2];
u32 RESERVED4[62];
vu32 IPR[15];
} NVIC_TypeDef;
typedef struct {
u8 NVIC_IRQChannel;
u8 NVIC_IRQChannelPreemptionPriority;
u8 NVIC_IRQChannelSubPriority;
bool NVIC_IRQChannelCmd; /* TRUE for enable */
} NVIC_InitTypeDef;
typedef struct {
vuc32 CPUID;
vu32 ICSR;
vu32 VTOR;
vu32 AIRCR;
vu32 SCR;
vu32 CCR;
vu32 SHPR[3];
vu32 SHCSR;
vu32 CFSR;
vu32 HFSR;
vu32 DFSR;
vu32 MMFAR;
vu32 BFAR;
vu32 AFSR;
} SCB_TypeDef;
void setPin(u32 bank, u8 pin);
void resetPin(u32 bank, u8 pin);
bool readPin(u32 bank, u8 pin);
void strobePin(u32 bank, u8 pin, u8 count, u32 rate);
void systemHardReset(void);
void systemReset(void);
void setupCLK(void);
void setupLED(void);
void setupFLASH(void);
void setupBUTTON(void);
bool checkUserCode(u32 usrAddr);
void jumpToUser(u32 usrAddr);
bool flashWriteWord(u32 addr, u32 word);
bool flashErasePage(u32 addr);
bool flashErasePages(u32 addr, u16 n);
void flashLock(void);
void flashUnlock(void);
void nvicInit(NVIC_InitTypeDef *);
void nvicDisableInterrupts(void);
#endif

View File

@ -1,84 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file main.c
*
* @brief main loop and calling any hardware init stuff. timing hacks for EEPROM
* writes not to block usb interrupts. logic to handle 2 second timeout then
* jump to user code.
*
*/
#include "common.h"
#include "dfu.h"
extern volatile dfuUploadTypes_t userUploadType;
int main()
{
systemReset(); // peripherals but not PC
setupCLK();
setupLED();
setupUSB();
setupBUTTON();
setupFLASH();
strobePin(LED_BANK, LED, STARTUP_BLINKS, BLINK_FAST);
/* wait for host to upload program or halt bootloader */
bool no_user_jump = (!checkUserCode(USER_CODE_FLASH0X8005000) && !checkUserCode(USER_CODE_FLASH0X8002000)) || readPin(BUTTON_BANK,BUTTON);
int delay_count = 0;
while ((delay_count++ < BOOTLOADER_WAIT) || no_user_jump)
{
strobePin(LED_BANK, LED, 1, BLINK_SLOW);
if (dfuUploadStarted())
{
dfuFinishUpload(); // systemHardReset from DFU once done
}
}
if (checkUserCode(USER_CODE_FLASH0X8002000))
{
jumpToUser(USER_CODE_FLASH0X8002000);
}
else
{
if (checkUserCode(USER_CODE_FLASH0X8005000))
{
jumpToUser(USER_CODE_FLASH0X8005000);
}
else
{
// Nothing to execute in either Flash or RAM
strobePin(LED_BANK, LED, 5, BLINK_FAST);
systemHardReset();
}
}
return 0;// Added to please the compiler
}

View File

@ -1,172 +0,0 @@
/*
Default linker script for STM32F10x_128K_20K
Original Copyright RAISONANCE S.A.S. 2008
Modified P Harrison May 2009
*/
/*
* Default stack sizes.
*
* These are used by the startup in order to allocate stacks for the different modes.
* PROVIDE" allows to easily override these values from an object file or the commmand line.
*/
__Stack_Size = 1024 ;
PROVIDE ( _Stack_Size = __Stack_Size ) ;
__Stack_Init = _estack - __Stack_Size ;
PROVIDE ( _Stack_Init = __Stack_Init ) ;
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 0x100 ;
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 3K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 8K
}
/* higher address of the user mode stack */
_estack = 0x20005000;
SECTIONS
{
/*
* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section,
* which goes to FLASH
*/
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >FLASH
/*
* for some STRx devices, the beginning of the startup code is stored in the .flashtext section,
* which goes to FLASH
*/
.flashtext :
{
. = ALIGN(4);
KEEP (*(.flashtext)) /* Startup code */
. = ALIGN(4);
} >FLASH
/*
* the program code is stored in the .text section, which goes to Flash
*/
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
_etext = .;
_sidata = _etext;
} >FLASH
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
/* we copy the important program globals vector in RAM as well, so that users can fool with it */
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >RAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >RAM
/*
* after that it's only debugging information.
*/
/* remove the debugging information from the standard libraries */
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/*
* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

View File

@ -1,169 +0,0 @@
/*
Default linker script for STM32F10x_128K_20K
Original Copyright RAISONANCE S.A.S. 2008
Modified P Harrison May 2009
*/
/*
* Default stack sizes.
*
* These are used by the startup in order to allocate stacks for the different modes.
* PROVIDE" allows to easily override these values from an object file or the commmand line.
*/
__Stack_Size = 1024 ;
PROVIDE ( _Stack_Size = __Stack_Size ) ;
__Stack_Init = _estack - __Stack_Size ;
PROVIDE ( _Stack_Init = __Stack_Init ) ;
/*
*There will be a link error if there is not this amount of RAM free at the end.
*/
_Minimum_Stack_Size = 0x100 ;
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000C00, LENGTH = 17K
}
/* higher address of the user mode stack */
_estack = 0x20005000;
_magicRate = 0x5000;
SECTIONS
{
/*
* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section,
* which goes to FLASH
*/
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* Startup code */
. = ALIGN(4);
} >RAM
/*
* for some STRx devices, the beginning of the startup code is stored in the .flashtext section,
* which goes to FLASH
*/
.flashtext :
{
. = ALIGN(4);
KEEP (*(.flashtext)) /* Startup code */
. = ALIGN(4);
} >RAM
/*
* the program code is stored in the .text section, which goes to Flash
*/
.text :
{
. = ALIGN(4);
*(.text) /* remaining code */
*(.text.*) /* remaining code */
*(.rodata) /* read-only data (constants) */
*(.rodata*)
*(.glue_7)
*(.glue_7t)
. = ALIGN(4);
_etext = .;
_sidata = _etext; /* Uused by the startup in order to initialize the .data secion */
} >RAM
/*
* This is the initialized data section. It is stored in RAM but the initial values
* are held in flash and copied to RAM by the startup code
*/
.data : AT ( _sidata ) /* AT makes the LMA follow on in the binary image */
{
. = ALIGN(4);
_sdata = . ; /* Used by the startup in order to initialize the .data section */
KEEP( *(.data) )
KEEP( *(.data.*) )
. = ALIGN(4);
_edata = . ; /* Used by the startup in order to initialize the .data section */
} >RAM
/*
* This is the uninitialized data section. Date here is stored in RAM and will be
* set to zero by the startup code.
*/
.bss :
{
. = ALIGN(4);
_sbss = .; /* Used by the startup in order to initialize the .bss section */
*(.bss)
*(COMMON)
. = ALIGN(4);
_ebss = . ; /* Used by the startup in order to initialize the .bss section */
} >RAM
PROVIDE ( end = _ebss );
PROVIDE ( _end = _ebss );
/*
* This is the user stack section
* This is just to check that there is enough RAM left for the User mode stack
* It should generate an error if it's full.
*/
._usrstack :
{
. = ALIGN(4);
_susrstack = . ;
. = . + _Minimum_Stack_Size ;
. = ALIGN(4);
_eusrstack = . ;
} >RAM
/*
* after that it's only debugging information.
*/
/* remove the debugging information from the standard libraries */
DISCARD :
{
libc.a ( * )
libm.a ( * )
libgcc.a ( * )
}
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/*
* DWARF debug sections.
* Symbols in the DWARF debugging sections are relative to the beginning
* of the section so we begin them at 0.
*/
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
}

View File

@ -1,367 +0,0 @@
/**
******************************************************************************
* @file startup_stm32f10x_md.s
* @author MCD Application Team
* @version V3.1.0
* @date 06/19/2009
* @brief STM32F10x Medium Density Devices vector table for RIDE7 toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M3 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
*******************************************************************************
* @copy
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global SystemInit_ExtMemCtl_Dummy
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
.equ BootRAM, 0xF108F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
.word MemManage_Handler
.word BusFault_Handler
.word UsageFault_Handler
.word 0
.word 0
.word 0
.word 0
.word SVC_Handler
.word DebugMon_Handler
.word 0
.word PendSV_Handler
.word SysTick_Handler
.word WWDG_IRQHandler
.word PVD_IRQHandler
.word TAMPER_IRQHandler
.word RTC_IRQHandler
.word FLASH_IRQHandler
.word RCC_IRQHandler
.word EXTI0_IRQHandler
.word EXTI1_IRQHandler
.word EXTI2_IRQHandler
.word EXTI3_IRQHandler
.word EXTI4_IRQHandler
.word DMA1_Channel1_IRQHandler
.word DMA1_Channel2_IRQHandler
.word DMA1_Channel3_IRQHandler
.word DMA1_Channel4_IRQHandler
.word DMA1_Channel5_IRQHandler
.word DMA1_Channel6_IRQHandler
.word DMA1_Channel7_IRQHandler
.word ADC1_2_IRQHandler
.word USB_HP_CAN1_TX_IRQHandler
.word USB_LP_CAN1_RX0_IRQHandler
.word CAN1_RX1_IRQHandler
.word CAN1_SCE_IRQHandler
.word EXTI9_5_IRQHandler
.word TIM1_BRK_IRQHandler
.word TIM1_UP_IRQHandler
.word TIM1_TRG_COM_IRQHandler
.word TIM1_CC_IRQHandler
.word TIM2_IRQHandler
.word TIM3_IRQHandler
.word TIM4_IRQHandler
.word I2C1_EV_IRQHandler
.word I2C1_ER_IRQHandler
.word I2C2_EV_IRQHandler
.word I2C2_ER_IRQHandler
.word SPI1_IRQHandler
.word SPI2_IRQHandler
.word USART1_IRQHandler
.word USART2_IRQHandler
.word USART3_IRQHandler
.word EXTI15_10_IRQHandler
.word RTCAlarm_IRQHandler
.word USBWakeUp_IRQHandler
/*
.word TIM8_BRK
.word TIM8_UP
.word TIM8_TRG_COM
.word TIM8_CC
.word ADC3
.word FSMC
.word SDIO
.word TIM5
.word SPI3
.word UART4
.word UART5
.word TIM6
.word TIM7
.word DMA2_Channel1
.word DMA2_Channel2
.word DMA2_Channel3
.word DMA2_Channel5
*/
.word BootRAM /* @0x108. This is for boot in RAM mode for
STM32F10x Medium Density devices. */
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
.weak MemManage_Handler
.thumb_set MemManage_Handler,Default_Handler
.weak BusFault_Handler
.thumb_set BusFault_Handler,Default_Handler
.weak UsageFault_Handler
.thumb_set UsageFault_Handler,Default_Handler
.weak SVC_Handler
.thumb_set SVC_Handler,Default_Handler
.weak DebugMon_Handler
.thumb_set DebugMon_Handler,Default_Handler
.weak PendSV_Handler
.thumb_set PendSV_Handler,Default_Handler
.weak SysTick_Handler
.thumb_set SysTick_Handler,Default_Handler
.weak WWDG_IRQHandler
.thumb_set WWDG_IRQHandler,Default_Handler
.weak PVD_IRQHandler
.thumb_set PVD_IRQHandler,Default_Handler
.weak TAMPER_IRQHandler
.thumb_set TAMPER_IRQHandler,Default_Handler
.weak RTC_IRQHandler
.thumb_set RTC_IRQHandler,Default_Handler
.weak FLASH_IRQHandler
.thumb_set FLASH_IRQHandler,Default_Handler
.weak RCC_IRQHandler
.thumb_set RCC_IRQHandler,Default_Handler
.weak EXTI0_IRQHandler
.thumb_set EXTI0_IRQHandler,Default_Handler
.weak EXTI1_IRQHandler
.thumb_set EXTI1_IRQHandler,Default_Handler
.weak EXTI2_IRQHandler
.thumb_set EXTI2_IRQHandler,Default_Handler
.weak EXTI3_IRQHandler
.thumb_set EXTI3_IRQHandler,Default_Handler
.weak EXTI4_IRQHandler
.thumb_set EXTI4_IRQHandler,Default_Handler
.weak DMA1_Channel1_IRQHandler
.thumb_set DMA1_Channel1_IRQHandler,Default_Handler
.weak DMA1_Channel2_IRQHandler
.thumb_set DMA1_Channel2_IRQHandler,Default_Handler
.weak DMA1_Channel3_IRQHandler
.thumb_set DMA1_Channel3_IRQHandler,Default_Handler
.weak DMA1_Channel4_IRQHandler
.thumb_set DMA1_Channel4_IRQHandler,Default_Handler
.weak DMA1_Channel5_IRQHandler
.thumb_set DMA1_Channel5_IRQHandler,Default_Handler
.weak DMA1_Channel6_IRQHandler
.thumb_set DMA1_Channel6_IRQHandler,Default_Handler
.weak DMA1_Channel7_IRQHandler
.thumb_set DMA1_Channel7_IRQHandler,Default_Handler
.weak ADC1_2_IRQHandler
.thumb_set ADC1_2_IRQHandler,Default_Handler
.weak USB_HP_CAN1_TX_IRQHandler
.thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler
.weak USB_LP_CAN1_RX0_IRQHandler
.thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler
.weak CAN1_RX1_IRQHandler
.thumb_set CAN1_RX1_IRQHandler,Default_Handler
.weak CAN1_SCE_IRQHandler
.thumb_set CAN1_SCE_IRQHandler,Default_Handler
.weak EXTI9_5_IRQHandler
.thumb_set EXTI9_5_IRQHandler,Default_Handler
.weak TIM1_BRK_IRQHandler
.thumb_set TIM1_BRK_IRQHandler,Default_Handler
.weak TIM1_UP_IRQHandler
.thumb_set TIM1_UP_IRQHandler,Default_Handler
.weak TIM1_TRG_COM_IRQHandler
.thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler
.weak TIM1_CC_IRQHandler
.thumb_set TIM1_CC_IRQHandler,Default_Handler
.weak TIM2_IRQHandler
.thumb_set TIM2_IRQHandler,Default_Handler
.weak TIM3_IRQHandler
.thumb_set TIM3_IRQHandler,Default_Handler
.weak TIM4_IRQHandler
.thumb_set TIM4_IRQHandler,Default_Handler
.weak I2C1_EV_IRQHandler
.thumb_set I2C1_EV_IRQHandler,Default_Handler
.weak I2C1_ER_IRQHandler
.thumb_set I2C1_ER_IRQHandler,Default_Handler
.weak I2C2_EV_IRQHandler
.thumb_set I2C2_EV_IRQHandler,Default_Handler
.weak I2C2_ER_IRQHandler
.thumb_set I2C2_ER_IRQHandler,Default_Handler
.weak SPI1_IRQHandler
.thumb_set SPI1_IRQHandler,Default_Handler
.weak SPI2_IRQHandler
.thumb_set SPI2_IRQHandler,Default_Handler
.weak USART1_IRQHandler
.thumb_set USART1_IRQHandler,Default_Handler
.weak USART2_IRQHandler
.thumb_set USART2_IRQHandler,Default_Handler
.weak USART3_IRQHandler
.thumb_set USART3_IRQHandler,Default_Handler
.weak EXTI15_10_IRQHandler
.thumb_set EXTI15_10_IRQHandler,Default_Handler
.weak RTCAlarm_IRQHandler
.thumb_set RTCAlarm_IRQHandler,Default_Handler
.weak USBWakeUp_IRQHandler
.thumb_set USBWakeUp_IRQHandler,Default_Handler

View File

@ -1,128 +0,0 @@
/**
******************************************************************************
* @file startup_stm32f10x_md.s
* @author MCD Application Team
* @version V3.1.0
* @date 06/19/2009
* @brief STM32F10x Medium Density Devices vector table for RIDE7 toolchain.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M3 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
*******************************************************************************
* @copy
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>&copy; COPYRIGHT 2009 STMicroelectronics</center></h2>
*/
.syntax unified
.cpu cortex-m3
.fpu softvfp
.thumb
.global g_pfnVectors
.global SystemInit_ExtMemCtl_Dummy
.global Default_Handler
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/* start address for the .data section. defined in linker script */
.word _sdata
/* end address for the .data section. defined in linker script */
.word _edata
/* start address for the .bss section. defined in linker script */
.word _sbss
/* end address for the .bss section. defined in linker script */
.word _ebss
.word _magicRate
.equ BootRAM, 0xF108F85F
/**
* @brief This is the code that gets called when the processor first
* starts execution following a reset event. Only the absolutely
* necessary set is performed, after which the application
* supplied main() routine is called.
* @param None
* @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
/* Copy the data segment initializers from flash to SRAM */
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/* Zero fill the bss segment. */
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/* Call the application's entry point.*/
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
*
* @param None
* @retval : None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word _magicRate

View File

@ -1,53 +0,0 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : cortexm3_macro.h
* Author : MCD Application Team
* Version : V2.0.3
* Date : 09/22/2008
* Description : Header file for cortexm3_macro.s.
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __CORTEXM3_MACRO_H
#define __CORTEXM3_MACRO_H
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_type.h"
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
void __WFI(void);
void __WFE(void);
void __SEV(void);
void __ISB(void);
void __DSB(void);
void __DMB(void);
void __SVC(void);
u32 __MRS_CONTROL(void);
void __MSR_CONTROL(u32 Control);
u32 __MRS_PSP(void);
void __MSR_PSP(u32 TopOfProcessStack);
u32 __MRS_MSP(void);
void __MSR_MSP(u32 TopOfMainStack);
void __RESETPRIMASK(void);
void __SETPRIMASK(void);
u32 __READ_PRIMASK(void);
void __RESETFAULTMASK(void);
void __SETFAULTMASK(void);
u32 __READ_FAULTMASK(void);
void __BASEPRICONFIG(u32 NewPriority);
u32 __GetBASEPRI(void);
u16 __REV_HalfWord(u16 Data);
u32 __REV_Word(u32 Data);
#endif /* __CORTEXM3_MACRO_H */
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

View File

@ -1,312 +0,0 @@
# 1 "./stm32_lib/cortexm3_macro.S"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "./stm32_lib/cortexm3_macro.S"
# 16 "./stm32_lib/cortexm3_macro.S"
.cpu cortex-m3
.fpu softvfp
.syntax unified
.thumb
.text
.globl __WFI
.globl __WFE
.globl __SEV
.globl __ISB
.globl __DSB
.globl __DMB
.globl __SVC
.globl __MRS_CONTROL
.globl __MSR_CONTROL
.globl __MRS_PSP
.globl __MSR_PSP
.globl __MRS_MSP
.globl __MSR_MSP
.globl __RESETPRIMASK
.globl __SETPRIMASK
.globl __READ_PRIMASK
.globl __RESETFAULTMASK
.globl __SETFAULTMASK
.globl __READ_FAULTMASK
.globl __BASEPRICONFIG
.globl __GetBASEPRI
.globl __REV_HalfWord
.globl __REV_Word
.thumb_func
__WFI:
WFI
BX r14
.thumb_func
__WFE:
WFE
BX r14
.thumb_func
__SEV:
SEV
BX r14
.thumb_func
__ISB:
ISB
BX r14
.thumb_func
__DSB:
DSB
BX r14
.thumb_func
__DMB:
DMB
BX r14
.thumb_func
__SVC:
SVC 0x01
BX r14
.thumb_func
__MRS_CONTROL:
MRS r0,control
BX r14
.thumb_func
__MSR_CONTROL:
MSR control, r0
ISB
BX r14
.thumb_func
__MRS_PSP:
MRS r0, psp
BX r14
.thumb_func
__MSR_PSP:
MSR psp, r0
BX r14
.thumb_func
__MRS_MSP:
MRS r0, msp
BX r14
.thumb_func
__MSR_MSP:
MSR msp, r0
BX r14
.thumb_func
__RESETPRIMASK:
CPSIE i
BX r14
.thumb_func
__SETPRIMASK:
CPSID i
BX r14
.thumb_func
__READ_PRIMASK:
MRS r0, PRIMASK
BX r14
.thumb_func
__RESETFAULTMASK:
CPSIE f
BX r14
.thumb_func
__SETFAULTMASK:
CPSID f
BX r14
.thumb_func
__READ_FAULTMASK:
MRS r0, FAULTMASK
BX r14
.thumb_func
__BASEPRICONFIG:
MSR basepri, r0
BX r14
.thumb_func
__GetBASEPRI:
MRS r0, basepri_max
BX r14
.thumb_func
__REV_HalfWord:
REV16 r0, r0
BX r14
.thumb_func
__REV_Word:
REV r0, r0
BX r14
.end

View File

@ -1,80 +0,0 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : stm32f10x_type.h
* Author : MCD Application Team
* Version : V2.0.3
* Date : 09/22/2008
* Description : This file contains all the common data types used for the
* STM32F10x firmware library.
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __STM32F10x_TYPE_H
#define __STM32F10x_TYPE_H
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
typedef signed long s32;
typedef signed short s16;
typedef signed char s8;
typedef signed long const sc32; /* Read Only */
typedef signed short const sc16; /* Read Only */
typedef signed char const sc8; /* Read Only */
typedef volatile signed long vs32;
typedef volatile signed short vs16;
typedef volatile signed char vs8;
typedef volatile signed long const vsc32; /* Read Only */
typedef volatile signed short const vsc16; /* Read Only */
typedef volatile signed char const vsc8; /* Read Only */
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef unsigned long const uc32; /* Read Only */
typedef unsigned short const uc16; /* Read Only */
typedef unsigned char const uc8; /* Read Only */
typedef volatile unsigned long vu32;
typedef volatile unsigned short vu16;
typedef volatile unsigned char vu8;
typedef volatile unsigned long const vuc32; /* Read Only */
typedef volatile unsigned short const vuc16; /* Read Only */
typedef volatile unsigned char const vuc8; /* Read Only */
typedef enum {FALSE = 0, TRUE = !FALSE} bool;
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
#define U8_MAX ((u8)255)
#define S8_MAX ((s8)127)
#define S8_MIN ((s8)-128)
#define U16_MAX ((u16)65535u)
#define S16_MAX ((s16)32767)
#define S16_MIN ((s16)-32768)
#define U32_MAX ((u32)4294967295uL)
#define S32_MAX ((s32)2147483647)
#define S32_MIN ((s32)-2147483648)
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
#endif /* __STM32F10x_TYPE_H */
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

View File

@ -1,501 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file usb.c
*
* @brief usb-specific hardware setup, NVIC, clocks, and usb activities
* in the pre-attached state. includes some of the lower level callbacks
* needed by the usb library, like suspend,resume,init,etc
*/
#include "usb.h"
#include "dfu.h"
void setupUSB (void) {
/* enable USB DISC Pin */
pRCC->APB2ENR |= RCC_APB2ENR_USB;
/* Setup USB DISC pin as output open drain */
SET_REG(USB_DISC_CR,
(GET_REG(USB_DISC_CR) & USB_DISC_CR_MASK) | USB_DISC_CR_OUTPUT_OD);
setPin (USB_DISC_BANK,USB_DISC);
/* turn on the USB clock */
pRCC->APB1ENR |= RCC_APB1ENR_USB_CLK;
/* initialize the usb application */
resetPin (USB_DISC_BANK,USB_DISC); /* present ourselves to the host */
usbAppInit();
}
void usbDsbBus(void) {
setPin(USB_DISC_BANK,USB_DISC);
}
vu32 bDeviceState = UNCONNECTED;
/* tracks sequential behavior of the ISTR */
vu16 wIstr;
vu8 bIntPackSOF = 0;
DEVICE Device_Table = {
NUM_ENDPTS,
1
};
DEVICE_PROP Device_Property = {
usbInit,
usbReset,
usbStatusIn,
usbStatusOut,
usbDataSetup,
usbNoDataSetup,
usbGetInterfaceSetting,
usbGetDeviceDescriptor,
usbGetConfigDescriptor,
usbGetStringDescriptor,
usbGetFunctionalDescriptor,
0,
bMaxPacketSize
};
USER_STANDARD_REQUESTS User_Standard_Requests = {
usbGetConfiguration,
usbSetConfiguration,
usbGetInterface,
usbSetInterface,
usbGetStatus,
usbClearFeature,
usbSetEndpointFeature,
usbSetDeviceFeature,
usbSetDeviceAddress
};
void (*pEpInt_IN[7])(void) = {
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
};
void (*pEpInt_OUT[7])(void) = {
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
nothingProc,
};
struct {
volatile RESUME_STATE eState;
volatile u8 bESOFcnt;
} ResumeS;
/* dummy proc */
void nothingProc(void) {
}
/* Function Definitions */
void usbAppInit(void) {
/* hook in to usb_core, depends on all those damn
non encapsulated externs! */
USB_Init();
}
void usbSuspend(void) {
u16 wCNTR;
wCNTR = _GetCNTR();
wCNTR |= CNTR_FSUSP | CNTR_LPMODE;
_SetCNTR(wCNTR);
/* run any power reduction handlers */
bDeviceState = SUSPENDED;
}
void usbResumeInit(void) {
u16 wCNTR;
/* restart any clocks that had been stopped */
wCNTR = _GetCNTR();
wCNTR &= (~CNTR_LPMODE);
_SetCNTR(wCNTR);
/* undo power reduction handlers here */
_SetCNTR(ISR_MSK);
}
void usbResume(RESUME_STATE eResumeSetVal) {
u16 wCNTR;
if (eResumeSetVal != RESUME_ESOF)
ResumeS.eState = eResumeSetVal;
switch (ResumeS.eState) {
case RESUME_EXTERNAL:
usbResumeInit();
ResumeS.eState = RESUME_OFF;
break;
case RESUME_INTERNAL:
usbResumeInit();
ResumeS.eState = RESUME_START;
break;
case RESUME_LATER:
ResumeS.bESOFcnt = 2;
ResumeS.eState = RESUME_WAIT;
break;
case RESUME_WAIT:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0)
ResumeS.eState = RESUME_START;
break;
case RESUME_START:
wCNTR = _GetCNTR();
wCNTR |= CNTR_RESUME;
_SetCNTR(wCNTR);
ResumeS.eState = RESUME_ON;
ResumeS.bESOFcnt = 10;
break;
case RESUME_ON:
ResumeS.bESOFcnt--;
if (ResumeS.bESOFcnt == 0) {
wCNTR = _GetCNTR();
wCNTR &= (~CNTR_RESUME);
_SetCNTR(wCNTR);
ResumeS.eState = RESUME_OFF;
}
break;
case RESUME_OFF:
case RESUME_ESOF:
default:
ResumeS.eState = RESUME_OFF;
break;
}
}
RESULT usbPowerOn(void) {
u16 wRegVal;
wRegVal = CNTR_FRES;
_SetCNTR(wRegVal);
wInterrupt_Mask = 0;
_SetCNTR(wInterrupt_Mask);
_SetISTR(0);
wInterrupt_Mask = CNTR_RESETM | CNTR_SUSPM | CNTR_WKUPM; /* the bare minimum */
_SetCNTR(wInterrupt_Mask);
return USB_SUCCESS;
}
RESULT usbPowerOff(void) {
_SetCNTR(CNTR_FRES);
_SetISTR(0);
_SetCNTR(CNTR_FRES + CNTR_PDWN);
/* note that all weve done here is powerdown the
usb peripheral. we have no disabled the clocks,
pulled the usb_disc pin back up, or reset the
application state machines */
return USB_SUCCESS;
}
void usbInit(void) {
dfuInit();
pInformation->Current_Configuration = 0;
usbPowerOn();
_SetISTR(0);
wInterrupt_Mask = ISR_MSK;
_SetCNTR(wInterrupt_Mask);
usbEnbISR(); /* configure the cortex M3 private peripheral NVIC */
bDeviceState = UNCONNECTED;
}
void usbReset(void) {
dfuUpdateByReset();
pInformation->Current_Configuration = 0;
pInformation->Current_Feature = usbConfigDescriptorDFU.Descriptor[7];
_SetBTABLE(BTABLE_ADDRESS);
/* setup the ctrl endpoint */
_SetEPType(ENDP0, EP_CONTROL);
_SetEPTxStatus(ENDP0, EP_TX_STALL);
_SetEPRxAddr(ENDP0, ENDP0_RXADDR);
_SetEPTxAddr(ENDP0, ENDP0_TXADDR);
Clear_Status_Out(ENDP0);
SetEPRxCount(ENDP0, pProperty->MaxPacketSize);
// SetEPTxCount(ENDP0, pProperty->MaxPacketSize);
SetEPRxValid(ENDP0);
bDeviceState = ATTACHED;
SetDeviceAddress(0); /* different than usbSetDeviceAddr! comes from usb_core */
}
void usbStatusIn(void) {
}
void usbStatusOut(void) {
}
RESULT usbDataSetup(u8 request) {
u8 *(*CopyRoutine)(u16);
CopyRoutine = NULL;
/* handle dfu class requests */
if ((pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
if (dfuUpdateByRequest()) {
/* successfull state transition, handle the request */
switch (request) {
case(DFU_GETSTATUS):
CopyRoutine = dfuCopyStatus;
break;
case(DFU_GETSTATE):
CopyRoutine = dfuCopyState;
break;
case(DFU_DNLOAD):
CopyRoutine = dfuCopyDNLOAD;
break;
case(DFU_UPLOAD):
CopyRoutine = dfuCopyUPLOAD;
break;
default:
/* leave copy routine null */
break;
}
}
}
if (CopyRoutine != NULL) {
pInformation->Ctrl_Info.CopyData = CopyRoutine;
pInformation->Ctrl_Info.Usb_wOffset = 0;
(*CopyRoutine)(0);
return USB_SUCCESS;
}
return USB_UNSUPPORT;
}
RESULT usbNoDataSetup(u8 request) {
if ((pInformation->USBbmRequestType & (REQUEST_TYPE | RECIPIENT)) == (CLASS_REQUEST | INTERFACE_RECIPIENT)) {
/* todo, keep track of the destination interface, often stored in wIndex */
if (dfuUpdateByRequest()) {
return USB_SUCCESS;
}
}
return USB_UNSUPPORT;
}
RESULT usbGetInterfaceSetting(u8 interface, u8 altSetting) {
/* alt setting 0 -> program RAM, alt setting 1 -> FLASH */
if (interface > NUM_ALT_SETTINGS) {
return USB_UNSUPPORT;
} else {
return USB_SUCCESS;
}
}
u8 *usbGetDeviceDescriptor(u16 len) {
return Standard_GetDescriptorData(len, &usbDeviceDescriptorDFU);
}
u8 *usbGetConfigDescriptor(u16 len) {
return Standard_GetDescriptorData(len, &usbConfigDescriptorDFU);
}
u8 *usbGetStringDescriptor(u16 len) {
u8 strIndex = pInformation->USBwValue0;
if (strIndex > STR_DESC_LEN) {
return NULL;
} else {
return Standard_GetDescriptorData(len, &usbStringDescriptor[strIndex]);
}
}
u8 *usbGetFunctionalDescriptor(u16 len) {
return Standard_GetDescriptorData(len, &usbFunctionalDescriptor);
}
/***** start of USER STANDARD REQUESTS ******
*
* These are the USER STANDARD REQUESTS, they are handled
* in the core but we are given these callbacks at the
* application level
*******************************************/
void usbGetConfiguration(void) {
/* nothing process */
}
void usbSetConfiguration(void) {
if (pInformation->Current_Configuration != 0) {
bDeviceState = CONFIGURED;
}
}
void usbGetInterface(void) {
/* nothing process */
}
void usbSetInterface(void) {
/* nothing process */
}
void usbGetStatus(void) {
/* nothing process */
}
void usbClearFeature(void) {
/* nothing process */
}
void usbSetEndpointFeature(void) {
/* nothing process */
}
void usbSetDeviceFeature(void) {
/* nothing process */
}
void usbSetDeviceAddress(void) {
bDeviceState = ADDRESSED;
}
/***** end of USER STANDARD REQUESTS *****/
void usbEnbISR(void) {
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = TRUE;
nvicInit(&NVIC_InitStructure);
}
void usbDsbISR(void) {
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USB_LP_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = FALSE;
nvicInit(&NVIC_InitStructure);
}
void USB_LP_CAN1_RX0_IRQHandler(void) {
wIstr = _GetISTR();
/* go nuts with the preproc switches since this is an ISTR and must be FAST */
#if (ISR_MSK & ISTR_RESET)
if (wIstr & ISTR_RESET & wInterrupt_Mask) {
_SetISTR((u16)CLR_RESET);
Device_Property.Reset();
}
#endif
#if (ISR_MSK & ISTR_DOVR)
if (wIstr & ISTR_DOVR & wInterrupt_Mask) {
_SetISTR((u16)CLR_DOVR);
}
#endif
#if (ISR_MSK & ISTR_ERR)
if (wIstr & ISTR_ERR & wInterrupt_Mask) {
_SetISTR((u16)CLR_ERR);
}
#endif
#if (ISR_MSK & ISTR_WKUP)
if (wIstr & ISTR_WKUP & wInterrupt_Mask) {
_SetISTR((u16)CLR_WKUP);
usbResume(RESUME_EXTERNAL);
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (ISR_MSK & ISTR_SUSP)
if (wIstr & ISTR_SUSP & wInterrupt_Mask) {
/* check if SUSPEND is possible */
if (F_SUSPEND_ENABLED) {
usbSuspend();
} else {
/* if not possible then resume after xx ms */
usbResume(RESUME_LATER);
}
/* clear of the ISTR bit must be done after setting of CNTR_FSUSP */
_SetISTR((u16)CLR_SUSP);
}
#endif
#if (ISR_MSK & ISTR_SOF)
if (wIstr & ISTR_SOF & wInterrupt_Mask) {
_SetISTR((u16)CLR_SOF);
bIntPackSOF++;
}
#endif
#if (ISR_MSK & ISTR_ESOF)
if (wIstr & ISTR_ESOF & wInterrupt_Mask) {
_SetISTR((u16)CLR_ESOF);
/* resume handling timing is made with ESOFs */
usbResume(RESUME_ESOF); /* request without change of the machine state */
}
#endif
/*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*/
#if (ISR_MSK & ISTR_CTR)
if (wIstr & ISTR_CTR & wInterrupt_Mask) {
/* servicing of the endpoint correct transfer interrupt */
/* clear of the CTR flag into the sub */
CTR_LP(); /* low priority ISR defined in the usb core lib */
}
#endif
}

View File

@ -1,142 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
#ifndef __USB_H
#define __USB_H
#include "common.h"
#include "usb_lib.h"
#include "usb_descriptor.h"
/* USB Disc Pin Setup. On the Mini, USB DISC is PB9 */
#define USB_DISC_BANK GPIOB
#define USB_DISC 9
#define USB_DISC_CR GPIO_CRH(USB_DISC_BANK)
#define USB_DISC_CR_MASK 0xFFFFFF0F
#define USB_DISC_CR_OUTPUT_OD 0x00000050
#define RCC_APB2ENR_USB 0x00000008
#define RCC_APB1ENR_USB_CLK 0x00800000
/* USB configuration params */
#define BTABLE_ADDRESS 0x00
#define ENDP0_RXADDR 0x40
#define ENDP0_TXADDR 0x80 /* gives 64 bytes i/o buflen */
#define ENDP1_TXADDR 0xC0
#define ENDP2_TXADDR 0x100
#define ENDP3_RXADDR 0x110
#define bMaxPacketSize 0x40 /* 64B, maximum for usb FS devices */
#define wTransferSize 0x0400 /* 1024B, want: maxpacket < wtransfer < 10KB (to ensure everything can live in ram */
#define NUM_ENDPTS 0x01
/* do we gracefully implement usb suspend? */
#define F_SUSPEND_ENABLED 1
/* defines which interrupts are handled */
#define ISR_MSK (CNTR_CTRM | \
CNTR_WKUPM | \
CNTR_SUSPM | \
CNTR_ERRM | \
CNTR_SOFM | \
CNTR_ESOFM | \
CNTR_RESETM \
)
typedef enum _RESUME_STATE {
RESUME_EXTERNAL,
RESUME_INTERNAL,
RESUME_LATER,
RESUME_WAIT,
RESUME_START,
RESUME_ON,
RESUME_OFF,
RESUME_ESOF
} RESUME_STATE;
typedef enum _DEVICE_STATE {
UNCONNECTED,
ATTACHED,
POWERED,
SUSPENDED,
ADDRESSED,
CONFIGURED
} DEVICE_STATE;
void setupUSB(void);
void usbDsbBus(void);
void usbAppInit(void); /* singleton usb initializer */
void usbSuspend(void);
void usbResumeInit(void);
void usbResume(RESUME_STATE state);
RESULT usbPowerOn(void);
RESULT usbPowerOff(void);
/* internal functions (as per the usb_core pProperty structure) */
void usbInit(void);
void usbReset(void);
void usbStatusIn(void);
void usbStatusOut(void);
RESULT usbDataSetup(u8 request);
RESULT usbNoDataSetup(u8 request);
RESULT usbGetInterfaceSetting(u8, u8);
u8 *usbGetDeviceDescriptor(u16 length);
u8 *usbGetConfigDescriptor(u16 length);
u8 *usbGetStringDescriptor(u16 length);
u8 *usbGetFunctionalDescriptor(u16 length);
/* internal callbacks to respond to standard requests */
void usbGetConfiguration(void);
void usbSetConfiguration(void);
void usbGetInterface(void);
void usbSetInterface(void);
void usbGetStatus(void);
void usbClearFeature(void);
void usbSetEndpointFeature(void);
void usbSetDeviceFeature(void);
void usbSetDeviceAddress(void);
/* the small number of comm emulator functions to
eventually be migrated into their own usart sources
*/
u8 *vcomGetLineCoding(u16 length);
u8 *vcomSetLineCoding(u16 length);
void vcomEp1In(void);
void vcomEp3Out(void);
/* Interrupt setup/handling exposed only so that
its obvious from main what interrupts are overloaded
from c_only_startup.s (see the top of main.c) */
void usbDsbISR(void);
void usbEnbISR(void);
/* override the weakly defined isr in linker */
void USB_LP_CAN1_RX0_IRQHandler(void);
void nothingProc(void);
#endif

View File

@ -1,31 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file usb_callbacks.c
*
* @brief aka endpoints: handling data transfer when "Configured". calls out to
* application specific callbacks (eg DFU)
*
*/

View File

@ -1,236 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
/**
* @file usb_descriptor.c
*
* @brief aka application descriptor; big static struct and callbacks for sending
* the descriptor.
*
*/
#include "usb_descriptor.h"
u8 u8_usbDeviceDescriptorDFU[18] = {
0x12, /* bLength */
0x01, /* bDescriptorType */
0x00, /* bcdUSB, version 1.00 */
0x01,
0x00, /* bDeviceClass : See interface */
0x00, /* bDeviceSubClass : See interface*/
0x00, /* bDeviceProtocol : See interface */
bMaxPacketSize, /* bMaxPacketSize0 0x40 = 64 */
VEND_ID0, /* idVendor (0110) */
VEND_ID1,
PROD_ID0, /* idProduct (0x1001 or 1002) */
PROD_ID1,
0x01, /* bcdDevice*/
0x02,
0x01, /* iManufacturer : index of string Manufacturer */
0x02, /* iProduct : index of string descriptor of product*/
0x03, /* iSerialNumber : index of string serial number*/
0x01 /*bNumConfigurations */
};
ONE_DESCRIPTOR usbDeviceDescriptorDFU = {
u8_usbDeviceDescriptorDFU,
0x12
};
u8 u8_usbFunctionalDescriptor[9] = {
/******************** DFU Functional Descriptor********************/
0x09, /*blength = 7 Bytes*/
0x21, /* DFU Functional Descriptor*/
0x03, /*bmAttributes, bitCanDnload | bitCanUpload */
0xFF, /*DetachTimeOut= 255 ms*/
0x00,
(wTransferSize & 0x00FF),
(wTransferSize & 0xFF00) >> 8, /* TransferSize = 1024 Byte*/
0x10, /* bcdDFUVersion = 1.1 */
0x01
};
ONE_DESCRIPTOR usbFunctionalDescriptor = {
u8_usbFunctionalDescriptor,
0x09
};
#define u8_usbConfigDescriptorDFU_LENGTH 45
u8 u8_usbConfigDescriptorDFU[u8_usbConfigDescriptorDFU_LENGTH] = {
0x09, /* bLength: Configuation Descriptor size */
0x02, /* bDescriptorType: Configuration */
u8_usbConfigDescriptorDFU_LENGTH, /* wTotalLength: Bytes returned */
0x00,
0x01, /* bNumInterfaces: 1 interface */
0x01, /* bConfigurationValue: */
0x00, /* iConfiguration: */
0x80, /* bmAttributes: */
0x32, /* MaxPower 100 mA */
/* 09 */
/************ Descriptor of DFU interface 0 Alternate setting 0 *********/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x00, /* bAlternateSetting: Alternate setting */
0x00, /* bNumEndpoints*/
0xFE, /* bInterfaceClass: DFU */
0x01, /* bInterfaceSubClass */
0x02, /* nInterfaceProtocol, switched to 0x02 while in dfu_mode */
0x04, /* iInterface: */
/************ Descriptor of DFU interface 0 Alternate setting 1 *********/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x01, /* bAlternateSetting: Alternate setting */
0x00, /* bNumEndpoints*/
0xFE, /* bInterfaceClass: DFU */
0x01, /* bInterfaceSubClass */
0x02, /* nInterfaceProtocol, switched to 0x02 while in dfu_mode */
0x05, /* iInterface: */
/************ Descriptor of DFU interface 0 Alternate setting 2 *********/
0x09, /* bLength: Interface Descriptor size */
0x04, /* bDescriptorType: */
0x00, /* bInterfaceNumber: Number of Interface */
0x02, /* bAlternateSetting: Alternate setting */
0x00, /* bNumEndpoints*/
0xFE, /* bInterfaceClass: DFU */
0x01, /* bInterfaceSubClass */
0x02, /* nInterfaceProtocol, switched to 0x02 while in dfu_mode */
0x06, /* iInterface: */
/******************** DFU Functional Descriptor********************/
0x09, /*blength = 7 Bytes*/
0x21, /* DFU Functional Descriptor*/
0x03, /*bmAttributes, bitCanDnload | bitCanUpload */
0xFF, /*DetachTimeOut= 255 ms*/
0x00,
(wTransferSize & 0x00FF),
(wTransferSize & 0xFF00) >> 8, /* TransferSize = 1024 Byte*/
0x10, /* bcdDFUVersion = 1.1 */
0x01
/***********************************************************/
/*36*/
};
ONE_DESCRIPTOR usbConfigDescriptorDFU = {
u8_usbConfigDescriptorDFU,
u8_usbConfigDescriptorDFU_LENGTH
};
#define USB_STR_LANG_ID_LEN 0x04
u8 u8_usbStringLangId[USB_STR_LANG_ID_LEN] = {
USB_STR_LANG_ID_LEN,
0x03,
0x09,
0x04 /* LangID = 0x0409: U.S. English */
};
#define USB_VENDOR_STR_LEN 0x12
u8 u8_usbStringVendor[USB_VENDOR_STR_LEN] = {
USB_VENDOR_STR_LEN,
0x03,
'L', 0, 'e', 0, 'a', 0, 'f', 0, 'L', 0, 'a', 0, 'b', 0, 's', 0
};
#define USB_PRODUCT_STR_LEN 0x14
u8 u8_usbStringProduct[USB_PRODUCT_STR_LEN] = {
USB_PRODUCT_STR_LEN,
0x03,
'M', 0, 'a', 0, 'p', 0, 'l', 0, 'e', 0, ' ', 0, '0', 0, '0', 0, '3', 0
};
#define USB_SERIAL_STR_LEN 0x10
u8 u8_usbStringSerial[USB_SERIAL_STR_LEN] = {
USB_SERIAL_STR_LEN,
0x03,
'L', 0, 'L', 0, 'M', 0, ' ', 0, '0', 0, '0', 0, '3', 0
};
#define ALT0_STR_LEN 0x6A
u8 u8_usbStringAlt0[ALT0_STR_LEN] = {
ALT0_STR_LEN,
0x03,
'B',0,'o',0,'o',0,'t',0,'l',0,'o',0,'a',0,'d',0,'e',0,'r',0,' ',0,'2',0,'.',0,'0',0,' ',0,'E',0,'R',0,'R',0,'O',0,'R',0,'.',0,' ',0,'U',0,'p',0,'l',0,'o',0,'a',0,'d',0,' ',0,'t',0,'o',0,' ',0,'R',0,'A',0,'M',0,' ',0,'i',0,'s',0,' ',0,'n',0,'o',0,'t',0,' ',0,'s',0,'u',0,'p',0,'p',0,'o',0,'r',0,'t',0,'e',0,'d',0
};
#define ALT1_STR_LEN 0x62
u8 u8_usbStringAlt1[ALT1_STR_LEN] = {
ALT1_STR_LEN,
0x03,
'B',0,'o',0,'o',0,'t',0,'l',0,'o',0,'a',0,'d',0,'e',0,'r',0,' ',0,'2',0,'.',0,'0',0,' ',0,'U',0,'p',0,'l',0,'o',0,'a',0,'d',0,' ',0,'t',0,'o',0,' ',0,'F',0,'l',0,'a',0,'s',0,'h',0,' ',0,'a',0,'d',0,'d',0,'r',0,'e',0,'s',0,'s',0,' ',0,'0',0,'x',0,'8',0,'0',0,'0',0,'5',0,'0',0,'0',0,'0',0
};
#define ALT2_STR_LEN 0x62
u8 u8_usbStringAlt2[ALT2_STR_LEN] = {
ALT2_STR_LEN,
0x03,
'B',0,'o',0,'o',0,'t',0,'l',0,'o',0,'a',0,'d',0,'e',0,'r',0,' ',0,'2',0,'.',0,'0',0,' ',0,'U',0,'p',0,'l',0,'o',0,'a',0,'d',0,' ',0,'t',0,'o',0,' ',0,'F',0,'l',0,'a',0,'s',0,'h',0,' ',0,'a',0,'d',0,'d',0,'r',0,'e',0,'s',0,'s',0,' ',0,'0',0,'x',0,'8',0,'0',0,'0',0,'2',0,'0',0,'0',0,'0',0
};
u8 u8_usbStringInterface = NULL;
ONE_DESCRIPTOR usbStringDescriptor[STR_DESC_LEN] = {
{ (u8 *)u8_usbStringLangId, USB_STR_LANG_ID_LEN },
{ (u8 *)u8_usbStringVendor, USB_VENDOR_STR_LEN },
{ (u8 *)u8_usbStringProduct, USB_PRODUCT_STR_LEN },
{ (u8 *)u8_usbStringSerial, USB_SERIAL_STR_LEN },
{ (u8 *)u8_usbStringAlt0, ALT0_STR_LEN },
{ (u8 *)u8_usbStringAlt1, ALT1_STR_LEN },
{ (u8 *)u8_usbStringAlt2, ALT2_STR_LEN }
};
/*
Roger.
Javascript utility to make new ALT ID text structs
<html>
<script>
function convertText(txt,idNum)
{
var txt2 ="#define ALT"+idNum+"_STR_LEN 0x"+(txt.length*2 + 2).toString(16).toUpperCase()+"<br/>u8 u8_usbStringAlt"+idNum+"[ALT"+idNum+"_STR_LEN] = {<br/>ALT"+idNum+"_STR_LEN,<br/>0x03,<br/>";
for (var i=0;i<txt.length;i++)
{
txt2+="'"+txt[i]+"',0,";
}
return txt2.substring(0,txt2.length-1)+"<br/>};<br/>";
}
document.write("<pre>");
document.write(convertText("Bootloader 2.0 ERROR. Upload to RAM is not supported",0)+"<br/>");
document.write(convertText("Bootloader 2.0 Upload to Flash address 0x8005000",1)+"<br/>");
document.write(convertText("Bootloader 2.0 Upload to Flash address 0x8002000",2)+"<br/>");
document.write("</pre>");
</script>
</html>
*/

View File

@ -1,40 +0,0 @@
/* *****************************************************************************
* The MIT License
*
* Copyright (c) 2010 LeafLabs LLC.
*
* 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.
* ****************************************************************************/
#ifndef __MAPLE_USB_DESC_H
#define __MAPLE_USB_DESC_H
#include "common.h"
#include "usb_lib.h"
#include "usb.h"
#define NUM_ALT_SETTINGS 3
#define STR_DESC_LEN 7
extern ONE_DESCRIPTOR usbDeviceDescriptorDFU;
extern ONE_DESCRIPTOR usbConfigDescriptorDFU;
extern ONE_DESCRIPTOR usbStringDescriptor[STR_DESC_LEN];
extern ONE_DESCRIPTOR usbFunctionalDescriptor;
#endif

View File

@ -1,86 +0,0 @@
/******************** (C) COPYRIGHT 2008 STMicroelectronics ********************
* File Name : usb_conf.h
* Author : MCD Application Team
* Version : V2.2.1
* Date : 09/22/2008
* Description : Device Firmware Upgrade (DFU) configuration file
********************************************************************************
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
* AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
* INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
* CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
* INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USB_CONF_H
#define __USB_CONF_H
/* Includes ------------------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/
/* Exported constants --------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions ------------------------------------------------------- */
/* External variables --------------------------------------------------------*/
/*-------------------------------------------------------------*/
/* EP_NUM */
/* defines how many endpoints are used by the device */
/*-------------------------------------------------------------*/
#define EP_NUM (1)
/*-------------------------------------------------------------*/
/* -------------- Buffer Description Table -----------------*/
/*-------------------------------------------------------------*/
/* buffer table base address */
/* buffer table base address */
#define BTABLE_ADDRESS (0x00)
/* EP0 */
/* rx/tx buffer base address */
#define ENDP0_RXADDR (0x10)
#define ENDP0_TXADDR (0x50)
/*-------------------------------------------------------------*/
/* ------------------- ISTR events -------------------------*/
/*-------------------------------------------------------------*/
/* IMR_MSK */
/* mask defining which events has to be handled */
/* by the device application software */
#define IMR_MSK (CNTR_CTRM | \
CNTR_WKUPM | \
CNTR_SUSPM | \
CNTR_ERRM | \
CNTR_SOFM | \
CNTR_ESOFM | \
CNTR_RESETM \
)
/* CTR service routines */
/* associated to defined endpoints */
#define EP1_IN_Callback NOP_Process
#define EP2_IN_Callback NOP_Process
#define EP3_IN_Callback NOP_Process
#define EP4_IN_Callback NOP_Process
#define EP5_IN_Callback NOP_Process
#define EP6_IN_Callback NOP_Process
#define EP7_IN_Callback NOP_Process
#define EP1_OUT_Callback NOP_Process
#define EP2_OUT_Callback NOP_Process
#define EP3_OUT_Callback NOP_Process
#define EP4_OUT_Callback NOP_Process
#define EP5_OUT_Callback NOP_Process
#define EP6_OUT_Callback NOP_Process
#define EP7_OUT_Callback NOP_Process
#endif /*__USB_CONF_H*/
/******************* (C) COPYRIGHT 2008 STMicroelectronics *****END OF FILE****/

Some files were not shown because too many files have changed in this diff Show More