Merge pull request #7 from rogerclarkmelbourne/master

Resync to Roger's
This commit is contained in:
victorpv 2015-08-24 22:14:52 -05:00
commit 37cdca09f4
417 changed files with 37815 additions and 8838 deletions

2
.gitignore vendored
View File

@ -6,4 +6,4 @@ other/maple-bootloader/cscope.out
other/maple-bootloader/build
other/maple-bootloader/*~
*.o
tools/src/stm32flash/src/parsers/parsers.a
tools/src/stm32flash_serial/src/parsers/parsers.a

12
.gitmodules vendored
View File

@ -7,6 +7,12 @@
[submodule "tools/src/texane-stlink"]
path = tools/src/texane-stlink
url = https://github.com/texane/stlink
[submodule "tools/src/dfu-util"]
path = tools/src/dfu-util
url = https://gitorious.org/dfu-util/dfu-util.git
[submodule "STM32duino-bootloader"]
path = STM32duino-bootloader
url = https://github.com/rogerclarkmelbourne/STM32duino-bootloader.git
[submodule "STM32F1/libraries/TFT_ILI9163C"]
path = STM32F1/libraries/TFT_ILI9163C
url = https://github.com/victorpv/TFT_ILI9163C.git
[submodule "STM32F1/libraries/Ethernet_STM"]
path = STM32F1/libraries/Ethernet_STM
url = https://github.com/Serasidis/Ethernet_STM

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,38 +6,38 @@ menu.bootloader_version=Bootloader version
menu.upload_method=Upload method
##############################################################
maple_mini.name=LeafLabs Maple Mini Rev 2 to Flash
mapleMini.name=Maple Mini
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
maple.name=Maple (Rev 3)
maple.upload.tool=maple_upload
maple.upload.protocol=maple_dfu
@ -60,7 +60,7 @@ maple.build.vect=VECT_TAB_ADDR=0x8005000
##############################################################
mapleRET6.name=LeafLabs Maple RET6 to Flash
mapleRET6.name=Maple (RET6)
mapleRET6.build.board=MAPLE_RET6
mapleRET6.build.core=maple
@ -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,21 +199,11 @@ 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.build.variant=generic_stm32f103r
genericSTM32F103R.name=Generic STM32F103R series
#genericSTM32F103R.build.variant=generic_stm32f103r
genericSTM32F103R.build.vect=VECT_TAB_ADDR=0x8000000
genericSTM32F103R.build.core=maple
genericSTM32F103R.build.board=GENERIC_STM32F103R
@ -211,15 +211,51 @@ genericSTM32F103R.upload.use_1200bps_touch=false
genericSTM32F103R.upload.file_type=bin
genericSTM32F103R.upload.auto_reset=true
genericSTM32F103R.menu.device_variant.STM32F103RE=STM32F103RE
genericSTM32F103R.menu.device_variant.STM32F103R8=STM32F103R8 (20k RAM. 64k Flash)
genericSTM32F103R.menu.device_variant.STM32F103R8.build.variant=generic_stm32f103r8
genericSTM32F103R.menu.device_variant.STM32F103R8.build.cpu_flags=-DMCU_STM32F103R8
genericSTM32F103R.menu.device_variant.STM32F103R8.upload.maximum_size=65536
genericSTM32F103R.menu.device_variant.STM32F103R8.upload.ram.maximum_size=20480
genericSTM32F103R.menu.device_variant.STM32F103R8.upload.flash.maximum_size=65536
genericSTM32F103R.menu.device_variant.STM32F103R8.build.ldscript=ld/stm32f103r8.ld
genericSTM32F103R.menu.device_variant.STM32F103RB=STM32F103RB (20k RAM. 128k Flash)
genericSTM32F103R.menu.device_variant.STM32F103RB.build.variant=generic_stm32f103r8
genericSTM32F103R.menu.device_variant.STM32F103RB.build.cpu_flags=-DMCU_STM32F103RB
genericSTM32F103R.menu.device_variant.STM32F103RB.upload.maximum_size=131072
genericSTM32F103R.menu.device_variant.STM32F103RB.upload.ram.maximum_size=20480
genericSTM32F103R.menu.device_variant.STM32F103RB.upload.flash.maximum_size=131072
genericSTM32F103R.menu.device_variant.STM32F103RB.build.ldscript=ld/stm32f103rb.ld
genericSTM32F103R.menu.device_variant.STM32F103RC=STM32F103RC (48k RAM. 256k Flash)
genericSTM32F103R.menu.device_variant.STM32F103RC.build.variant=generic_stm32f103r
genericSTM32F103R.menu.device_variant.STM32F103RC.build.cpu_flags=-DMCU_STM32F103RC
genericSTM32F103R.menu.device_variant.STM32F103RC.upload.maximum_size=262144
genericSTM32F103R.menu.device_variant.STM32F103RC.upload.ram.maximum_size=49152
genericSTM32F103R.menu.device_variant.STM32F103RC.upload.flash.maximum_size=262144
genericSTM32F103R.menu.device_variant.STM32F103RC.build.ldscript=ld/stm32f103rc.ld
genericSTM32F103R.menu.device_variant.STM32F103RE=STM32F103RE (64k RAM. 512k Flash)
genericSTM32F103R.menu.device_variant.STM32F103RE.build.variant=generic_stm32f103r
genericSTM32F103R.menu.device_variant.STM32F103RE.build.cpu_flags=-DMCU_STM32F103RE
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.maximum_size=492000
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.ram.maximum_size=61000
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.flash.maximum_size=492000
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.maximum_size=524288
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.ram.maximum_size=65536
genericSTM32F103R.menu.device_variant.STM32F103RE.upload.flash.maximum_size=524288
genericSTM32F103R.menu.device_variant.STM32F103RE.build.ldscript=ld/stm32f103re.ld
#---------------------------- 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/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
@ -235,19 +271,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
@ -285,11 +311,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
@ -300,20 +335,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
@ -345,6 +369,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
@ -358,12 +392,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

@ -235,7 +235,7 @@ int32 i2c_master_xfer(i2c_dev *dev,
i2c_enable_irq(dev, I2C_IRQ_EVENT);
i2c_start_condition(dev);
rc = wait_for_state_change(dev, I2C_STATE_XFER_DONE, timeout);
if (rc < 0) {
goto out;
@ -347,9 +347,20 @@ void _i2c_irq_handler(i2c_dev *dev) {
* register. We should get another TXE interrupt
* immediately to fill DR again.
*/
if (msg->length != 1) {
if (msg->length > 1) {
i2c_write(dev, msg->data[msg->xferred++]);
}
} else if (msg->length == 0) { /* We're just sending an address */
i2c_stop_condition(dev);
/*
* Turn off event interrupts to keep BTF from firing until
* the end of the stop condition. Why on earth they didn't
* have a start/stop condition request clear BTF is beyond
* me.
*/
i2c_disable_irq(dev, I2C_IRQ_EVENT);
I2C_CRUMB(STOP_SENT, 0, 0);
dev->state = I2C_STATE_XFER_DONE;
} /* else we're just sending one byte */
}
sr1 = sr2 = 0;
}
@ -456,7 +467,7 @@ void _i2c_irq_handler(i2c_dev *dev) {
void _i2c_irq_error_handler(i2c_dev *dev) {
I2C_CRUMB(ERROR_ENTRY, dev->regs->SR1, dev->regs->SR2);
dev->error_flags = dev->regs->SR2 & (I2C_SR1_BERR |
dev->error_flags = dev->regs->SR1 & (I2C_SR1_BERR |
I2C_SR1_ARLO |
I2C_SR1_AF |
I2C_SR1_OVR);

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

@ -1,3 +1,4 @@
/******************************************************************************
* The MIT License
*
@ -410,3 +411,102 @@ static void enable_bas_gen_irq(timer_dev *dev) {
}
nvic_irq_enable(irq_num);
}
/* Note.
*
* 2015/07/06 Roger Clark
*
* The IRQ handlers were initially in timer_f1.c however this seems to cause problems
* in which the compiler / linker doesn't always link all the required handlers.
* The work around was to move the handlers into this file
*/
/*
* IRQ handlers
*
* Defer to the timer_private dispatch API.
*
* FIXME: The names of these handlers are inaccurate since XL-density
* devices came out. Update these to match the STM32F2 names, maybe
* using some weak symbol magic to preserve backwards compatibility if
* possible. Once that's done, we can just move the IRQ handlers into
* the top-level libmaple/timer.c, and there will be no need for this
* file.
*/
void __irq_tim1_brk(void) {
dispatch_adv_brk(TIMER1);
#if STM32_HAVE_TIMER(9)
dispatch_tim_9_12(TIMER9);
#endif
}
void __irq_tim1_up(void) {
dispatch_adv_up(TIMER1);
#if STM32_HAVE_TIMER(10)
dispatch_tim_10_11_13_14(TIMER10);
#endif
}
void __irq_tim1_trg_com(void) {
dispatch_adv_trg_com(TIMER1);
#if STM32_HAVE_TIMER(11)
dispatch_tim_10_11_13_14(TIMER11);
#endif
}
void __irq_tim1_cc(void) {
dispatch_adv_cc(TIMER1);
}
void __irq_tim2(void) {
dispatch_general(TIMER2);
}
void __irq_tim3(void) {
dispatch_general(TIMER3);
}
void __irq_tim4(void) {
dispatch_general(TIMER4);
}
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
void __irq_tim5(void) {
dispatch_general(TIMER5);
}
void __irq_tim6(void) {
dispatch_basic(TIMER6);
}
void __irq_tim7(void) {
dispatch_basic(TIMER7);
}
void __irq_tim8_brk(void) {
dispatch_adv_brk(TIMER8);
#if STM32_HAVE_TIMER(12)
dispatch_tim_9_12(TIMER12);
#endif
}
void __irq_tim8_up(void) {
dispatch_adv_up(TIMER8);
#if STM32_HAVE_TIMER(13)
dispatch_tim_10_11_13_14(TIMER13);
#endif
}
void __irq_tim8_trg_com(void) {
dispatch_adv_trg_com(TIMER8);
#if STM32_HAVE_TIMER(14)
dispatch_tim_10_11_13_14(TIMER14);
#endif
}
void __irq_tim8_cc(void) {
dispatch_adv_cc(TIMER8);
}
#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */

View File

@ -30,95 +30,12 @@
* @brief STM32F1 timer.
*/
#include <libmaple/timer.h>
#include <libmaple/stm32.h>
#include "timer_private.h"
/*
* IRQ handlers
*
* Defer to the timer_private dispatch API.
*
* FIXME: The names of these handlers are inaccurate since XL-density
* devices came out. Update these to match the STM32F2 names, maybe
* using some weak symbol magic to preserve backwards compatibility if
* possible. Once that's done, we can just move the IRQ handlers into
* the top-level libmaple/timer.c, and there will be no need for this
* file.
* 2015/07/06
* Note. The IRQ handlers which were initially in this file have been moved to timer.c
* to resolve a linker issue in where some IRQ handlers were not being linked even though
* they were being used.
* This file has been retains for historical reasons, but can be moved at some time in the future
* when full testing of the code in the new location has been completed.
*/
void __irq_tim1_brk(void) {
dispatch_adv_brk(TIMER1);
#if STM32_HAVE_TIMER(9)
dispatch_tim_9_12(TIMER9);
#endif
}
void __irq_tim1_up(void) {
dispatch_adv_up(TIMER1);
#if STM32_HAVE_TIMER(10)
dispatch_tim_10_11_13_14(TIMER10);
#endif
}
void __irq_tim1_trg_com(void) {
dispatch_adv_trg_com(TIMER1);
#if STM32_HAVE_TIMER(11)
dispatch_tim_10_11_13_14(TIMER11);
#endif
}
void __irq_tim1_cc(void) {
dispatch_adv_cc(TIMER1);
}
void __irq_tim2(void) {
dispatch_general(TIMER2);
}
void __irq_tim3(void) {
dispatch_general(TIMER3);
}
void __irq_tim4(void) {
dispatch_general(TIMER4);
}
#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY)
void __irq_tim5(void) {
dispatch_general(TIMER5);
}
void __irq_tim6(void) {
dispatch_basic(TIMER6);
}
void __irq_tim7(void) {
dispatch_basic(TIMER7);
}
void __irq_tim8_brk(void) {
dispatch_adv_brk(TIMER8);
#if STM32_HAVE_TIMER(12)
dispatch_tim_9_12(TIMER12);
#endif
}
void __irq_tim8_up(void) {
dispatch_adv_up(TIMER8);
#if STM32_HAVE_TIMER(13)
dispatch_tim_10_11_13_14(TIMER13);
#endif
}
void __irq_tim8_trg_com(void) {
dispatch_adv_trg_com(TIMER8);
#if STM32_HAVE_TIMER(14)
dispatch_tim_10_11_13_14(TIMER14);
#endif
}
void __irq_tim8_cc(void) {
dispatch_adv_cc(TIMER8);
}
#endif /* defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) */

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

@ -74,11 +74,12 @@
#include <stdint.h>
#warning these are just here to get SPI to compile they need to be changed and moved!
#define SS (1)
#define MOSI 2
#define MISO 3
#define SCK 4
#define SS BOARD_SPI1_NSS_PIN
#define MOSI BOARD_SPI1_MOSI_PIN
#define MISO BOARD_SPI1_MISO_PIN
#define SCK BOARD_SPI1_SCK_PIN
typedef unsigned int word;
// typedef uint16 word;// definition from Arduino website, now appears to be incorrect for 32 bit devices

@ -0,0 +1 @@
Subproject commit 5dd518a193f5879744b1b3f5b112ee03c6ee14b2

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

@ -91,26 +91,50 @@ static const spi_pins board_spi_pins[] __FLASH__ = {
*/
SPIClass::SPIClass(uint32 spi_num) {
_currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed
switch (spi_num) {
#if BOARD_NR_SPI >= 1
case 1:
this->spi_d = SPI1;
_currentSetting->spi_d = SPI1;
break;
#endif
#if BOARD_NR_SPI >= 2
case 2:
this->spi_d = SPI2;
_currentSetting->spi_d = SPI2;
break;
#endif
#if BOARD_NR_SPI >= 3
case 3:
this->spi_d = SPI3;
_currentSetting->spi_d = SPI3;
break;
#endif
default:
ASSERT(0);
}
// Init things specific to each SPI device
// clock divider setup is a bit of hack, and needs to be improved at a later date.
_settings[0].spi_d = SPI1;
_settings[0].clockDivider = determine_baud_rate(_settings[0].spi_d, _settings[0].clock);
_settings[0].spiDmaDev = DMA1;
_settings[0].spiTxDmaChannel = DMA_CH3;
_settings[0].spiRxDmaChannel = DMA_CH2;
_settings[1].spi_d = SPI2;
_settings[1].clockDivider = determine_baud_rate(_settings[1].spi_d, _settings[1].clock);
_settings[1].spiDmaDev = DMA1;
_settings[1].spiTxDmaChannel = DMA_CH5;
_settings[1].spiRxDmaChannel = DMA_CH4;
#if BOARD_NR_SPI >= 3
_settings[2].spi_d = SPI3;
_settings[2].clockDivider = determine_baud_rate(_settings[2].spi_d, _settings[2].clock);
_settings[2].spiDmaDev = DMA2;
_settings[2].spiTxDmaChannel = DMA_CH2;
_settings[2].spiRxDmaChannel = DMA_CH1;
#endif
//pinMode(BOARD_SPI_DEFAULT_SS,OUTPUT);
}
@ -119,49 +143,46 @@ 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);
uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS);
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 1);
#ifdef SPI_DEBUG
Serial.print("spi_master_enable("); Serial.print(clockDivider); Serial.print(","); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")");
Serial.print("spi_master_enable("); Serial.print(_currentSetting->clockDivider); Serial.print(","); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")");
#endif
spi_master_enable(spi_d, (spi_baud_rate)clockDivider, (spi_mode)dataMode, flags);
spi_master_enable(_currentSetting->spi_d, (spi_baud_rate)_currentSetting->clockDivider, (spi_mode)_currentSetting->dataMode, flags);
}
void SPIClass::beginSlave(void) {
if (dataMode >= 4) {
if (_currentSetting->dataMode >= 4) {
ASSERT(0);
return;
}
uint32 flags = ((bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE);
spi_init(spi_d);
configure_gpios(spi_d, 0);
uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE);
spi_init(_currentSetting->spi_d);
configure_gpios(_currentSetting->spi_d, 0);
#ifdef SPI_DEBUG
Serial.print("spi_slave_enable("); Serial.print(dataMode); Serial.print(","); Serial.print(flags); Serial.println(")");
Serial.print("spi_slave_enable("); Serial.print(_currentSetting->dataMode); Serial.print(","); Serial.print(flags); Serial.println(")");
#endif
spi_slave_enable(spi_d, (spi_mode)dataMode, flags);
spi_slave_enable(_currentSetting->spi_d, (spi_mode)_currentSetting->dataMode, flags);
}
void SPIClass::end(void) {
if (!spi_is_enabled(this->spi_d)) {
if (!spi_is_enabled(_currentSetting->spi_d)) {
return;
}
// Follows RM0008's sequence for disabling a SPI in master/slave
// full duplex mode.
while (spi_is_rx_nonempty(this->spi_d)) {
while (spi_is_rx_nonempty(_currentSetting->spi_d)) {
// FIXME [0.1.0] remove this once you have an interrupt based driver
volatile uint16 rx __attribute__((unused)) = spi_rx_reg(this->spi_d);
volatile uint16 rx __attribute__((unused)) = spi_rx_reg(_currentSetting->spi_d);
}
while (!spi_is_tx_empty(this->spi_d))
while (!spi_is_tx_empty(_currentSetting->spi_d))
;
while (spi_is_busy(this->spi_d))
while (spi_is_busy(_currentSetting->spi_d))
;
spi_peripheral_disable(this->spi_d);
spi_peripheral_disable(_currentSetting->spi_d);
}
/* Roger Clark added 3 functions */
@ -170,7 +191,7 @@ void SPIClass::setClockDivider(uint32_t clockDivider)
#ifdef SPI_DEBUG
Serial.print("Clock divider set to "); Serial.println(clockDivider);
#endif
this->clockDivider = clockDivider;
_currentSetting->clockDivider = clockDivider;
this->begin();
}
@ -179,7 +200,7 @@ void SPIClass::setBitOrder(BitOrder bitOrder)
#ifdef SPI_DEBUG
Serial.print("Bit order set to "); Serial.println(bitOrder);
#endif
this->bitOrder = bitOrder;
_currentSetting->bitOrder = bitOrder;
this->begin();
}
@ -189,11 +210,11 @@ void SPIClass::setBitOrder(BitOrder bitOrder)
*/
void SPIClass::setDataSize(uint32 datasize)
{
uint32 cr1 = this->spi_d->regs->CR1;
uint32 cr1 = _currentSetting->spi_d->regs->CR1;
datasize &= SPI_CR1_DFF;
cr1 &= ~(SPI_CR1_DFF);
cr1 |= datasize;
this->spi_d->regs->CR1 = cr1;
_currentSetting->spi_d->regs->CR1 = cr1;
}
void SPIClass::setDataMode(uint8_t dataMode)
@ -228,7 +249,7 @@ If someone finds this is not the case or sees a logic error with this let me kno
#ifdef SPI_DEBUG
Serial.print("Data mode set to "); Serial.println(dataMode);
#endif
this->dataMode = dataMode;
_currentSetting->dataMode = dataMode;
this->begin();
}
@ -243,29 +264,9 @@ void SPIClass::beginTransaction(uint8_t pin, SPISettings settings)
//digitalWrite(_SSPin,LOW);
setBitOrder(settings.bitOrder);
setDataMode(settings.dataMode);
setClockDivider(determine_baud_rate(spi_d, settings.clock));
setClockDivider(determine_baud_rate(_currentSetting->spi_d, settings.clock));
begin();
#if 0
// code from SAM core
uint8_t mode = interruptMode;
if (mode > 0) {
if (mode < 16) {
if (mode & 1) PIOA->PIO_IDR = interruptMask[0];
if (mode & 2) PIOB->PIO_IDR = interruptMask[1];
if (mode & 4) PIOC->PIO_IDR = interruptMask[2];
if (mode & 8) PIOD->PIO_IDR = interruptMask[3];
} else {
interruptSave = interruptsStatus();
noInterrupts();
}
}
uint32_t ch = BOARD_PIN_TO_SPI_CHANNEL(pin);
bitOrder[ch] = settings.border;
SPI_ConfigureNPCS(spi, ch, settings.config);
//setBitOrder(pin, settings.border);
//setDataMode(pin, settings.datamode);
//setClockDivider(pin, settings.clockdiv);
#endif
}
void SPIClass::endTransaction(void)
@ -304,9 +305,9 @@ uint8 SPIClass::read(void) {
void SPIClass::read(uint8 *buf, uint32 len) {
uint32 rxed = 0;
while (rxed < len) {
while (!spi_is_rx_nonempty(this->spi_d))
while (!spi_is_rx_nonempty(_currentSetting->spi_d))
;
buf[rxed++] = (uint8)spi_rx_reg(this->spi_d);
buf[rxed++] = (uint8)spi_rx_reg(_currentSetting->spi_d);
}
}
@ -319,9 +320,9 @@ void SPIClass::write(uint16 data) {
* This almost doubles the speed of this function.
*/
spi_tx_reg(this->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
spi_tx_reg(_currentSetting->spi_d, data); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
}
//void SPIClass::write(uint8 byte) {
@ -333,27 +334,27 @@ void SPIClass::write(uint16 data) {
* This almost doubles the speed of this function.
*/
// spi_tx_reg(this->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
// while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
// while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
// spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
// while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
// while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
//}
void SPIClass::write(const uint8 *data, uint32 length) {
uint32 txed = 0;
while (txed < length) {
txed += spi_tx(this->spi_d, data + txed, length - txed);
txed += spi_tx(_currentSetting->spi_d, data + txed, length - txed);
}
while (spi_is_tx_empty(this->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete."
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "4. After writing the last data item into the SPI_DR register, wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... then wait until BSY=0, this indicates that the transmission of the last data is complete."
}
uint8 SPIClass::transfer(uint8 byte) {
uint8 SPIClass::transfer(uint8 byte) const {
uint8 b;
spi_tx_reg(this->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
spi_tx_reg(_currentSetting->spi_d, byte); // "2. Write the first data item to be transmitted into the SPI_DR register (this clears the TXE flag)."
while (spi_is_rx_nonempty(_currentSetting->spi_d) == 0); // "4. Wait until RXNE=1 ..."
b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
return b;
}
/* Roger Clark and Victor Perez, 2015
@ -364,53 +365,57 @@ uint8 SPIClass::transfer(uint8 byte) {
*/
uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length) {
if (length == 0) return 0;
uint8 b;
if (spi_is_rx_nonempty(this->spi_d) == 1) b = spi_rx_reg(this->spi_d); //Clear the RX buffer in case a byte is waiting on it.
dma1_ch3_Active=true;
dma_init(DMA1);
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
uint8 b = 0;
if (spi_is_rx_nonempty(_currentSetting->spi_d) == 1) b = spi_rx_reg(_currentSetting->spi_d); //Clear the RX buffer in case a byte is waiting on it.
// dma1_ch3_Active=true;
dma_init(_currentSetting->spiDmaDev);
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
// RX
spi_rx_dma_enable(SPI1);
dma_setup_transfer(DMA1, DMA_CH2, &SPI1->regs->DR, DMA_SIZE_8BITS,
spi_rx_dma_enable(_currentSetting->spi_d);
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
receiveBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_TRNS_CMPLT));// receive buffer DMA
dma_set_num_transfers(DMA1, DMA_CH2, length);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel, length);
// TX
spi_tx_dma_enable(SPI1);
spi_tx_dma_enable(_currentSetting->spi_d);
if (!transmitBuf) {
static uint8_t ff = 0XFF;
transmitBuf = &ff;
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
transmitBuf, DMA_SIZE_8BITS, (DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit FF repeatedly
}
else {
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
transmitBuf, DMA_SIZE_8BITS, (DMA_MINC_MODE | DMA_FROM_MEM | DMA_TRNS_CMPLT));// Transmit buffer DMA
}
dma_set_num_transfers(DMA1, DMA_CH3, length);
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_enable(DMA1, DMA_CH2);// enable receive
dma_enable(DMA1, DMA_CH3);// enable transmit
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);// enable receive
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
// while (dma1_ch3_Active);
// if (receiveBuf) {
uint32_t m = millis();
while (dma1_ch3_Active) {
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0) {//Avoid interrupts and just loop waiting for the flag to be set.
if ((millis() - m) > 100) {
dma1_ch3_Active = 0;
// dma1_ch3_Active = 0;
b = 2;
break;
}
}
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
// }
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(DMA1, DMA_CH3);
dma_disable(DMA1, DMA_CH2);
spi_rx_dma_disable(SPI1);
spi_tx_dma_disable(SPI1);
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiRxDmaChannel);
spi_rx_dma_disable(_currentSetting->spi_d); // And disable generation of DMA request from the SPI port so other peripherals can use the channels
spi_tx_dma_disable(_currentSetting->spi_d);
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
}
return b;
}
@ -422,25 +427,29 @@ uint8 SPIClass::dmaTransfer(uint8 *transmitBuf, uint8 *receiveBuf, uint16 length
uint8 SPIClass::dmaSend(uint8 *transmitBuf, uint16 length, bool minc) {
if (length == 0) return 0;
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
uint8 b;
dma1_ch3_Active=true;
dma_init(DMA1);
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
uint8 b = 0;
// dma1_ch3_Active=true;
dma_init(_currentSetting->spiDmaDev);
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
// TX
spi_tx_dma_enable(SPI1);
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_8BITS,
spi_tx_dma_enable(_currentSetting->spi_d);
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_8BITS,
transmitBuf, DMA_SIZE_8BITS, flags);// Transmit buffer DMA
dma_set_num_transfers(DMA1, DMA_CH3, length);
dma_enable(DMA1, DMA_CH3);// enable transmit
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
while (dma1_ch3_Active);
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(DMA1, DMA_CH3);
spi_tx_dma_disable(SPI1);
// while (dma1_ch3_Active);
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
spi_tx_dma_disable(_currentSetting->spi_d);
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
uint8 x = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
}
return b;
}
@ -449,23 +458,27 @@ uint8 SPIClass::dmaSend(uint16 *transmitBuf, uint16 length, bool minc) {
uint32 flags = ((DMA_MINC_MODE * minc) | DMA_FROM_MEM | DMA_TRNS_CMPLT);
uint8 b;
dma1_ch3_Active=true;
dma_init(DMA1);
dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
dma_init(_currentSetting->spiDmaDev);
// dma_attach_interrupt(DMA1, DMA_CH3, &SPIClass::DMA1_CH3_Event);
// TX
spi_tx_dma_enable(SPI1);
dma_setup_transfer(DMA1, DMA_CH3, &SPI1->regs->DR, DMA_SIZE_16BITS,
spi_tx_dma_enable(_currentSetting->spi_d);
dma_setup_transfer(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, &_currentSetting->spi_d->regs->DR, DMA_SIZE_16BITS,
transmitBuf, DMA_SIZE_16BITS, flags);// Transmit buffer DMA
dma_set_num_transfers(DMA1, DMA_CH3, length);
dma_enable(DMA1, DMA_CH3);// enable transmit
dma_set_num_transfers(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel, length);
dma_enable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);// enable transmit
while (dma1_ch3_Active);
while (spi_is_rx_nonempty(this->spi_d) == 0); // "4. Wait until RXNE=1 ..."
b = spi_rx_reg(this->spi_d); // "... and read the last received data."
while (spi_is_tx_empty(this->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(this->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(DMA1, DMA_CH3);
spi_tx_dma_disable(SPI1);
// while (dma1_ch3_Active);
while ((dma_get_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel) & 0x2)==0); //Avoid interrupts and just loop waiting for the flag to be set.
dma_clear_isr_bits(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
while (spi_is_tx_empty(_currentSetting->spi_d) == 0); // "5. Wait until TXE=1 ..."
while (spi_is_busy(_currentSetting->spi_d) != 0); // "... and then wait until BSY=0 before disabling the SPI."
dma_disable(_currentSetting->spiDmaDev, _currentSetting->spiTxDmaChannel);
spi_tx_dma_disable(_currentSetting->spi_d);
if (spi_is_rx_nonempty(_currentSetting->spi_d) != 0){; // "4. Wait until RXNE=1 ..."
b = spi_rx_reg(_currentSetting->spi_d); // "... and read the last received data."
}
return b;
}
@ -483,19 +496,19 @@ void SPIClass::detachInterrupt(void) {
*/
uint8 SPIClass::misoPin(void) {
return dev_to_spi_pins(this->spi_d)->miso;
return dev_to_spi_pins(_currentSetting->spi_d)->miso;
}
uint8 SPIClass::mosiPin(void) {
return dev_to_spi_pins(this->spi_d)->mosi;
return dev_to_spi_pins(_currentSetting->spi_d)->mosi;
}
uint8 SPIClass::sckPin(void) {
return dev_to_spi_pins(this->spi_d)->sck;
return dev_to_spi_pins(_currentSetting->spi_d)->sck;
}
uint8 SPIClass::nssPin(void) {
return dev_to_spi_pins(this->spi_d)->nss;
return dev_to_spi_pins(_currentSetting->spi_d)->nss;
}
/*

View File

@ -118,6 +118,13 @@ private:
uint32_t clock;
BitOrder bitOrder;
uint8_t dataMode;
spi_dev *spi_d;
uint8_t _SSPin;
uint32_t clockDivider;
dma_channel spiRxDmaChannel, spiTxDmaChannel;
dma_dev* spiDmaDev;
friend class SPIClass;
};
@ -238,7 +245,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.
@ -304,7 +311,24 @@ public:
* @brief Get a pointer to the underlying libmaple spi_dev for
* this HardwareSPI instance.
*/
spi_dev* c_dev(void) { return this->spi_d; }
spi_dev* c_dev(void) { return _currentSetting->spi_d; }
spi_dev *dev(){ return _currentSetting->spi_d;}
/**
* @brief Sets the number of the SPI peripheral to be used by
* this HardwareSPI instance.
*
* @param spi_num Number of the SPI port. 1-2 in low density devices
* or 1-3 in high density devices.
*/
void setModule(int spi_num)
{
_currentSetting=&_settings[spi_num-1];// SPI channels are called 1 2 and 3 but the array is zero indexed
}
/* -- The following methods are deprecated --------------------------- */
@ -338,12 +362,8 @@ public:
*/
uint8 recv(void);
spi_dev *dev(){ return spi_d;}
private:
/*
static inline void DMA1_CH3_Event() {
dma1_ch3_Active = 0;
// dma_disable(DMA1, DMA_CH3);
@ -351,11 +371,17 @@ private:
// To Do. Need to wait for
}
*/
SPISettings _settings[BOARD_NR_SPI];
SPISettings *_currentSetting;
/*
spi_dev *spi_d;
uint8_t _SSPin;
uint32_t clockDivider;
uint8_t dataMode;
BitOrder bitOrder;
*/
};

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,19 @@
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).
01 July 2015 - Added a Flac decoder patch.
*/
// 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];}))
#if defined(USEFLAC)
#include "flac.h"
#endif
#define vs1003_chunk_size 32
/****************************************************************************/
// VS1003 SCI Write Command byte is 0x02
@ -81,24 +69,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 +115,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 +132,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 +147,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 +158,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 +175,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 +205,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 +232,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
@ -252,6 +242,9 @@ void VS1003_STM::begin(void)
write_register(SCI_MODE, (1<<SM_SDINEW) | (1<<SM_RESET));
delay(1);
await_data_request();
#if defined(USEFLAC)
loadUserCode(flac_patch,FLAC_PATCHLEN);
#endif
//write_register(SCI_CLOCKF,0xB800); // Experimenting with higher clock settings
write_register(SCI_CLOCKF,0x6000);
delay(1);
@ -259,17 +252,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 +273,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 +337,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,29 @@
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.
01 July 2015 - Added a Flac decoder patch.
*/
//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
//#define USEFLAC
#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 +40,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 +90,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 +128,12 @@ public:
* (see fdevopen() in avr/io.h).
*/
void printDetails(void) const;
/**
*
*
*/
void modeSwitch(void);
/**
* Set the player volume

File diff suppressed because it is too large Load Diff

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

View File

@ -40,11 +40,19 @@
uint8 HardWire::process() {
int8 res = i2c_master_xfer(sel_hard, &itc_msg, 1, 0);
if (res != 0) {
if (res == I2C_ERROR_PROTOCOL) {
if (sel_hard->error_flags & I2C_SR1_AF) { /* NACK */
res = (sel_hard->error_flags & I2C_SR1_ADDR ? ENACKADDR :
ENACKTRNS);
} else if (sel_hard->error_flags & I2C_SR1_OVR) { /* Over/Underrun */
res = EDATA;
} else { /* Bus or Arbitration error */
res = EOTHER;
}
i2c_disable(sel_hard);
i2c_master_enable(sel_hard, (I2C_BUS_RESET | dev_flags));
}
return 0;
return res;
}
// TODO: Add in Error Handling if devsel is out of range for other Maples
@ -56,7 +64,7 @@ HardWire::HardWire(uint8 dev_sel, uint8 flags) {
} else {
ASSERT(1);
}
dev_flags=flags;
dev_flags = flags;
}
HardWire::~HardWire() {

View File

@ -67,5 +67,5 @@ public:
void begin(uint8 = 0x00);
};
extern HardWire HWire;
#endif // _HARDWIRE_H_

View File

@ -191,4 +191,4 @@ TwoWire::~TwoWire() {
// Declare the instance that the users of the library can use
//TwoWire Wire(SCL, SDA, SOFT_STANDARD);
TwoWire Wire(PB6, PB7, SOFT_FAST);
TwoWire Wire(PB6, PB7, SOFT_STANDARD);

View File

@ -50,7 +50,7 @@
#define SDA 19
#define SCL 20
#define SOFT_STANDARD 16
#define SOFT_STANDARD 27
#define SOFT_FAST 0

View File

@ -61,11 +61,10 @@ void WireBase::beginTransmission(int slave_address) {
uint8 WireBase::endTransmission(void) {
uint8 retVal;
if (tx_buf_overflow) {
if (tx_buf_overflow) {
return EDATA;
}
retVal=process();// Changed so that the return value from process is returned by this function see also the return line below
retVal = process();// Changed so that the return value from process is returned by this function see also the return line below
tx_buf_idx = 0;
tx_buf_overflow = false;
return retVal;//SUCCESS;

View File

@ -0,0 +1,76 @@
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
// Version 6, August 1, 2015
// Modified to support HardWire for STM32duino
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <HardWire.h>
HardWire HWire(1, I2C_FAST_MODE); // I2c1
void setup() {
Serial.begin(115200);
HWire.begin();
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
HWire.beginTransmission(address);
error = HWire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
nDevices++;
}
else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found");
else
Serial.println("done");
delay(5000); // wait 5 seconds for next scan
}

View File

@ -0,0 +1,74 @@
// --------------------------------------
// i2c_scanner
//
// Version 1
// This program (or code that looks like it)
// can be found in many places.
// For example on the Arduino.cc forum.
// The original author is not know.
// Version 2, Juni 2012, Using Arduino 1.0.1
// Adapted to be as simple as possible by Arduino.cc user Krodal
// Version 3, Feb 26 2013
// V3 by louarnold
// Version 4, March 3, 2013, Using Arduino 1.0.3
// by Arduino.cc user Krodal.
// Changes by louarnold removed.
// Scanning addresses changed from 0...127 to 1...119,
// according to the i2c scanner by Nick Gammon
// http://www.gammon.com.au/forum/?id=10896
// Version 5, March 28, 2013
// As version 4, but address scans now to 127.
// A sensor seems to use address 120.
//
// This sketch tests the standard 7-bit addresses
// Devices with higher bit address might not be seen properly.
//
#include <Wire.h>
void setup() {
Serial.begin(115200);
Wire.begin();
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++) {
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
nDevices++;
}
else if (error == 4) {
Serial.print("Unknown error at address 0x");
if (address < 16)
Serial.print("0");
Serial.println(address, HEX);
}
}
if (nDevices == 0)
Serial.println("No I2C devices found");
else
Serial.println("done");
delay(5000); // wait 5 seconds for next scan
}

View File

@ -3,7 +3,7 @@
# For more info:
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
name=STM32 Boards (stm32duino)
name=STM32 Boards (STM32duino.com)
version=0.1.2
compiler.warning_flags=-w -DDEBUG_LEVEL=DEBUG_NONE
@ -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

@ -255,7 +255,7 @@ extern timer_dev *TIMER14;
#define TIMER_SMCR_ETPS_DIV8 (0x3 << 12)
#define TIMER_SMCR_ETF (0xF << 12)
#define TIMER_SMCR_MSM (1U << TIMER_SMCR_MSM_BIT)
#define TIMER_SMCR_TS (0x3 << 4)
#define TIMER_SMCR_TS (0x7 << 4)
#define TIMER_SMCR_TS_ITR0 (0x0 << 4)
#define TIMER_SMCR_TS_ITR1 (0x1 << 4)
#define TIMER_SMCR_TS_ITR2 (0x2 << 4)
@ -264,7 +264,7 @@ extern timer_dev *TIMER14;
#define TIMER_SMCR_TS_TI1FP1 (0x5 << 4)
#define TIMER_SMCR_TS_TI2FP2 (0x6 << 4)
#define TIMER_SMCR_TS_ETRF (0x7 << 4)
#define TIMER_SMCR_SMS 0x3
#define TIMER_SMCR_SMS 0x7
#define TIMER_SMCR_SMS_DISABLED 0x0
#define TIMER_SMCR_SMS_ENCODER1 0x1
#define TIMER_SMCR_SMS_ENCODER2 0x2

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>
@ -52,13 +56,13 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
{GPIOA, TIMER2, ADC1, 0, 1, 0}, /* PA0 */
{GPIOA, TIMER2, ADC1, 1, 2, 1}, /* PA1 */
{GPIOA, TIMER2, ADC1, 1, 2, 1}, /* PA1 */
{GPIOA, TIMER2, ADC1, 2, 3, 2}, /* PA2 */
{GPIOA, TIMER2, ADC1, 3, 4, 3}, /* PA3 */
{GPIOA, NULL, ADC1, 4, 0, 4}, /* PA4 */
{GPIOA, NULL, ADC1, 5, 0, 5}, /* PA5 */
{GPIOA, TIMER3, ADC1, 6, 1, 6}, /* PA6 */
{GPIOA, TIMER3, ADC1, 7, 2, 7}, /* PA7 */
{GPIOA, NULL, ADC1, 4, 0, 4}, /* PA4 */
{GPIOA, NULL, ADC1, 5, 0, 5}, /* PA5 */
{GPIOA, TIMER3, ADC1, 6, 1, 6}, /* PA6 */
{GPIOA, TIMER3, ADC1, 7, 2, 7}, /* PA7 */
{GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* PA8 */
{GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* PA9 */
{GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* PA10 */
@ -77,7 +81,7 @@ extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
{GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* PB6 */
{GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* PB7 */
{GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* PB8 */
{GPIOB, NULL, NULL, 9, 0, ADCx}, /* PB9 */
{GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* PB9 */
{GPIOB, NULL, NULL, 10, 0, ADCx}, /* PB10 */
{GPIOB, NULL, NULL, 11, 0, ADCx}, /* PB11 */
{GPIOB, NULL, NULL, 12, 0, ADCx}, /* PB12 */
@ -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

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RE boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 504K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RB boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,17 @@
/*
* Linker script for Generic STM32F103RB boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RC boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 256K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RC boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 48K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 248K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -1,23 +1,5 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
* Linker script for Generic STM32F103RE boards.
*/
MEMORY
{

View File

@ -0,0 +1,157 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 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 wirish/boards/maple_mini/board.cpp
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Maple Mini board file.
*/
#include <board/board.h>
#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>
/* Since we want the Serial Wire/JTAG pins as GPIOs, disable both SW
* and JTAG debug support, unless configured otherwise. */
void boardInit(void) {
#ifndef CONFIG_MAPLE_MINI_NO_DISABLE_DEBUG
disableDebugPorts();
#endif
}
// Note. See the enum of pin names in board.h
extern const stm32_pin_info PIN_MAP[BOARD_NR_GPIO_PINS] = {
{GPIOA, TIMER2, ADC1, 0, 1, 0}, /* PA0 */
{GPIOA, TIMER2, ADC1, 1, 2, 1}, /* PA1 */
{GPIOA, TIMER2, ADC1, 2, 3, 2}, /* PA2 */
{GPIOA, TIMER2, ADC1, 3, 4, 3}, /* PA3 */
{GPIOA, NULL, ADC1, 4, 0, 4}, /* PA4 */
{GPIOA, NULL, ADC1, 5, 0, 5}, /* PA5 */
{GPIOA, TIMER3, ADC1, 6, 1, 6}, /* PA6 */
{GPIOA, TIMER3, ADC1, 7, 2, 7}, /* PA7 */
{GPIOA, TIMER1, NULL, 8, 1, ADCx}, /* PA8 */
{GPIOA, TIMER1, NULL, 9, 2, ADCx}, /* PA9 */
{GPIOA, TIMER1, NULL, 10, 3, ADCx}, /* PA10 */
{GPIOA, TIMER1, NULL, 11, 4, ADCx}, /* PA11 */
{GPIOA, NULL, NULL, 12, 0, ADCx}, /* PA12 */
{GPIOA, NULL, NULL, 13, 0, ADCx}, /* PA13 */
{GPIOA, NULL, NULL, 14, 0, ADCx}, /* PA14 */
{GPIOA, NULL, NULL, 15, 0, ADCx}, /* PA15 */
{GPIOB, TIMER3, ADC1, 0, 3, 8}, /* PB0 */
{GPIOB, TIMER3, ADC1, 1, 4, 9}, /* PB1 */
{GPIOB, NULL, NULL, 2, 0, ADCx}, /* PB2 */
{GPIOB, NULL, NULL, 3, 0, ADCx}, /* PB3 */
{GPIOB, NULL, NULL, 4, 0, ADCx}, /* PB4 */
{GPIOB, NULL, NULL, 5, 0, ADCx}, /* PB5 */
{GPIOB, TIMER4, NULL, 6, 1, ADCx}, /* PB6 */
{GPIOB, TIMER4, NULL, 7, 2, ADCx}, /* PB7 */
{GPIOB, TIMER4, NULL, 8, 3, ADCx}, /* PB8 */
{GPIOB, TIMER4, NULL, 9, 4, ADCx}, /* PB9 */
{GPIOB, NULL, NULL, 10, 0, ADCx}, /* PB10 */
{GPIOB, NULL, NULL, 11, 0, ADCx}, /* PB11 */
{GPIOB, NULL, NULL, 12, 0, ADCx}, /* PB12 */
{GPIOB, NULL, NULL, 13, 0, ADCx}, /* PB13 */
{GPIOB, NULL, NULL, 14, 0, ADCx}, /* PB14 */
{GPIOB, NULL, NULL, 15, 0, ADCx}, /* PB15 */
/* Andy Hull - the R8 is similar to the C8 but exposes more GPIO as follows */
{GPIOC, NULL, ADC1, 0, 0, 10}, /* PC0 */
{GPIOC, NULL, ADC1, 1, 0, 11}, /* PC1 */
{GPIOC, NULL, ADC1, 2, 0, 12}, /* PC2 */
{GPIOC, NULL, ADC1, 3, 0, 13}, /* PC3 */
{GPIOC, NULL, ADC1, 4, 0, 14}, /* PC4 */
{GPIOC, NULL, ADC1, 5, 0, 15}, /* PC5 */
{GPIOC, NULL, NULL, 6, 0, ADCx}, /* PC6 */
{GPIOC, NULL, NULL, 7, 0, ADCx}, /* PC7 */
{GPIOC, NULL, NULL, 8, 0, ADCx}, /* PC8 */
{GPIOC, NULL, NULL, 9, 0, ADCx}, /* PC9 */
{GPIOC, NULL, NULL, 10, 0, ADCx}, /* PC10 */
{GPIOC, NULL, NULL, 11, 0, ADCx}, /* PC11 */
{GPIOC, NULL, NULL, 12, 0, ADCx}, /* PC12 */
{GPIOC, NULL, NULL, 13, 0, ADCx}, /* PC13 */
{GPIOC, NULL, NULL, 14, 0, ADCx}, /* PC14 */
{GPIOC, NULL, NULL, 15, 0, ADCx}, /* PC15 */
{GPIOD, NULL, NULL, 2, 0, ADCx}, /* PD2 */
};
extern const uint8 boardPWMPins[BOARD_NR_PWM_PINS] __FLASH__ = {
PB0, PA7, PA6, PA3, PA2, PA1, PA0, PB7, PB6, PA10, PA9, PA8, PC6, PC7, PC8, PC9
};
extern const uint8 boardADCPins[BOARD_NR_ADC_PINS] __FLASH__ = {
PB0, PA7, PA6 , PA5 , PA4 , PA3 , PA2 , PA1 , PA0 , PC0, PC1, PC2, PC3, PC4, PC5
};
// Note. These defines are not really used by generic boards. They are for Maple Serial USB
#define USB_DP PA12
#define USB_DM PA11
// NOte. These definitions are not really used for generic boards, they only relate to boards modified to behave like Maple boards
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

@ -0,0 +1,84 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 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 wirish/boards/maple_mini/include/board/board.h
* @author Marti Bolivar <mbolivar@leaflabs.com>
* @brief Maple Mini board header.
*
* See wirish/boards/maple/include/board/board.h for more information
* on these definitions.
*/
#ifndef _BOARD_GENERIC_STM32F103R8_H_
#define _BOARD_GENERIC_STM32F103R8_H_
#define CYCLES_PER_MICROSECOND 72
#define SYSTICK_RELOAD_VAL 71999 /* takes a cycle to reload */
#define BOARD_NR_USARTS 3
#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_NR_SPI 2
#define BOARD_SPI1_NSS_PIN PA4
#define BOARD_SPI1_MOSI_PIN PA7
#define BOARD_SPI1_MISO_PIN PA6
#define BOARD_SPI1_SCK_PIN PA5
#define BOARD_SPI2_NSS_PIN PB12
#define BOARD_SPI2_MOSI_PIN PB15
#define BOARD_SPI2_MISO_PIN PB14
#define BOARD_SPI2_SCK_PIN PB13
#define BOARD_NR_GPIO_PINS 49
#define BOARD_NR_PWM_PINS 16
#define BOARD_NR_ADC_PINS 15
#define BOARD_NR_USED_PINS 4
#define BOARD_JTMS_SWDIO_PIN 22
#define BOARD_JTCK_SWCLK_PIN 21
#define BOARD_JTDI_PIN 20
#define BOARD_JTDO_PIN 19
#define BOARD_NJTRST_PIN 18
#define BOARD_USB_DISC_DEV GPIOB
#define BOARD_USB_DISC_BIT 10
// Note this needs to match with the PIN_MAP array in board.cpp
enum {
PA0, PA1, PA2, PA3, PA4, PA5, PA6, PA7, PA8, PA9, PA10, PA11, PA12, PA13, PA14, PA15,
PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13, PB14, PB15,
PC0, PC1, PC2, PC3, PC4, PC5, PC6, PC7, PC8, PC9, PC10, PC11, PC12, PC13, PC14, PC15,
PD2
};
#endif

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RE boards, using the generic bootloader (which takes the lower 8k of memory)
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,30 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 120K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,220 @@
/*
* Linker script for libmaple.
*
* Original author "lanchon" from ST forums, with modifications by LeafLabs.
*/
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/*
* Configure other libraries we want in the link.
*
* libgcc, libc, and libm are common across supported toolchains.
* However, some toolchains require additional archives which aren't
* present everywhere (e.g. ARM's gcc-arm-embedded releases).
*
* To hack around this, we let the build system specify additional
* archives by putting the right extra_libs.inc (in a directory under
* toolchains/) in our search path.
*/
GROUP(libgcc.a libc.a libm.a)
INCLUDE extra_libs.inc
/*
* These force the linker to search for vector table symbols.
*
* These symbols vary by STM32 family (and also within families).
* It's up to the build system to configure the link's search path
* properly for the target MCU.
*/
INCLUDE vector_symbols.inc
/* STM32 vector table. */
EXTERN(__stm32_vector_table)
/* C runtime initialization function. */
EXTERN(start_c)
/* main entry point */
EXTERN(main)
/* Initial stack pointer value. */
EXTERN(__msp_init)
PROVIDE(__msp_init = ORIGIN(ram) + LENGTH(ram));
/* Reset vector and chip reset entry point */
EXTERN(__start__)
ENTRY(__start__)
PROVIDE(__exc_reset = __start__);
/* Heap boundaries, for libmaple */
EXTERN(_lm_heap_start);
EXTERN(_lm_heap_end);
SECTIONS
{
.text :
{
__text_start__ = .;
/*
* STM32 vector table. Leave this here. Yes, really.
*/
*(.stm32.interrupt_vector)
/*
* Program code and vague linking
*/
*(.text .text.* .gnu.linkonce.t.*)
*(.plt)
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
*(.ARM.extab* .gnu.linkonce.armextab.*)
*(.gcc_except_table)
*(.eh_frame_hdr)
*(.eh_frame)
. = ALIGN(4);
KEEP(*(.init))
. = ALIGN(4);
__preinit_array_start = .;
KEEP (*(.preinit_array))
__preinit_array_end = .;
. = ALIGN(4);
__init_array_start = .;
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array))
__init_array_end = .;
. = ALIGN(0x4);
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*crtend.o(.ctors))
. = ALIGN(4);
KEEP(*(.fini))
. = ALIGN(4);
__fini_array_start = .;
KEEP (*(.fini_array))
KEEP (*(SORT(.fini_array.*)))
__fini_array_end = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*crtend.o(.dtors))
} > REGION_TEXT
/*
* End of text
*/
.text.align :
{
. = ALIGN(8);
__text_end__ = .;
} > REGION_TEXT
/*
* .ARM.exidx exception unwinding; mandated by ARM's C++ ABI
*/
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > REGION_RODATA
__exidx_end = .;
/*
* .data
*/
.data :
{
__data_start__ = .;
LONG(0)
. = ALIGN(8);
*(.got.plt) *(.got)
*(.data .data.* .gnu.linkonce.d.*)
. = ALIGN(8);
__data_end__ = .;
} > REGION_DATA AT> REGION_RODATA
/*
* Read-only data
*/
.rodata :
{
*(.rodata .rodata.* .gnu.linkonce.r.*)
/* .USER_FLASH: We allow users to allocate into Flash here */
*(.USER_FLASH)
/* ROM image configuration; for C startup */
. = ALIGN(4);
_lm_rom_img_cfgp = .;
LONG(LOADADDR(.data));
/*
* Heap: Linker scripts may choose a custom heap by overriding
* _lm_heap_start and _lm_heap_end. Otherwise, the heap is in
* internal SRAM, beginning after .bss, and growing towards
* the stack.
*
* I'm shoving these here naively; there's probably a cleaner way
* to go about this. [mbolivar]
*/
_lm_heap_start = DEFINED(_lm_heap_start) ? _lm_heap_start : _end;
_lm_heap_end = DEFINED(_lm_heap_end) ? _lm_heap_end : __msp_init;
} > REGION_RODATA
/*
* .bss
*/
.bss :
{
. = ALIGN(8);
__bss_start__ = .;
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN (8);
__bss_end__ = .;
_end = __bss_end__;
} > REGION_BSS
/*
* Debugging sections
*/
.stab 0 (NOLOAD) : { *(.stab) }
.stabstr 0 (NOLOAD) : { *(.stabstr) }
/* 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) }
.note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
.ARM.attributes 0 : { KEEP (*(.ARM.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) }
}

View File

@ -0,0 +1,7 @@
/*
* Extra archives needed by ARM's GCC ARM Embedded arm-none-eabi-
* releases (https://launchpad.net/gcc-arm-embedded/).
*/
/* This is for the provided newlib. */
GROUP(libnosys.a)

View File

@ -0,0 +1,26 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-flash.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,33 @@
/*
* libmaple linker script for "Flash" builds.
*
* A Flash build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but offsets the sections by
* enough space to store the Maple bootloader, which lives in low
* Flash and uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
/*INCLUDE mem-flash.inc*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 44K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -1,36 +1,31 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
rom (rx) : ORIGIN = 0x08002000, LENGTH = 504K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-jtag.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,36 @@
/*
* libmaple linker script for "JTAG" builds.
*
* A "JTAG" build puts .text (and .rodata) in Flash, and
* .data/.bss/heap (of course) in SRAM, but links starting at the
* Flash and SRAM starting addresses (0x08000000 and 0x20000000
* respectively). This will wipe out a Maple bootloader if there's one
* on the board, so only use this if you know what you're doing.
*
* Of course, a "JTAG" build is perfectly usable for upload over SWD,
* the system memory bootloader, etc. The name is just a historical
* artifact.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 108K
}

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}

View File

@ -0,0 +1,5 @@
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
}

View File

@ -0,0 +1,25 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
INCLUDE mem-ram.inc
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,31 @@
/*
* libmaple linker script for RAM builds.
*
* A Flash build puts .text, .rodata, and .data/.bss/heap (of course)
* in SRAM, but offsets the sections by enough space to store the
* Maple bootloader, which uses low memory.
*/
/*
* This pulls in the appropriate MEMORY declaration from the right
* subdirectory of stm32/mem/ (the environment must call ld with the
* right include directory flags to make this happen). Boards can also
* use this file to use any of libmaple's memory-related hooks (like
* where the heap should live).
*/
/*INCLUDE mem-ram.inc*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
rom (rx) : ORIGIN = 0x08005000, LENGTH = 0
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", ram);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", ram);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RB boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 64K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

View File

@ -0,0 +1,18 @@
/*
* Linker script for Generic STM32F103RB boards.
*/
MEMORY
{
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
}
/* Provide memory region aliases for common.inc */
REGION_ALIAS("REGION_TEXT", rom);
REGION_ALIAS("REGION_DATA", ram);
REGION_ALIAS("REGION_BSS", ram);
REGION_ALIAS("REGION_RODATA", rom);
/* Let common.inc handle the real work. */
INCLUDE common.inc

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