diff options
170 files changed, 18495 insertions, 279 deletions
@@ -1,18 +1,23 @@  # See: http://code.google.com/p/arduino/wiki/Platforms +menu.cpu=Processor +  ##############################################################  uno.name=Arduino Uno +uno.upload.tool=avrdude  uno.upload.protocol=arduino  uno.upload.maximum_size=32256  uno.upload.speed=115200 -uno.bootloader.low_fuses=0xff -uno.bootloader.high_fuses=0xde + +uno.bootloader.tool=avrdude +uno.bootloader.low_fuses=0xFF +uno.bootloader.high_fuses=0xDE  uno.bootloader.extended_fuses=0x05 -uno.bootloader.path=optiboot -uno.bootloader.file=optiboot_atmega328.hex  uno.bootloader.unlock_bits=0x3F  uno.bootloader.lock_bits=0x0F +uno.bootloader.file=optiboot/optiboot_atmega328.hex +  uno.build.mcu=atmega328p  uno.build.f_cpu=16000000L  uno.build.core=arduino @@ -20,101 +25,100 @@ uno.build.variant=standard  ############################################################## -atmega328.name=Arduino Duemilanove w/ ATmega328 +atmega328diecimila.name=Arduino Duemilanove or Diecimila -atmega328.upload.protocol=arduino -atmega328.upload.maximum_size=30720 -atmega328.upload.speed=57600 +atmega328diecimila.upload.tool=avrdude +atmega328diecimila.upload.protocol=arduino -atmega328.bootloader.low_fuses=0xFF -atmega328.bootloader.high_fuses=0xDA -atmega328.bootloader.extended_fuses=0x05 -atmega328.bootloader.path=atmega -atmega328.bootloader.file=ATmegaBOOT_168_atmega328.hex -atmega328.bootloader.unlock_bits=0x3F -atmega328.bootloader.lock_bits=0x0F +atmega328diecimila.bootloader.tool=avrdude +atmega328diecimila.bootloader.low_fuses=0xFF +atmega328diecimila.bootloader.unlock_bits=0x3F +atmega328diecimila.bootloader.lock_bits=0x0F -atmega328.build.mcu=atmega328p -atmega328.build.f_cpu=16000000L -atmega328.build.core=arduino -atmega328.build.variant=standard +atmega328diecimila.build.f_cpu=16000000L +atmega328diecimila.build.core=arduino +atmega328diecimila.build.variant=standard -############################################################## +## Arduino Duemilanove or Diecimila w/ ATmega328 +menu.cpu.atmega328diecimila.atmega328=ATmega328 -diecimila.name=Arduino Diecimila or Duemilanove w/ ATmega168 +menu.cpu.atmega328diecimila.atmega328.upload.maximum_size=30720 +menu.cpu.atmega328diecimila.atmega328.upload.speed=57600 -diecimila.upload.protocol=arduino -diecimila.upload.maximum_size=14336 -diecimila.upload.speed=19200 +menu.cpu.atmega328diecimila.atmega328.bootloader.high_fuses=0xDA +menu.cpu.atmega328diecimila.atmega328.bootloader.extended_fuses=0x05 +menu.cpu.atmega328diecimila.atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex -diecimila.bootloader.low_fuses=0xff -diecimila.bootloader.high_fuses=0xdd -diecimila.bootloader.extended_fuses=0x00 -diecimila.bootloader.path=atmega -diecimila.bootloader.file=ATmegaBOOT_168_diecimila.hex -diecimila.bootloader.unlock_bits=0x3F -diecimila.bootloader.lock_bits=0x0F - -diecimila.build.mcu=atmega168 -diecimila.build.f_cpu=16000000L -diecimila.build.core=arduino -diecimila.build.variant=standard - -############################################################## +menu.cpu.atmega328diecimila.atmega328.build.mcu=atmega328p -nano328.name=Arduino Nano w/ ATmega328 +## Arduino Duemilanove or Diecimila w/ ATmega168 +menu.cpu.atmega328diecimila.atmega168=ATmega168 -nano328.upload.protocol=arduino -nano328.upload.maximum_size=30720 -nano328.upload.speed=57600 +menu.cpu.atmega328diecimila.atmega168.upload.maximum_size=14336 +menu.cpu.atmega328diecimila.atmega168.upload.speed=19200 -nano328.bootloader.low_fuses=0xFF -nano328.bootloader.high_fuses=0xDA -nano328.bootloader.extended_fuses=0x05 -nano328.bootloader.path=atmega -nano328.bootloader.file=ATmegaBOOT_168_atmega328.hex -nano328.bootloader.unlock_bits=0x3F -nano328.bootloader.lock_bits=0x0F +menu.cpu.atmega328diecimila.atmega168.bootloader.high_fuses=0xdd +menu.cpu.atmega328diecimila.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.atmega328diecimila.atmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex -nano328.build.mcu=atmega328p -nano328.build.f_cpu=16000000L -nano328.build.core=arduino -nano328.build.variant=eightanaloginputs +menu.cpu.atmega328diecimila.atmega168.build.mcu=atmega168  ############################################################## -nano.name=Arduino Nano w/ ATmega168 +nano.name=Arduino Nano +nano.upload.tool=avrdude  nano.upload.protocol=arduino -nano.upload.maximum_size=14336 -nano.upload.speed=19200 - -nano.bootloader.low_fuses=0xff -nano.bootloader.high_fuses=0xdd -nano.bootloader.extended_fuses=0x00 -nano.bootloader.path=atmega -nano.bootloader.file=ATmegaBOOT_168_diecimila.hex + +nano.bootloader.tool=avrdude  nano.bootloader.unlock_bits=0x3F  nano.bootloader.lock_bits=0x0F -nano.build.mcu=atmega168  nano.build.f_cpu=16000000L  nano.build.core=arduino  nano.build.variant=eightanaloginputs +## Arduino Nano w/ ATmega328 +menu.cpu.nano.atmega328=ATmega328 + +menu.cpu.nano.atmega328.upload.maximum_size=30720 +menu.cpu.nano.atmega328.upload.speed=57600 + +menu.cpu.nano.atmega328.bootloader.low_fuses=0xFF +menu.cpu.nano.atmega328.bootloader.high_fuses=0xDA +menu.cpu.nano.atmega328.bootloader.extended_fuses=0x05 +menu.cpu.nano.atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex + +menu.cpu.nano.atmega328.build.mcu=atmega328p + +## Arduino Nano w/ ATmega168 +menu.cpu.nano.atmega168=ATmega168 + +menu.cpu.nano.atmega168.upload.maximum_size=14336 +menu.cpu.nano.atmega168.upload.speed=19200 + +menu.cpu.nano.atmega168.bootloader.low_fuses=0xff +menu.cpu.nano.atmega168.bootloader.high_fuses=0xdd +menu.cpu.nano.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.nano.atmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex + +menu.cpu.nano.atmega168.build.mcu=atmega168 +  ##############################################################  mega2560.name=Arduino Mega 2560 or Mega ADK +mega2560.cpu=2560 or ADK +mega2560.upload.tool=avrdude  mega2560.upload.protocol=wiring  mega2560.upload.maximum_size=258048  mega2560.upload.speed=115200 +mega2560.bootloader.tool=avrdude  mega2560.bootloader.low_fuses=0xFF  mega2560.bootloader.high_fuses=0xD8  mega2560.bootloader.extended_fuses=0xFD -mega2560.bootloader.path=stk500v2 -mega2560.bootloader.file=stk500boot_v2_mega2560.hex +mega2560.bootloader.file=stk500v2/stk500boot_v2_mega2560.hex  mega2560.bootloader.unlock_bits=0x3F  mega2560.bootloader.lock_bits=0x0F @@ -126,16 +130,18 @@ mega2560.build.variant=mega  ##############################################################  mega.name=Arduino Mega (ATmega1280) +mega.cpu=ATmega1280 +mega.upload.tool=avrdude  mega.upload.protocol=arduino  mega.upload.maximum_size=126976  mega.upload.speed=57600 +mega.bootloader.tool=avrdude  mega.bootloader.low_fuses=0xFF  mega.bootloader.high_fuses=0xDA  mega.bootloader.extended_fuses=0xF5 -mega.bootloader.path=atmega -mega.bootloader.file=ATmegaBOOT_168_atmega1280.hex +mega.bootloader.file=atmega/ATmegaBOOT_168_atmega1280.hex  mega.bootloader.unlock_bits=0x3F  mega.bootloader.lock_bits=0x0F @@ -147,121 +153,138 @@ mega.build.variant=mega  ##############################################################  leonardo.name=Arduino Leonardo +leonardo.upload.tool=avrdude  leonardo.upload.protocol=avr109  leonardo.upload.maximum_size=28672  leonardo.upload.speed=57600  leonardo.upload.disable_flushing=true +leonardo.upload.use_1200bps_touch=true +leonardo.upload.wait_for_upload_port=true + +leonardo.bootloader.tool=avrdude  leonardo.bootloader.low_fuses=0xff  leonardo.bootloader.high_fuses=0xd8  leonardo.bootloader.extended_fuses=0xcb -leonardo.bootloader.path=caterina -leonardo.bootloader.file=Caterina-Leonardo.hex +leonardo.bootloader.file=caterina/Caterina-Leonardo.hex  leonardo.bootloader.unlock_bits=0x3F  leonardo.bootloader.lock_bits=0x2F +  leonardo.build.mcu=atmega32u4  leonardo.build.f_cpu=16000000L  leonardo.build.vid=0x2341  leonardo.build.pid=0x8036  leonardo.build.core=arduino  leonardo.build.variant=leonardo - -############################################################## - -esplora.name=Arduino Esplora -esplora.upload.protocol=avr109 -esplora.upload.maximum_size=28672 -esplora.upload.speed=57600 -esplora.upload.disable_flushing=true -esplora.bootloader.low_fuses=0xff -esplora.bootloader.high_fuses=0xd8 -esplora.bootloader.extended_fuses=0xcb -esplora.bootloader.path=caterina -esplora.bootloader.file=Caterina-Esplora.hex -esplora.bootloader.unlock_bits=0x3F -esplora.bootloader.lock_bits=0x2F -esplora.build.mcu=atmega32u4 -esplora.build.f_cpu=16000000L -esplora.build.vid=0x2341 -esplora.build.pid=0x803C -esplora.build.core=arduino -esplora.build.variant=leonardo +leonardo.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}  ##############################################################  micro.name=Arduino Micro +micro.upload.tool=avrdude  micro.upload.protocol=avr109  micro.upload.maximum_size=28672  micro.upload.speed=57600  micro.upload.disable_flushing=true +micro.upload.use_1200bps_touch=true +micro.upload.wait_for_upload_port=true + +micro.bootloader.tool=avrdude  micro.bootloader.low_fuses=0xff  micro.bootloader.high_fuses=0xd8  micro.bootloader.extended_fuses=0xcb -micro.bootloader.path=caterina -micro.bootloader.file=Caterina-Micro.hex +micro.bootloader.file=caterina/Caterina-Micro.hex  micro.bootloader.unlock_bits=0x3F  micro.bootloader.lock_bits=0x2F +  micro.build.mcu=atmega32u4  micro.build.f_cpu=16000000L  micro.build.vid=0x2341  micro.build.pid=0x8037  micro.build.core=arduino  micro.build.variant=micro +micro.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}  ############################################################## -mini328.name=Arduino Mini w/ ATmega328 - -mini328.upload.protocol=arduino -mini328.upload.maximum_size=28672 -mini328.upload.speed=115200 +esplora.name=Arduino Esplora +esplora.upload.tool=avrdude +esplora.upload.protocol=avr109 +esplora.upload.maximum_size=28672 +esplora.upload.speed=57600 +esplora.upload.disable_flushing=true +esplora.upload.use_1200bps_touch=true +esplora.upload.wait_for_upload_port=true -mini328.bootloader.low_fuses=0xff -mini328.bootloader.high_fuses=0xd8 -mini328.bootloader.extended_fuses=0x05 -mini328.bootloader.path=optiboot -mini328.bootloader.file=optiboot_atmega328-Mini.hex -mini328.bootloader.unlock_bits=0x3F -mini328.bootloader.lock_bits=0x0F +esplora.bootloader.tool=avrdude +esplora.bootloader.low_fuses=0xff +esplora.bootloader.high_fuses=0xd8 +esplora.bootloader.extended_fuses=0xcb +esplora.bootloader.file=caterina/Caterina-Esplora.hex +esplora.bootloader.unlock_bits=0x3F +esplora.bootloader.lock_bits=0x2F -mini328.build.mcu=atmega328p -mini328.build.f_cpu=16000000L -mini328.build.core=arduino -mini328.build.variant=eightanaloginputs +esplora.build.mcu=atmega32u4 +esplora.build.f_cpu=16000000L +esplora.build.vid=0x2341 +esplora.build.pid=0x8036 +esplora.build.core=arduino +esplora.build.variant=leonardo +esplora.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}  ############################################################## -mini.name=Arduino Mini w/ ATmega168 +mini.name=Arduino Mini +mini.upload.tool=avrdude  mini.upload.protocol=arduino -mini.upload.maximum_size=14336 -mini.upload.speed=19200 +mini.bootloader.tool=avrdude  mini.bootloader.low_fuses=0xff -mini.bootloader.high_fuses=0xdd -mini.bootloader.extended_fuses=0x00 -mini.bootloader.path=atmega -mini.bootloader.file=ATmegaBOOT_168_ng.hex  mini.bootloader.unlock_bits=0x3F  mini.bootloader.lock_bits=0x0F -mini.build.mcu=atmega168  mini.build.f_cpu=16000000L  mini.build.core=arduino  mini.build.variant=eightanaloginputs +## Arduino Mini w/ ATmega328 +menu.cpu.mini.atmega328=ATmega328 + +menu.cpu.mini.atmega328.upload.maximum_size=28672 +menu.cpu.mini.atmega328.upload.speed=115200 + +menu.cpu.mini.atmega328.bootloader.high_fuses=0xd8 +menu.cpu.mini.atmega328.bootloader.extended_fuses=0x05 +menu.cpu.mini.atmega328.bootloader.file=optiboot/optiboot_atmega328-Mini.hex + +menu.cpu.mini.atmega328.build.mcu=atmega328p + +## Arduino Mini w/ ATmega168 +menu.cpu.mini.atmega168=ATmega168 + +menu.cpu.mini.atmega168.upload.maximum_size=14336 +menu.cpu.mini.atmega168.upload.speed=19200 + +menu.cpu.mini.atmega168.bootloader.high_fuses=0xdd +menu.cpu.mini.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.mini.atmega168.bootloader.file=atmega/ATmegaBOOT_168_ng.hex + +menu.cpu.mini.atmega168.build.mcu=atmega168 +  ##############################################################  ethernet.name=Arduino Ethernet +ethernet.upload.tool=avrdude  ethernet.upload.protocol=arduino  ethernet.upload.maximum_size=32256  ethernet.upload.speed=115200 +ethernet.bootloader.tool=avrdude  ethernet.bootloader.low_fuses=0xff  ethernet.bootloader.high_fuses=0xde  ethernet.bootloader.extended_fuses=0x05 -ethernet.bootloader.path=optiboot -ethernet.bootloader.file=optiboot_atmega328.hex +ethernet.bootloader.file=optiboot/optiboot_atmega328.hex  ethernet.bootloader.unlock_bits=0x3F  ethernet.bootloader.lock_bits=0x0F @@ -274,15 +297,16 @@ ethernet.build.core=arduino  fio.name=Arduino Fio +fio.upload.tool=avrdude  fio.upload.protocol=arduino  fio.upload.maximum_size=30720  fio.upload.speed=57600 +fio.bootloader.tool=avrdude  fio.bootloader.low_fuses=0xFF  fio.bootloader.high_fuses=0xDA  fio.bootloader.extended_fuses=0x05 -fio.bootloader.path=arduino:atmega -fio.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex +fio.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex  fio.bootloader.unlock_bits=0x3F  fio.bootloader.lock_bits=0x0F @@ -293,232 +317,217 @@ fio.build.variant=eightanaloginputs  ############################################################## -bt328.name=Arduino BT w/ ATmega328 - -bt328.upload.protocol=arduino -bt328.upload.maximum_size=28672 -bt328.upload.speed=19200 -bt328.upload.disable_flushing=true - -bt328.bootloader.low_fuses=0xff -bt328.bootloader.high_fuses=0xd8 -bt328.bootloader.extended_fuses=0x05 -bt328.bootloader.path=bt -bt328.bootloader.file=ATmegaBOOT_168_atmega328_bt.hex -bt328.bootloader.unlock_bits=0x3F -bt328.bootloader.lock_bits=0x0F - -bt328.build.mcu=atmega328p -bt328.build.f_cpu=16000000L -bt328.build.core=arduino -bt328.build.variant=eightanaloginputs - -############################################################## - -bt.name=Arduino BT w/ ATmega168 +bt.name=Arduino BT +bt.upload.tool=avrdude  bt.upload.protocol=arduino -bt.upload.maximum_size=14336  bt.upload.speed=19200  bt.upload.disable_flushing=true +bt.bootloader.tool=avrdude  bt.bootloader.low_fuses=0xff -bt.bootloader.high_fuses=0xdd -bt.bootloader.extended_fuses=0x00 -bt.bootloader.path=bt -bt.bootloader.file=ATmegaBOOT_168.hex  bt.bootloader.unlock_bits=0x3F  bt.bootloader.lock_bits=0x0F -bt.build.mcu=atmega168  bt.build.f_cpu=16000000L  bt.build.core=arduino  bt.build.variant=eightanaloginputs +## Arduino BT w/ ATmega328 +menu.cpu.bt.atmega328=ATmega328 +menu.cpu.bt.atmega328.upload.maximum_size=28672 + +menu.cpu.bt.atmega328.bootloader.high_fuses=0xd8 +menu.cpu.bt.atmega328.bootloader.extended_fuses=0x05 +menu.cpu.bt.atmega328.bootloader.file=bt/ATmegaBOOT_168_atmega328_bt.hex + +menu.cpu.bt.atmega328.build.mcu=atmega328p + +## Arduino BT w/ ATmega168 +menu.cpu.bt.atmega168=ATmega168 +menu.cpu.bt.atmega168.upload.maximum_size=14336 + +menu.cpu.bt.atmega168.bootloader.high_fuses=0xdd +menu.cpu.bt.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.bt.atmega168.bootloader.file=bt/ATmegaBOOT_168.hex + +menu.cpu.bt.atmega168.build.mcu=atmega168 +  ##############################################################  LilyPadUSB.name=LilyPad Arduino USB + +LilyPadUSB.upload.tool=avrdude  LilyPadUSB.upload.protocol=avr109  LilyPadUSB.upload.maximum_size=28672  LilyPadUSB.upload.speed=57600  LilyPadUSB.upload.disable_flushing=true +LilyPadUSB.upload.use_1200bps_touch=true +LilyPadUSB.upload.wait_for_upload_port=true + +LilyPadUSB.bootloader.tool=avrdude  LilyPadUSB.bootloader.low_fuses=0xff  LilyPadUSB.bootloader.high_fuses=0xd8  LilyPadUSB.bootloader.extended_fuses=0xce -LilyPadUSB.bootloader.path=caterina-LilyPadUSB -LilyPadUSB.bootloader.file=Caterina-LilyPadUSB.hex +LilyPadUSB.bootloader.file=caterina-LilyPadUSB/Caterina-LilyPadUSB.hex  LilyPadUSB.bootloader.unlock_bits=0x3F  LilyPadUSB.bootloader.lock_bits=0x2F +  LilyPadUSB.build.mcu=atmega32u4  LilyPadUSB.build.f_cpu=8000000L  LilyPadUSB.build.vid=0x1B4F  LilyPadUSB.build.pid=0x9208  LilyPadUSB.build.core=arduino  LilyPadUSB.build.variant=leonardo +LilyPadUSB.build.extra_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid}  ############################################################## -lilypad328.name=LilyPad Arduino w/ ATmega328 - -lilypad328.upload.protocol=arduino -lilypad328.upload.maximum_size=30720 -lilypad328.upload.speed=57600 - -lilypad328.bootloader.low_fuses=0xFF -lilypad328.bootloader.high_fuses=0xDA -lilypad328.bootloader.extended_fuses=0x05 -lilypad328.bootloader.path=atmega -lilypad328.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex -lilypad328.bootloader.unlock_bits=0x3F -lilypad328.bootloader.lock_bits=0x0F - -lilypad328.build.mcu=atmega328p -lilypad328.build.f_cpu=8000000L -lilypad328.build.core=arduino -lilypad328.build.variant=standard - -############################################################## - -lilypad.name=LilyPad Arduino w/ ATmega168 +lilypad.name=LilyPad Arduino +lilypad.upload.tool=avrdude  lilypad.upload.protocol=arduino -lilypad.upload.maximum_size=14336 -lilypad.upload.speed=19200 - -lilypad.bootloader.low_fuses=0xe2 -lilypad.bootloader.high_fuses=0xdd -lilypad.bootloader.extended_fuses=0x00 -lilypad.bootloader.path=lilypad -lilypad.bootloader.file=LilyPadBOOT_168.hex + +lilypad.bootloader.tool=avrdude  lilypad.bootloader.unlock_bits=0x3F  lilypad.bootloader.lock_bits=0x0F -lilypad.build.mcu=atmega168  lilypad.build.f_cpu=8000000L  lilypad.build.core=arduino  lilypad.build.variant=standard -############################################################## +## LilyPad Arduino w/ ATmega328 +menu.cpu.lilypad.atmega328=ATmega328 + +menu.cpu.lilypad.atmega328.upload.maximum_size=30720 +menu.cpu.lilypad.atmega328.upload.speed=57600 + +menu.cpu.lilypad.atmega328.bootloader.low_fuses=0xFF +menu.cpu.lilypad.atmega328.bootloader.high_fuses=0xDA +menu.cpu.lilypad.atmega328.bootloader.extended_fuses=0x05 +menu.cpu.lilypad.atmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex + +menu.cpu.lilypad.atmega328.build.mcu=atmega328p -pro5v328.name=Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328 +## LilyPad Arduino w/ ATmega168 +menu.cpu.lilypad.atmega168=ATmega168 -pro5v328.upload.protocol=arduino -pro5v328.upload.maximum_size=30720 -pro5v328.upload.speed=57600 +menu.cpu.lilypad.atmega168.upload.maximum_size=14336 +menu.cpu.lilypad.atmega168.upload.speed=19200 -pro5v328.bootloader.low_fuses=0xFF -pro5v328.bootloader.high_fuses=0xDA -pro5v328.bootloader.extended_fuses=0x05 -pro5v328.bootloader.path=atmega -pro5v328.bootloader.file=ATmegaBOOT_168_atmega328.hex -pro5v328.bootloader.unlock_bits=0x3F -pro5v328.bootloader.lock_bits=0x0F +menu.cpu.lilypad.atmega168.bootloader.low_fuses=0xe2 +menu.cpu.lilypad.atmega168.bootloader.high_fuses=0xdd +menu.cpu.lilypad.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.lilypad.atmega168.bootloader.file=lilypad/LilyPadBOOT_168.hex -pro5v328.build.mcu=atmega328p -pro5v328.build.f_cpu=16000000L -pro5v328.build.core=arduino -pro5v328.build.variant=standard +menu.cpu.lilypad.atmega168.build.mcu=atmega168  ############################################################## -pro5v.name=Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega168 +pro.name=Arduino Pro or Pro Mini -pro5v.upload.protocol=arduino -pro5v.upload.maximum_size=14336 -pro5v.upload.speed=19200 +pro.upload.tool=avrdude +pro.upload.protocol=arduino -pro5v.bootloader.low_fuses=0xff -pro5v.bootloader.high_fuses=0xdd -pro5v.bootloader.extended_fuses=0x00 -pro5v.bootloader.path=atmega -pro5v.bootloader.file=ATmegaBOOT_168_diecimila.hex -pro5v.bootloader.unlock_bits=0x3F -pro5v.bootloader.lock_bits=0x0F +pro.bootloader.tool=avrdude +pro.bootloader.unlock_bits=0x3F +pro.bootloader.lock_bits=0x0F -pro5v.build.mcu=atmega168 -pro5v.build.f_cpu=16000000L -pro5v.build.core=arduino -pro5v.build.variant=standard +pro.build.core=arduino +pro.build.variant=standard -############################################################## +## Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328 +menu.cpu.pro.16MHzatmega328=ATmega328 (5V, 16 MHz) -pro328.name=Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega328 +menu.cpu.pro.16MHzatmega328.upload.maximum_size=30720 +menu.cpu.pro.16MHzatmega328.upload.speed=57600 -pro328.upload.protocol=arduino -pro328.upload.maximum_size=30720 -pro328.upload.speed=57600 +menu.cpu.pro.16MHzatmega328.bootloader.low_fuses=0xFF +menu.cpu.pro.16MHzatmega328.bootloader.high_fuses=0xDA +menu.cpu.pro.16MHzatmega328.bootloader.extended_fuses=0x05 +menu.cpu.pro.16MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex -pro328.bootloader.low_fuses=0xFF -pro328.bootloader.high_fuses=0xDA -pro328.bootloader.extended_fuses=0x05 -pro328.bootloader.path=atmega -pro328.bootloader.file=ATmegaBOOT_168_atmega328_pro_8MHz.hex -pro328.bootloader.unlock_bits=0x3F -pro328.bootloader.lock_bits=0x0F +menu.cpu.pro.16MHzatmega328.build.mcu=atmega328p +menu.cpu.pro.16MHzatmega328.build.f_cpu=16000000L -pro328.build.mcu=atmega328p -pro328.build.f_cpu=8000000L -pro328.build.core=arduino -pro328.build.variant=standard +## Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega328 +menu.cpu.pro.8MHzatmega328=ATmega328 (3.3V, 8 MHz) -############################################################## +menu.cpu.pro.8MHzatmega328.upload.maximum_size=30720 +menu.cpu.pro.8MHzatmega328.upload.speed=57600 -pro.name=Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega168 +menu.cpu.pro.8MHzatmega328.bootloader.low_fuses=0xFF +menu.cpu.pro.8MHzatmega328.bootloader.high_fuses=0xDA +menu.cpu.pro.8MHzatmega328.bootloader.extended_fuses=0x05 +menu.cpu.pro.8MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328_pro_8MHz.hex -pro.upload.protocol=arduino -pro.upload.maximum_size=14336 -pro.upload.speed=19200 - -pro.bootloader.low_fuses=0xc6 -pro.bootloader.high_fuses=0xdd -pro.bootloader.extended_fuses=0x00 -pro.bootloader.path=atmega -pro.bootloader.file=ATmegaBOOT_168_pro_8MHz.hex -pro.bootloader.unlock_bits=0x3F -pro.bootloader.lock_bits=0x0F +menu.cpu.pro.8MHzatmega328.build.mcu=atmega328p +menu.cpu.pro.8MHzatmega328.build.f_cpu=8000000L -pro.build.mcu=atmega168 -pro.build.f_cpu=8000000L -pro.build.core=arduino -pro.build.variant=standard +## Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega168 +menu.cpu.pro.16MHzatmega168=ATmega168 (5V, 16 MHz) -############################################################## +menu.cpu.pro.16MHzatmega168.upload.maximum_size=14336 +menu.cpu.pro.16MHzatmega168.upload.speed=19200 + +menu.cpu.pro.16MHzatmega168.bootloader.low_fuses=0xff +menu.cpu.pro.16MHzatmega168.bootloader.high_fuses=0xdd +menu.cpu.pro.16MHzatmega168.bootloader.extended_fuses=0x00 +menu.cpu.pro.16MHzatmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex -atmega168.name=Arduino NG or older w/ ATmega168 +menu.cpu.pro.16MHzatmega168.build.mcu=atmega168 +menu.cpu.pro.16MHzatmega168.build.f_cpu=16000000L -atmega168.upload.protocol=arduino -atmega168.upload.maximum_size=14336 -atmega168.upload.speed=19200 +## Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega168 +menu.cpu.pro.8MHzatmega168=ATmega168 (3.3V, 8 MHz) -atmega168.bootloader.low_fuses=0xff -atmega168.bootloader.high_fuses=0xdd -atmega168.bootloader.extended_fuses=0x00 -atmega168.bootloader.path=atmega -atmega168.bootloader.file=ATmegaBOOT_168_ng.hex -atmega168.bootloader.unlock_bits=0x3F -atmega168.bootloader.lock_bits=0x0F +menu.cpu.pro.8MHzatmega168.upload.maximum_size=14336 +menu.cpu.pro.8MHzatmega168.upload.speed=19200 -atmega168.build.mcu=atmega168 -atmega168.build.f_cpu=16000000L -atmega168.build.core=arduino -atmega168.build.variant=standard +menu.cpu.pro.8MHzatmega168.bootloader.low_fuses=0xc6 +menu.cpu.pro.8MHzatmega168.bootloader.high_fuses=0xdd +menu.cpu.pro.8MHzatmega168.bootloader.extended_fuses=0x00 +menu.cpu.pro.8MHzatmega168.bootloader.file=atmega/ATmegaBOOT_168_pro_8MHz.hex + +menu.cpu.pro.8MHzatmega168.build.mcu=atmega168 +menu.cpu.pro.8MHzatmega168.build.f_cpu=8000000L  ############################################################## -atmega8.name=Arduino NG or older w/ ATmega8 +atmegang.name=Arduino NG or older + +atmegang.upload.tool=avrdude +atmegang.upload.protocol=arduino +atmegang.upload.speed=19200 + +atmegang.bootloader.tool=avrdude +atmegang.bootloader.unlock_bits=0x3F +atmegang.bootloader.lock_bits=0x0F + +atmegang.build.mcu=atmegang +atmegang.build.f_cpu=16000000L +atmegang.build.core=arduino +atmegang.build.variant=standard + +## Arduino NG or older w/ ATmega168 +menu.cpu.atmegang.atmega168=ATmega168 + +menu.cpu.atmegang.atmega168.upload.maximum_size=14336 + +menu.cpu.atmegang.atmega168.bootloader.low_fuses=0xff +menu.cpu.atmegang.atmega168.bootloader.high_fuses=0xdd +menu.cpu.atmegang.atmega168.bootloader.extended_fuses=0x00 +menu.cpu.atmegang.atmega168.bootloader.file=atmega/ATmegaBOOT_168_ng.hex + +menu.cpu.atmegang.atmega168.build.mcu=atmega168 + +## Arduino NG or older w/ ATmega8 +menu.cpu.atmegang.atmega8=ATmega8 -atmega8.upload.protocol=arduino -atmega8.upload.maximum_size=7168 -atmega8.upload.speed=19200 +menu.cpu.atmegang.atmega8.upload.maximum_size=7168 -atmega8.bootloader.low_fuses=0xdf -atmega8.bootloader.high_fuses=0xca -atmega8.bootloader.path=atmega8 -atmega8.bootloader.file=ATmegaBOOT-prod-firmware-2009-11-07.hex -atmega8.bootloader.unlock_bits=0x3F -atmega8.bootloader.lock_bits=0x0F +menu.cpu.atmegang.atmega8.bootloader.low_fuses=0xdf +menu.cpu.atmegang.atmega8.bootloader.high_fuses=0xca +menu.cpu.atmegang.atmega8.bootloader.file=atmega8/ATmegaBOOT-prod-firmware-2009-11-07.hex -atmega8.build.mcu=atmega8 -atmega8.build.f_cpu=16000000L -atmega8.build.core=arduino -atmega8.build.variant=standard +menu.cpu.atmegang.atmega8.build.mcu=atmega8 diff --git a/bootloaders/atmega/ATmegaBOOT_168.c b/bootloaders/atmega/ATmegaBOOT_168.c index 2b9fefa..2b9fefa 100755..100644 --- a/bootloaders/atmega/ATmegaBOOT_168.c +++ b/bootloaders/atmega/ATmegaBOOT_168.c diff --git a/bootloaders/atmega/Makefile b/bootloaders/atmega/Makefile index 0fd54db..0fd54db 100755..100644 --- a/bootloaders/atmega/Makefile +++ b/bootloaders/atmega/Makefile diff --git a/bootloaders/atmega8/ATmegaBOOT.c b/bootloaders/atmega8/ATmegaBOOT.c index 8c8d22a..8c8d22a 100755..100644 --- a/bootloaders/atmega8/ATmegaBOOT.c +++ b/bootloaders/atmega8/ATmegaBOOT.c diff --git a/bootloaders/bt/Makefile b/bootloaders/bt/Makefile index 431f2e7..431f2e7 100755..100644 --- a/bootloaders/bt/Makefile +++ b/bootloaders/bt/Makefile diff --git a/bootloaders/caterina-LilyPadUSB/Caterina.c b/bootloaders/caterina-LilyPadUSB/Caterina.c index 9a59081..9a59081 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Caterina.c +++ b/bootloaders/caterina-LilyPadUSB/Caterina.c diff --git a/bootloaders/caterina-LilyPadUSB/Caterina.h b/bootloaders/caterina-LilyPadUSB/Caterina.h index f8251d4..f8251d4 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Caterina.h +++ b/bootloaders/caterina-LilyPadUSB/Caterina.h diff --git a/bootloaders/caterina-LilyPadUSB/Descriptors.c b/bootloaders/caterina-LilyPadUSB/Descriptors.c index f58519f..f58519f 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Descriptors.c +++ b/bootloaders/caterina-LilyPadUSB/Descriptors.c diff --git a/bootloaders/caterina-LilyPadUSB/Descriptors.h b/bootloaders/caterina-LilyPadUSB/Descriptors.h index 94091ae..94091ae 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Descriptors.h +++ b/bootloaders/caterina-LilyPadUSB/Descriptors.h diff --git a/bootloaders/caterina-LilyPadUSB/Makefile b/bootloaders/caterina-LilyPadUSB/Makefile index 8443e14..8443e14 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Makefile +++ b/bootloaders/caterina-LilyPadUSB/Makefile diff --git a/bootloaders/caterina-LilyPadUSB/Readme.txt b/bootloaders/caterina-LilyPadUSB/Readme.txt index 9656a6e..9656a6e 100755..100644 --- a/bootloaders/caterina-LilyPadUSB/Readme.txt +++ b/bootloaders/caterina-LilyPadUSB/Readme.txt diff --git a/bootloaders/stk500v2/License.txt b/bootloaders/stk500v2/License.txt index e7dcdd8..e7dcdd8 100755..100644 --- a/bootloaders/stk500v2/License.txt +++ b/bootloaders/stk500v2/License.txt diff --git a/bootloaders/stk500v2/Makefile b/bootloaders/stk500v2/Makefile index 54c5f85..54c5f85 100755..100644 --- a/bootloaders/stk500v2/Makefile +++ b/bootloaders/stk500v2/Makefile diff --git a/bootloaders/stk500v2/command.h b/bootloaders/stk500v2/command.h index 03b1b38..03b1b38 100755..100644 --- a/bootloaders/stk500v2/command.h +++ b/bootloaders/stk500v2/command.h diff --git a/bootloaders/stk500v2/stk500boot.c b/bootloaders/stk500v2/stk500boot.c index 13dec89..13dec89 100755..100644 --- a/bootloaders/stk500v2/stk500boot.c +++ b/bootloaders/stk500v2/stk500boot.c diff --git a/cores/arduino/Arduino.h b/cores/arduino/Arduino.h index b265825..02c2a8f 100755..100644 --- a/cores/arduino/Arduino.h +++ b/cores/arduino/Arduino.h @@ -15,6 +15,8 @@  extern "C"{  #endif +void yield(void); +  #define HIGH 0x1  #define LOW  0x0 diff --git a/cores/arduino/Print.cpp b/cores/arduino/Print.cpp index 53961ec..53961ec 100755..100644 --- a/cores/arduino/Print.cpp +++ b/cores/arduino/Print.cpp diff --git a/cores/arduino/Print.h b/cores/arduino/Print.h index dc76150..dc76150 100755..100644 --- a/cores/arduino/Print.h +++ b/cores/arduino/Print.h diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index 9bb6fe7..9bb6fe7 100755..100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp diff --git a/cores/arduino/hooks.c b/cores/arduino/hooks.c new file mode 100644 index 0000000..641eabc --- /dev/null +++ b/cores/arduino/hooks.c @@ -0,0 +1,31 @@ +/* +  Copyright (c) 2012 Arduino.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +  See the GNU Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +/** + * Empty yield() hook. + * + * This function is intended to be used by library writers to build + * libraries or sketches that supports cooperative threads. + * + * Its defined as a weak symbol and it can be redefined to implement a + * real cooperative scheduler. + */ +static void __empty() { +	// Empty +} +void yield(void) __attribute__ ((weak, alias("__empty"))); diff --git a/cores/arduino/wiring.c b/cores/arduino/wiring.c index ac8bb6f..ec5b888 100644 --- a/cores/arduino/wiring.c +++ b/cores/arduino/wiring.c @@ -111,6 +111,7 @@ void delay(unsigned long ms)  	uint16_t start = (uint16_t)micros();  	while (ms > 0) { +		yield();  		if (((uint16_t)micros() - start) >= 1000) {  			ms--;  			start += 1000; diff --git a/cores/arduino/wiring_private.h b/cores/arduino/wiring_private.h index f678265..f678265 100755..100644 --- a/cores/arduino/wiring_private.h +++ b/cores/arduino/wiring_private.h diff --git a/cores/arduino/wiring_pulse.c b/cores/arduino/wiring_pulse.c index 0d96886..0d96886 100755..100644 --- a/cores/arduino/wiring_pulse.c +++ b/cores/arduino/wiring_pulse.c diff --git a/cores/arduino/wiring_shift.c b/cores/arduino/wiring_shift.c index cfe7867..cfe7867 100755..100644 --- a/cores/arduino/wiring_shift.c +++ b/cores/arduino/wiring_shift.c diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.c b/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.c index 7bed831..7bed831 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.c +++ b/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.c diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.h b/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.h index 4fb236e..4fb236e 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.h +++ b/firmwares/atmegaxxu2/arduino-usbdfu/Arduino-usbdfu.h diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/Board/LEDs.h b/firmwares/atmegaxxu2/arduino-usbdfu/Board/LEDs.h index 152e8f5..152e8f5 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/Board/LEDs.h +++ b/firmwares/atmegaxxu2/arduino-usbdfu/Board/LEDs.h diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.c b/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.c index 4deaa06..4deaa06 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.c +++ b/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.c diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.h b/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.h index 6c93f20..6c93f20 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.h +++ b/firmwares/atmegaxxu2/arduino-usbdfu/Descriptors.h diff --git a/firmwares/atmegaxxu2/arduino-usbdfu/makefile b/firmwares/atmegaxxu2/arduino-usbdfu/makefile index 1fb4ed3..1fb4ed3 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbdfu/makefile +++ b/firmwares/atmegaxxu2/arduino-usbdfu/makefile diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.c b/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.c index 4de73c8..4de73c8 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.c +++ b/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.c diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.h b/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.h index 99fde39..99fde39 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.h +++ b/firmwares/atmegaxxu2/arduino-usbserial/Arduino-usbserial.h diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Board/LEDs.h b/firmwares/atmegaxxu2/arduino-usbserial/Board/LEDs.h index 152e8f5..152e8f5 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Board/LEDs.h +++ b/firmwares/atmegaxxu2/arduino-usbserial/Board/LEDs.h diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.c b/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.c index 705dddf..705dddf 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.c +++ b/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.c diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.h b/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.h index 3ac4e52..3ac4e52 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.h +++ b/firmwares/atmegaxxu2/arduino-usbserial/Descriptors.h diff --git a/firmwares/atmegaxxu2/arduino-usbserial/Lib/LightweightRingBuff.h b/firmwares/atmegaxxu2/arduino-usbserial/Lib/LightweightRingBuff.h index fb48c1f..fb48c1f 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/Lib/LightweightRingBuff.h +++ b/firmwares/atmegaxxu2/arduino-usbserial/Lib/LightweightRingBuff.h diff --git a/firmwares/atmegaxxu2/arduino-usbserial/makefile b/firmwares/atmegaxxu2/arduino-usbserial/makefile index 79d6be2..79d6be2 100755..100644 --- a/firmwares/atmegaxxu2/arduino-usbserial/makefile +++ b/firmwares/atmegaxxu2/arduino-usbserial/makefile diff --git a/libraries/EEPROM/EEPROM.cpp b/libraries/EEPROM/EEPROM.cpp new file mode 100644 index 0000000..dfa1deb --- /dev/null +++ b/libraries/EEPROM/EEPROM.cpp @@ -0,0 +1,50 @@ +/* +  EEPROM.cpp - EEPROM library +  Copyright (c) 2006 David A. Mellis.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include <avr/eeprom.h> +#include "Arduino.h" +#include "EEPROM.h" + +/****************************************************************************** + * Definitions + ******************************************************************************/ + +/****************************************************************************** + * Constructors + ******************************************************************************/ + +/****************************************************************************** + * User API + ******************************************************************************/ + +uint8_t EEPROMClass::read(int address) +{ +	return eeprom_read_byte((unsigned char *) address); +} + +void EEPROMClass::write(int address, uint8_t value) +{ +	eeprom_write_byte((unsigned char *) address, value); +} + +EEPROMClass EEPROM; diff --git a/libraries/EEPROM/EEPROM.h b/libraries/EEPROM/EEPROM.h new file mode 100644 index 0000000..aa2b577 --- /dev/null +++ b/libraries/EEPROM/EEPROM.h @@ -0,0 +1,35 @@ +/* +  EEPROM.h - EEPROM library +  Copyright (c) 2006 David A. Mellis.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +#ifndef EEPROM_h +#define EEPROM_h + +#include <inttypes.h> + +class EEPROMClass +{ +  public: +    uint8_t read(int); +    void write(int, uint8_t); +}; + +extern EEPROMClass EEPROM; + +#endif + diff --git a/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino b/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino new file mode 100644 index 0000000..d1e29bd --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_clear/eeprom_clear.ino @@ -0,0 +1,23 @@ +/* + * EEPROM Clear + * + * Sets all of the bytes of the EEPROM to 0. + * This example code is in the public domain. + + */ + +#include <EEPROM.h> + +void setup() +{ +  // write a 0 to all 512 bytes of the EEPROM +  for (int i = 0; i < 512; i++) +    EEPROM.write(i, 0); +     +  // turn the LED on when we're done +  digitalWrite(13, HIGH); +} + +void loop() +{ +} diff --git a/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino b/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino new file mode 100644 index 0000000..0709b2d --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_read/eeprom_read.ino @@ -0,0 +1,43 @@ +/* + * EEPROM Read + * + * Reads the value of each byte of the EEPROM and prints it  + * to the computer. + * This example code is in the public domain. + */ + +#include <EEPROM.h> + +// start reading from the first byte (address 0) of the EEPROM +int address = 0; +byte value; + +void setup() +{ +  // initialize serial and wait for port to open: +  Serial.begin(9600); +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +} + +void loop() +{ +  // read a byte from the current address of the EEPROM +  value = EEPROM.read(address); +   +  Serial.print(address); +  Serial.print("\t"); +  Serial.print(value, DEC); +  Serial.println(); +   +  // advance to the next address of the EEPROM +  address = address + 1; +   +  // there are only 512 bytes of EEPROM, from 0 to 511, so if we're +  // on address 512, wrap around to address 0 +  if (address == 512) +    address = 0; +     +  delay(500); +} diff --git a/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino b/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino new file mode 100644 index 0000000..ae7c57e --- /dev/null +++ b/libraries/EEPROM/examples/eeprom_write/eeprom_write.ino @@ -0,0 +1,38 @@ +/* + * EEPROM Write + * + * Stores values read from analog input 0 into the EEPROM. + * These values will stay in the EEPROM when the board is + * turned off and may be retrieved later by another sketch. + */ + +#include <EEPROM.h> + +// the current address in the EEPROM (i.e. which byte +// we're going to write to next) +int addr = 0; + +void setup() +{ +} + +void loop() +{ +  // need to divide by 4 because analog inputs range from +  // 0 to 1023 and each byte of the EEPROM can only hold a +  // value from 0 to 255. +  int val = analogRead(0) / 4; +   +  // write the value to the appropriate byte of the EEPROM. +  // these values will remain there when the board is +  // turned off. +  EEPROM.write(addr, val); +   +  // advance to the next address.  there are 512 bytes in  +  // the EEPROM, so go back to 0 when we hit 512. +  addr = addr + 1; +  if (addr == 512) +    addr = 0; +   +  delay(100); +} diff --git a/libraries/EEPROM/keywords.txt b/libraries/EEPROM/keywords.txt new file mode 100644 index 0000000..d3218fe --- /dev/null +++ b/libraries/EEPROM/keywords.txt @@ -0,0 +1,18 @@ +####################################### +# Syntax Coloring Map For Ultrasound +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +EEPROM	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Esplora/Esplora.cpp b/libraries/Esplora/Esplora.cpp new file mode 100644 index 0000000..83df0d7 --- /dev/null +++ b/libraries/Esplora/Esplora.cpp @@ -0,0 +1,175 @@ +/* +  Esplora.cpp - Arduino Esplora board library +  Written by Enrico Gueli +  Copyright (c) 2012 Arduino(TM)  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + + +#include "Esplora.h" + +_Esplora Esplora; + +/* + * The following constants tell, for each accelerometer + * axis, which values are returned when the axis measures + * zero acceleration. + */ +const int ACCEL_ZERO_X = 320; +const int ACCEL_ZERO_Y = 330; +const int ACCEL_ZERO_Z = 310; + +const byte MUX_ADDR_PINS[] = { A0, A1, A2, A3 }; +const byte MUX_COM_PIN = A4; + +const int JOYSTICK_DEAD_ZONE = 100; + +const byte RED_PIN    = 5; +const byte BLUE_PIN   = 9; +const byte GREEN_PIN  = 10; + +const byte BUZZER_PIN = 6; + +// non-multiplexer Esplora pins:  +// Accelerometer: x-A5, y-A7, z-A6 +// External outputs: D3, D11 +// Buzzer: A8 +// RGB Led: red-D5, green-D10/A11, blue-D9/A10 +// Led 13: D13 + +const byte ACCEL_X_PIN = A5; +const byte ACCEL_Y_PIN = A11; +const byte ACCEL_Z_PIN = A6; + +const byte LED_PIN     = 13; + +_Esplora::_Esplora() { +  for (byte p=0; p<4; p++) { +    pinMode(MUX_ADDR_PINS[p], OUTPUT); +  } +  pinMode(RED_PIN, OUTPUT); +  pinMode(GREEN_PIN, OUTPUT); +  pinMode(BLUE_PIN, OUTPUT); +} + +unsigned int _Esplora::readChannel(byte channel) { +  digitalWrite(MUX_ADDR_PINS[0], (channel & 1) ? HIGH : LOW); +  digitalWrite(MUX_ADDR_PINS[1], (channel & 2) ? HIGH : LOW); +  digitalWrite(MUX_ADDR_PINS[2], (channel & 4) ? HIGH : LOW); +  digitalWrite(MUX_ADDR_PINS[3], (channel & 8) ? HIGH : LOW); +  // workaround to cope with lack of pullup resistor on joystick switch +  if (channel == CH_JOYSTICK_SW) { +    pinMode(MUX_COM_PIN, INPUT_PULLUP);  +    unsigned int joystickSwitchState = (digitalRead(MUX_COM_PIN) == HIGH) ? 1023 : 0; +    digitalWrite(MUX_COM_PIN, LOW); +    return joystickSwitchState; +  } +  else +    return analogRead(MUX_COM_PIN); +} + +boolean _Esplora::joyLowHalf(byte joyCh) { +  return (readChannel(joyCh) < 512 - JOYSTICK_DEAD_ZONE) +    ? LOW : HIGH; +} + +boolean _Esplora::joyHighHalf(byte joyCh) { +  return (readChannel(joyCh) > 512 + JOYSTICK_DEAD_ZONE) +    ? LOW : HIGH; +} + +boolean _Esplora::readButton(byte ch) { +  if (ch >= SWITCH_1 && ch <= SWITCH_4) { +    ch--; +  } +   +  switch(ch) { +  case JOYSTICK_RIGHT: +    return joyLowHalf(CH_JOYSTICK_X); +  case JOYSTICK_LEFT: +    return joyHighHalf(CH_JOYSTICK_X); +  case JOYSTICK_UP: +    return joyLowHalf(CH_JOYSTICK_Y); +  case JOYSTICK_DOWN: +    return joyHighHalf(CH_JOYSTICK_Y); +  } +     +  unsigned int val = readChannel(ch); +  return (val > 512) ? HIGH : LOW; +} + +void _Esplora::writeRGB(byte r, byte g, byte b) { +  writeRed(r); +  writeGreen(g); +  writeBlue(b); +} + +#define RGB_FUNC(name, pin, lastVar) \ +void _Esplora::write##name(byte val) { \ +  if (val == lastVar) \ +    return; \ +  analogWrite(pin, val);  \ +  lastVar = val; \ +  delay(5); \ +} \ +\ +byte _Esplora::read##name() { \ +  return lastVar; \ +} +   +RGB_FUNC(Red,   RED_PIN,   lastRed) +RGB_FUNC(Green, GREEN_PIN, lastGreen) +RGB_FUNC(Blue,  BLUE_PIN,  lastBlue) + +void _Esplora::tone(unsigned int freq) { +  if (freq > 0) +    ::tone(BUZZER_PIN, freq); +  else +    ::noTone(BUZZER_PIN); +} + +void _Esplora::tone(unsigned int freq, unsigned long duration) { +  if (freq > 0) +    ::tone(BUZZER_PIN, freq, duration); +  else +    ::noTone(BUZZER_PIN); +} + +void _Esplora::noTone() { +  ::noTone(BUZZER_PIN); +} + +int _Esplora::readTemperature(const byte scale) { +  long rawT = readChannel(CH_TEMPERATURE); +  if (scale == DEGREES_C) { +    return (int)((rawT * 500 / 1024) - 50); +  } +  else if (scale == DEGREES_F) { +    return (int)((rawT * 450 / 512 ) - 58); +  } +  else { +    return readTemperature(DEGREES_C); +  } +} + +int _Esplora::readAccelerometer(const byte axis) { +  switch (axis) { +    case X_AXIS: return analogRead(ACCEL_X_PIN) - ACCEL_ZERO_X; +    case Y_AXIS: return analogRead(ACCEL_Y_PIN) - ACCEL_ZERO_Y; +    case Z_AXIS: return analogRead(ACCEL_Z_PIN) - ACCEL_ZERO_Z; +    default: return 0; +  } +} diff --git a/libraries/Esplora/Esplora.h b/libraries/Esplora/Esplora.h new file mode 100644 index 0000000..74fa88b --- /dev/null +++ b/libraries/Esplora/Esplora.h @@ -0,0 +1,163 @@ +/* +  Esplora.h - Arduino Esplora board library +  Written by Enrico Gueli +  Copyright (c) 2012 Arduino(TM)  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +#ifndef ESPLORA_H_ +#define ESPLORA_H_ + +#include "Arduino.h" + +/* + * The following constants are used internally by the Esplora + * library code. + */ + +const byte JOYSTICK_BASE  = 16; // it's a "virtual" channel: its ID won't conflict with real ones + +const byte MAX_CHANNELS   = 13; + +const byte CH_SWITCH_1    = 0; +const byte CH_SWITCH_2    = 1; +const byte CH_SWITCH_3    = 2; +const byte CH_SWITCH_4    = 3; +const byte CH_SLIDER      = 4; +const byte CH_LIGHT       = 5; +const byte CH_TEMPERATURE = 6; +const byte CH_MIC         = 7; +const byte CH_JOYSTICK_SW = 10; +const byte CH_JOYSTICK_X  = 11; +const byte CH_JOYSTICK_Y  = 12; + +/* + * The following constants can be used with the readButton() + * method. + */ + +const byte SWITCH_1       = 1; +const byte SWITCH_2       = 2; +const byte SWITCH_3       = 3; +const byte SWITCH_4       = 4; + +const byte SWITCH_DOWN  = SWITCH_1; +const byte SWITCH_LEFT  = SWITCH_2; +const byte SWITCH_UP    = SWITCH_3; +const byte SWITCH_RIGHT = SWITCH_4; + +const byte JOYSTICK_DOWN  = JOYSTICK_BASE; +const byte JOYSTICK_LEFT  = JOYSTICK_BASE+1; +const byte JOYSTICK_UP    = JOYSTICK_BASE+2; +const byte JOYSTICK_RIGHT = JOYSTICK_BASE+3; + +/* + * These constants can be use for comparison with the value returned + * by the readButton() method. + */ +const boolean PRESSED   = LOW; +const boolean RELEASED  = HIGH; + +/* + * The following constants can be used with the readTemperature() + * method to specify the desired scale. + */ +const byte DEGREES_C = 0; +const byte DEGREES_F = 1; + +/* + * The following constants can be used with the readAccelerometer() + * method to specify the desired axis to return. + */ +const byte X_AXIS = 0; +const byte Y_AXIS = 1; +const byte Z_AXIS = 2; + + +class _Esplora { +private: +  byte lastRed; +  byte lastGreen; +  byte lastBlue; + +  unsigned int readChannel(byte channel);     +   +  boolean joyLowHalf(byte joyCh); +  boolean joyHighHalf(byte joyCh); +     +public: +  _Esplora(); +   +  /* +   * Returns a number corresponding to the position of the +   * linear potentiometer. 0 means full right, 1023 means +   * full left. +   */ +  inline unsigned int readSlider() { return readChannel(CH_SLIDER); } + +  /* +   * Returns a number corresponding to the amount of ambient +   * light sensed by the light sensor. +   */ +  inline unsigned int readLightSensor() { return readChannel(CH_LIGHT); } + +  /* +   * Returns the current ambient temperature, expressed either in Celsius +   * or Fahreneit scale. +   */ +  int readTemperature(const byte scale); + +  /* +   * Returns a number corresponding to the amount of ambient noise. +   */ +  inline unsigned int readMicrophone() { return readChannel(CH_MIC); } +   +  inline unsigned int readJoystickSwitch() { return readChannel(CH_JOYSTICK_SW); } + +  inline int readJoystickX() {  +    return readChannel(CH_JOYSTICK_X) - 512; +  } +  inline int readJoystickY() { +    return readChannel(CH_JOYSTICK_Y) - 512; +  } + +  int readAccelerometer(const byte axis); +   +  /* +   * Reads the current state of a button. It will return +   * LOW if the button is pressed, and HIGH otherwise. +   */ +  boolean readButton(byte channel); +   +  void writeRGB(byte red, byte green, byte blue); +  void writeRed(byte red); +  void writeGreen(byte green); +  void writeBlue(byte blue); + +  byte readRed(); +  byte readGreen(); +  byte readBlue(); +   +  void tone(unsigned int freq); +  void tone(unsigned int freq, unsigned long duration); +  void noTone(); +}; + + + +extern _Esplora Esplora; + +#endif // ESPLORA_H_ diff --git a/libraries/Esplora/examples/EsploraKart/EsploraKart.ino b/libraries/Esplora/examples/EsploraKart/EsploraKart.ino new file mode 100644 index 0000000..4c1621c --- /dev/null +++ b/libraries/Esplora/examples/EsploraKart/EsploraKart.ino @@ -0,0 +1,125 @@ +/* +  Esplora Kart + +  This sketch turns the Esplora into a PC game pad. + +  It uses the both the analog joystick and the four switches. +  By moving the joystick in a direction or by pressing a switch, +  the PC will "see" that a key is pressed. If the PC is running +  a game that has keyboard input, the Esplora can control it. +   +  The default configuration is suitable for SuperTuxKart, an +  open-source racing game. It can be downloaded from +  http://supertuxkart.sourceforge.net/ . + +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +*/ + + +#include <Esplora.h> + +/* +  You're going to handle eight different buttons. You'll use arrays,  +  which are ordered lists of variables with a fixed size. Each array  +  has an index (counting from 0) to keep track of the position +  you're reading in the array, and each position can contain a number. +  +  This code uses three different arrays: one for the buttons you'll read; +  a second to hold the current states of those buttons; and a third to hold +  the keystrokes associated with each button. + */ + +/* +  This array holds the last sensed state of each of the buttons +  you're reading. +  Later in the code, you'll read the button states, and compare them +  to the previous states that are stored in this array. If the two +  states are different, it means that the button was either +  pressed or released. + */ +boolean buttonStates[8]; + +/* +  This array holds the names of the buttons being read. +  Later in the sketch, you'll use these names with +  the method Esplora.readButton(x), where x +  is one of these buttons. + */ +const byte buttons[] = { +  JOYSTICK_DOWN, +  JOYSTICK_LEFT, +  JOYSTICK_UP, +  JOYSTICK_RIGHT, +  SWITCH_RIGHT, // fire +  SWITCH_LEFT, // bend +  SWITCH_UP, // nitro +  SWITCH_DOWN, // look back +}; + +/* +  This array tells what keystroke to send to the PC when a +  button is pressed. +  If you look at this array and the above one, you can see that +  the "cursor down" keystroke is sent when the joystick is moved +  down, the "cursor up" keystroke when the joystick is moved up +  and so on. +*/ +const char keystrokes[] = { +  KEY_DOWN_ARROW, +  KEY_LEFT_ARROW, +  KEY_UP_ARROW, +  KEY_RIGHT_ARROW, +  ' ', +  'V', +  'N', +  'B' +}; + +/* +  This is code is run only at startup, to initialize the +  virtual USB keyboard. +*/ +void setup() { +  Keyboard.begin(); +} + +/* +  After setup() is finished, this code is run continuously. +  Here we continuously check if something happened with the +  buttons. +*/ +void loop() {  +   +  // Iterate through all the buttons: +  for (byte thisButton=0; thisButton<8; thisButton++) { +    boolean lastState = buttonStates[thisButton]; +    boolean newState = Esplora.readButton(buttons[thisButton]); +    if (lastState != newState) { // Something changed! +      /*  +        The Keyboard library allows you to "press" and "release" the +        keys as two distinct actions. These actions can be +        linked to the buttons we're handling. +       */ +      if (newState == PRESSED) { +        Keyboard.press(keystrokes[thisButton]); +      } +      else if (newState == RELEASED) { +        Keyboard.release(keystrokes[thisButton]); +      } +    } + +    // Store the new button state, so you can sense a difference later: +    buttonStates[thisButton] = newState; +  } +   +  /* +    Wait a little bit (50ms) between a check and another. +    When a mechanical switch is pressed or released, the +    contacts may bounce very rapidly. If the check is done too +    fast, these bounces may be confused as multiple presses and +    may lead to unexpected behaviour. +   */ +  delay(50); +} + diff --git a/libraries/Esplora/examples/EsploraLedShow/EsploraLedShow.ino b/libraries/Esplora/examples/EsploraLedShow/EsploraLedShow.ino new file mode 100644 index 0000000..84f049a --- /dev/null +++ b/libraries/Esplora/examples/EsploraLedShow/EsploraLedShow.ino @@ -0,0 +1,42 @@ +/* +  Esplora LED Show + +  Makes the RGB LED bright and glow as the joystick or the +  slider are moved. +   +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +  Modified 24 Nov 2012 +  by Tom Igoe +*/ +#include <Esplora.h> + +void setup() { +  // initialize the serial communication: +  Serial.begin(9600); +} + +void loop() { +  // read the sensors into variables: +  int xAxis = Esplora.readJoystickX(); +  int yAxis = Esplora.readJoystickY(); +  int slider = Esplora.readSlider(); +   +  // convert the sensor readings to light levels: +  byte red   = map(xAxis, -512, 512, 0, 255); +  byte green = map(xAxis, -512, 512, 0, 255); +  byte blue  = slider/4; +  +  // print the light levels: +  Serial.print(red); +  Serial.print(' '); +  Serial.print(green); +  Serial.print(' '); +  Serial.println(blue); + +  // write the light levels to the LED.  +  Esplora.writeRGB(red, green, blue); + +  // add a delay to keep the LED from flickering:   +  delay(10); +} diff --git a/libraries/Esplora/examples/EsploraLedShow2/EsploraLedShow2.ino b/libraries/Esplora/examples/EsploraLedShow2/EsploraLedShow2.ino new file mode 100644 index 0000000..8f9f8a2 --- /dev/null +++ b/libraries/Esplora/examples/EsploraLedShow2/EsploraLedShow2.ino @@ -0,0 +1,55 @@ +/* +  Esplora Led/Microphone + +  This simple sketch reads the microphone, light sensor, and slider. +  Then it uses those readings to set the brightness of red, green and blue +  channels of the RGB LED. The red channel will change with the loudness +  "heared" by the microphone, the green channel changes as the +  amount of light in the room and the blue channel will change +  with the position of the slider. + +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +  Modified 24 Nov 2012 +  by Tom Igoe +*/ + +#include <Esplora.h> + +void setup() { +  // initialize the serial communication: +  Serial.begin(9600); +} + +int lowLight = 400;   // the light sensor reading when it's covered +int highLight = 1023; // the maximum light sensor reading  +int minGreen = 0;     // minimum brightness of the green LED +int maxGreen = 100;   // maximum brightness of the green LED + +void loop() { +  // read the sensors into variables: +  int mic = Esplora.readMicrophone(); +  int light = Esplora.readLightSensor(); +  int slider = Esplora.readSlider(); +   +  // convert the sensor readings to light levels: +  byte red   = constrain(mic, 0, 255); +  byte green = constrain( +                  map(light, lowLight, highLight, minGreen, maxGreen), +                  0, 255); +  byte blue  = slider/4; + +  // print the light levels (to see what's going on): +  Serial.print(red); +  Serial.print(' '); +  Serial.print(green); +  Serial.print(' '); +  Serial.println(blue); + +  // write the light levels to the LED.  +  // note that the green value is always 0: +  Esplora.writeRGB(red, green, blue); +   +  // add a delay to keep the LED from flickering: +  delay(10);  +} diff --git a/libraries/Esplora/examples/EsploraMusic/EsploraMusic.ino b/libraries/Esplora/examples/EsploraMusic/EsploraMusic.ino new file mode 100644 index 0000000..10c17f7 --- /dev/null +++ b/libraries/Esplora/examples/EsploraMusic/EsploraMusic.ino @@ -0,0 +1,52 @@ +/* +  Esplora Music + +  This sketch turns the Esplora in a simple musical instrument. +  Press the Switch 1 and move the slider to see how it works. + +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +  modified 24 Nov 2012 +  by Tom Igoe +*/ + + +#include <Esplora.h> + + +const int note[] = { +262, // C +277, // C# +294, // D +311, // D# +330, // E +349, // F +370, // F# +392, // G +415, // G# +440, // A +466, // A# +494, // B +523  // C next octave +}; + +void setup() { +} + +void loop() { +  // read the button labeled SWITCH_DOWN. If it's low, +  // then play a note: +  if (Esplora.readButton(SWITCH_DOWN) == LOW) { +    int slider = Esplora.readSlider(); +     +    // use map() to map the slider's range to the  +    // range of notes you have: +    byte thisNote = map(slider, 0, 1023, 0, 13); +    // play the note corresponding to the slider's position: +    Esplora.tone(note[thisNote]); +  } +  else { +    // if the button isn't pressed, turn the note off: +    Esplora.noTone(); +  } +} diff --git a/libraries/Esplora/examples/EsploraRemote/EsploraRemote.ino b/libraries/Esplora/examples/EsploraRemote/EsploraRemote.ino new file mode 100644 index 0000000..135b26a --- /dev/null +++ b/libraries/Esplora/examples/EsploraRemote/EsploraRemote.ino @@ -0,0 +1,94 @@ +/* +  Esplora Slave + +  This sketch allows to test all the Esplora's peripherals. +  It is also used with the ProcessingStart sketch (for Processing). +   +  When uploaded, you can open the Serial monitor and write one of +  the following commands (without quotes) to get an answer: +   +  "D": prints the current value of all sensors, separated by a comma. +       See the dumpInputs() function below to get the meaning of +       each value. +        +  "Rxxx" +  "Gxxx" +  "Bxxx": set the color of the RGB led. For example, write "R255" +          to turn on the red to full brightness, "G128" to turn +          the green to half brightness, or "G0" to turn off +          the green channel. +   +  "Txxxx": play a tone with the buzzer. The number is the +           frequency, e.g. "T440" plays the central A note. +           Write "T0" to turn off the buzzer. +   + +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +*/ + +#include <Esplora.h> + +void setup() { +  while(!Serial); // needed for Leonardo-based board like Esplora +  Serial.begin(9600); +} + +void loop() { +  if (Serial.available()) +    parseCommand(); +} + +/* + * This function reads a character from the serial line and + * decide what to do next. The "what to do" part is given by + * function it calls (e.g. dumpInputs(), setRed() and so on). + */ +void parseCommand() { +  char cmd = Serial.read(); +  switch(cmd) { +    case 'D': dumpInputs(); break; +    case 'R': setRed(); break; +    case 'G': setGreen(); break; +    case 'B': setBlue(); break; +    case 'T': setTone(); break; +  } +} + +void dumpInputs() {   +  /* +   * please note: a single row contains two instructions. +   * one is to print the sensor value, the other to print the +   * comma symbol. +   */ +  Serial.print(Esplora.readButton(SWITCH_1)); Serial.print(','); +  Serial.print(Esplora.readButton(SWITCH_2)); Serial.print(','); +  Serial.print(Esplora.readButton(SWITCH_3)); Serial.print(','); +  Serial.print(Esplora.readButton(SWITCH_4)); Serial.print(','); +  Serial.print(Esplora.readSlider());         Serial.print(','); +  Serial.print(Esplora.readLightSensor());    Serial.print(','); +  Serial.print(Esplora.readTemperature(DEGREES_C)); Serial.print(','); +  Serial.print(Esplora.readMicrophone());     Serial.print(','); +  Serial.print(Esplora.readJoystickSwitch()); Serial.print(','); +  Serial.print(Esplora.readJoystickX());      Serial.print(','); +  Serial.print(Esplora.readJoystickY());      Serial.print(','); +  Serial.print(Esplora.readAccelerometer(X_AXIS)); Serial.print(','); +  Serial.print(Esplora.readAccelerometer(Y_AXIS)); Serial.print(','); +  Serial.print(Esplora.readAccelerometer(Z_AXIS)); Serial.println(); +} + +void setRed() { +  Esplora.writeRed(Serial.parseInt()); +} + +void setGreen() { +  Esplora.writeGreen(Serial.parseInt()); +} + +void setBlue() { +  Esplora.writeBlue(Serial.parseInt()); +} + +void setTone() { +  Esplora.tone(Serial.parseInt()); +} diff --git a/libraries/Esplora/examples/EsploraTable/EsploraTable.ino b/libraries/Esplora/examples/EsploraTable/EsploraTable.ino new file mode 100644 index 0000000..712dffa --- /dev/null +++ b/libraries/Esplora/examples/EsploraTable/EsploraTable.ino @@ -0,0 +1,213 @@ +/* +  Esplora Table + +  Acts like a keyboard that prints sensor +  data in a table-like text, row by row. +   +  At startup, it does nothing. It waits for you to open a +  spreadsheet (e.g. Google Drive spreadsheet) so it can write +  data. By pressing Switch 1, it starts printing the table +  headers and the first row of data. It waits a bit, then it +  will print another row, and so on. +   +  The amount of time between each row is determined by the slider. +  If put to full left, the sketch will wait 10 seconds; at +  full right position, it will wait 5 minutes. An intermediate +  position will make the sketch wait for some time in-between. +   +  Clicking the Switch 1 at any time will stop the logging. + +  The color LED shows what the sketch is doing: +  blue  = idle, waiting for you to press Switch 1 to start logging +  green = active; will print soon +  red   = printing data to the PC + +  Created on 22 november 2012 +  By Enrico Gueli <enrico.gueli@gmail.com> +  modified 24 Nov 2012 +  by Tom Igoe +*/ + +#include <Esplora.h> + +/* + * this variable tells if the data-logging is currently active. + */ +boolean active = false; + +/* + * this variable holds the time in the future when the sketch + * will "sample" the data (sampling is the act of reading some + * input at a known time). This variable is checked continuously + * against millis() to know when it's time to sample. + */ +unsigned long nextSampleAt = 0; + +/* + * This variable just holds the millis() value at the time the + * logging was activated. This is needed to enter the correct + * value in the "Time" column in the printed table. + */ +unsigned long startedAt = 0; + + +/* + * when the "active" variable is set to true, the same is done + * with this variable. This is needed because the code that does + * the "just-after-activation" stuff is run some time later than + * the code that says "be active now". + */ +boolean justActivated = false; + + +/* + * this variable holds the last sensed status of the switch press + * button. If the code sees a difference between the value of + * this variable and the current status of the switch, it means + * that the button was either pressed or released. + */ +boolean lastStartBtn = HIGH; + +/* + * Initialization code. The virtual USB keyboard must be + * initialized; the Serial class is needed just for debugging. + */ +void setup() { +  Keyboard.begin(); +  Serial.begin(9600); +} + +/* + * This code is run continuously. + */ +void loop() { +  /* +   * note: we don't use Arduino's delay() here, because we can't +   * normally do anything while delaying. Our own version lets us +   * check for button presses often enough to not miss any event. +   */ +  activeDelay(50); +  +  /* +   * the justActivated variable may be set to true in the +   * checkSwitchPress() function. Here we check its status to +   * print the table headers and configure what's needed to. +   */ +  if (justActivated == true) { +    justActivated = false; // do this just once +    printHeaders(); +    // do next sampling ASAP +    nextSampleAt = startedAt = millis(); +  } +   +  if (active == true) { +    if (nextSampleAt < millis()) { +      // it's time to sample! +      int slider = Esplora.readSlider(); +      // the row below maps the slider position to a range between +      // 10 and 290 seconds. +      int sampleInterval = map(slider, 0, 1023, 10, 290); +      nextSampleAt = millis() + sampleInterval * 1000; +       +      logAndPrint(); +    } +     +    // let the RGB led blink green once per second, for 200ms. +    unsigned int ms = millis() % 1000; +    if (ms < 200) +      Esplora.writeGreen(50); +    else +      Esplora.writeGreen(0); +     +    Esplora.writeBlue(0); +  }  +  else +    // while not active, keep a reassuring blue color coming +    // from the Esplora... +    Esplora.writeBlue(20); +     +} + +/* + * Print the table headers. + */ +void printHeaders() { +  Keyboard.print("Time"); +  Keyboard.write(KEY_TAB); +  activeDelay(300); // Some spreadsheets are slow, e.g. Google +                    // Drive that wants to save every edit. +  Keyboard.print("Accel X"); +  Keyboard.write(KEY_TAB); +  activeDelay(300); +  Keyboard.print("Accel Y"); +  Keyboard.write(KEY_TAB); +  activeDelay(300); +  Keyboard.print("Accel Z"); +  Keyboard.println(); +  activeDelay(300); +} + +void logAndPrint() { +  // do all the samplings at once, because keystrokes have delays +  unsigned long timeSecs = (millis() - startedAt) /1000; +  int xAxis = Esplora.readAccelerometer(X_AXIS); +  int yAxis = Esplora.readAccelerometer(Y_AXIS); +  int zAxis = Esplora.readAccelerometer(Z_AXIS); +   +  Esplora.writeRed(100); +   +  Keyboard.print(timeSecs); +  Keyboard.write(KEY_TAB); +  activeDelay(300); +  Keyboard.print(xAxis); +  Keyboard.write(KEY_TAB); +  activeDelay(300); +  Keyboard.print(yAxis); +  Keyboard.write(KEY_TAB); +  activeDelay(300); +  Keyboard.print(zAxis); +  Keyboard.println(); +  activeDelay(300); +  Keyboard.write(KEY_HOME); +   +  Esplora.writeRed(0); +} + +/** + * Similar to delay(), but allows the program to do something else + * in the meanwhile. In particular, it calls checkSwitchPress(). + * Note 1: it may wait longer than the specified amount, not less; + * Note 2: beware of data synchronization issues, e.g. if the + * activeDelay() function alters some variables used by the + * caller of this function. + */ +void activeDelay(unsigned long amount) { +  unsigned long at = millis() + amount; +  while (millis() < at) { +    checkSwitchPress(); +  } +} + +/* + * This function reads the status of the switch; if it sees that + * it was pressed, toggles the status of the "active" variable. + * If it's set to true, also the justActivated variable is set to + * true, so the loop() function above can do the right things. + * This function should be called as often as possible and do as + * little as possible, because it can be called while another + * function is running. + */ +void checkSwitchPress() { +  boolean startBtn = Esplora.readButton(SWITCH_DOWN); + +  if (startBtn != lastStartBtn) { +    if (startBtn == HIGH) { // button released +      active = !active; +      if (active) +        justActivated = true;     +    } +     +    lastStartBtn = startBtn; +  } +} + diff --git a/libraries/Esplora/keywords.txt b/libraries/Esplora/keywords.txt new file mode 100644 index 0000000..02ba660 --- /dev/null +++ b/libraries/Esplora/keywords.txt @@ -0,0 +1,68 @@ +####################################### +# Syntax Coloring Map For Esplora +#######################################  +# Class +####################################### + +Esplora	KEYWORD3 + +####################################### +# Methods and Functions  +#######################################	 + +begin	KEYWORD2 +readSlider	KEYWORD2 +readLightSensor	KEYWORD2 +readTemperature	KEYWORD2 +readMicrophone	KEYWORD2 +readJoystickSwitch	KEYWORD2 +readJoystickX	KEYWORD2 +readJoystickY	KEYWORD2 +readAccelerometer	KEYWORD2 +readButton	KEYWORD2 +writeRGB	KEYWORD2 +writeRed	KEYWORD2 +writeGreen	KEYWORD2 +writeBlue	KEYWORD2 +readRed	KEYWORD2 +readGreen	KEYWORD2 +readBlue	KEYWORD2 +tone	KEYWORD2 +noTone	KEYWORD2 + + +####################################### +# Constants +####################################### +  +JOYSTICK_BASE	LITERAL1 +MAX_CHANNELS	LITERAL1 +CH_SWITCH_1	LITERAL1 +CH_SWITCH_2	LITERAL1 +CH_SWITCH_3	LITERAL1 +CH_SWITCH_4	LITERAL1 +CH_SLIDER	LITERAL1 +CH_LIGHT	LITERAL1 +CH_TEMPERATURE	LITERAL1 +CH_MIC	LITERAL1 +CH_JOYSTICK_SW	LITERAL1 +CH_JOYSTICK_X	LITERAL1 +CH_JOYSTICK_Y	LITERAL1 +SWITCH_1	LITERAL1 +SWITCH_2	LITERAL1 +SWITCH_3	LITERAL1 +SWITCH_4	LITERAL1 +SWITCH_DOWN	LITERAL1 +SWITCH_LEFT	LITERAL1 +SWITCH_UP	LITERAL1 +SWITCH_RIGHT	LITERAL1 +JOYSTICK_DOWN	LITERAL1 +JOYSTICK_LEFT	LITERAL1 +JOYSTICK_UP	LITERAL1 +PRESSED	LITERAL1 +RELEASED	LITERAL1 +DEGREES_C	LITERAL1 +DEGREES_F	LITERAL1 +X_AXIS	LITERAL1 +Y_AXIS	LITERAL1 +Z_AXIS	LITERAL1 diff --git a/libraries/Ethernet/Dhcp.cpp b/libraries/Ethernet/Dhcp.cpp new file mode 100644 index 0000000..56d5b69 --- /dev/null +++ b/libraries/Ethernet/Dhcp.cpp @@ -0,0 +1,480 @@ +// DHCP Library v0.3 - April 25, 2009
 +// Author: Jordan Terrell - blog.jordanterrell.com
 +
 +#include "w5100.h"
 +
 +#include <string.h>
 +#include <stdlib.h>
 +#include "Dhcp.h"
 +#include "Arduino.h"
 +#include "util.h"
 +
 +int DhcpClass::beginWithDHCP(uint8_t *mac, unsigned long timeout, unsigned long responseTimeout)
 +{
 +    _dhcpLeaseTime=0;
 +    _dhcpT1=0;
 +    _dhcpT2=0;
 +    _lastCheck=0;
 +    _timeout = timeout;
 +    _responseTimeout = responseTimeout;
 +
 +    // zero out _dhcpMacAddr
 +    memset(_dhcpMacAddr, 0, 6); 
 +    reset_DHCP_lease();
 +
 +    memcpy((void*)_dhcpMacAddr, (void*)mac, 6);
 +    _dhcp_state = STATE_DHCP_START;
 +    return request_DHCP_lease();
 +}
 +
 +void DhcpClass::reset_DHCP_lease(){
 +    // zero out _dhcpSubnetMask, _dhcpGatewayIp, _dhcpLocalIp, _dhcpDhcpServerIp, _dhcpDnsServerIp
 +    memset(_dhcpLocalIp, 0, 20);
 +}
 +
 +//return:0 on error, 1 if request is sent and response is received
 +int DhcpClass::request_DHCP_lease(){
 +    
 +    uint8_t messageType = 0;
 +  
 +    
 +  
 +    // Pick an initial transaction ID
 +    _dhcpTransactionId = random(1UL, 2000UL);
 +    _dhcpInitialTransactionId = _dhcpTransactionId;
 +
 +    _dhcpUdpSocket.stop();
 +    if (_dhcpUdpSocket.begin(DHCP_CLIENT_PORT) == 0)
 +    {
 +      // Couldn't get a socket
 +      return 0;
 +    }
 +    
 +    presend_DHCP();
 +    
 +    int result = 0;
 +    
 +    unsigned long startTime = millis();
 +    
 +    while(_dhcp_state != STATE_DHCP_LEASED)
 +    {
 +        if(_dhcp_state == STATE_DHCP_START)
 +        {
 +            _dhcpTransactionId++;
 +            
 +            send_DHCP_MESSAGE(DHCP_DISCOVER, ((millis() - startTime) / 1000));
 +            _dhcp_state = STATE_DHCP_DISCOVER;
 +        }
 +        else if(_dhcp_state == STATE_DHCP_REREQUEST){
 +            _dhcpTransactionId++;
 +            send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime)/1000));
 +            _dhcp_state = STATE_DHCP_REQUEST;
 +        }
 +        else if(_dhcp_state == STATE_DHCP_DISCOVER)
 +        {
 +            uint32_t respId;
 +            messageType = parseDHCPResponse(_responseTimeout, respId);
 +            if(messageType == DHCP_OFFER)
 +            {
 +                // We'll use the transaction ID that the offer came with,
 +                // rather than the one we were up to
 +                _dhcpTransactionId = respId;
 +                send_DHCP_MESSAGE(DHCP_REQUEST, ((millis() - startTime) / 1000));
 +                _dhcp_state = STATE_DHCP_REQUEST;
 +            }
 +        }
 +        else if(_dhcp_state == STATE_DHCP_REQUEST)
 +        {
 +            uint32_t respId;
 +            messageType = parseDHCPResponse(_responseTimeout, respId);
 +            if(messageType == DHCP_ACK)
 +            {
 +                _dhcp_state = STATE_DHCP_LEASED;
 +                result = 1;
 +                //use default lease time if we didn't get it
 +                if(_dhcpLeaseTime == 0){
 +                    _dhcpLeaseTime = DEFAULT_LEASE;
 +                }
 +                //calculate T1 & T2 if we didn't get it
 +                if(_dhcpT1 == 0){
 +                    //T1 should be 50% of _dhcpLeaseTime
 +                    _dhcpT1 = _dhcpLeaseTime >> 1;
 +                }
 +                if(_dhcpT2 == 0){
 +                    //T2 should be 87.5% (7/8ths) of _dhcpLeaseTime
 +                    _dhcpT2 = _dhcpT1 << 1;
 +                }
 +                _renewInSec = _dhcpT1;
 +                _rebindInSec = _dhcpT2;
 +            }
 +            else if(messageType == DHCP_NAK)
 +                _dhcp_state = STATE_DHCP_START;
 +        }
 +        
 +        if(messageType == 255)
 +        {
 +            messageType = 0;
 +            _dhcp_state = STATE_DHCP_START;
 +        }
 +        
 +        if(result != 1 && ((millis() - startTime) > _timeout))
 +            break;
 +    }
 +    
 +    // We're done with the socket now
 +    _dhcpUdpSocket.stop();
 +    _dhcpTransactionId++;
 +
 +    return result;
 +}
 +
 +void DhcpClass::presend_DHCP()
 +{
 +}
 +
 +void DhcpClass::send_DHCP_MESSAGE(uint8_t messageType, uint16_t secondsElapsed)
 +{
 +    uint8_t buffer[32];
 +    memset(buffer, 0, 32);
 +    IPAddress dest_addr( 255, 255, 255, 255 ); // Broadcast address
 +
 +    if (-1 == _dhcpUdpSocket.beginPacket(dest_addr, DHCP_SERVER_PORT))
 +    {
 +        // FIXME Need to return errors
 +        return;
 +    }
 +
 +    buffer[0] = DHCP_BOOTREQUEST;   // op
 +    buffer[1] = DHCP_HTYPE10MB;     // htype
 +    buffer[2] = DHCP_HLENETHERNET;  // hlen
 +    buffer[3] = DHCP_HOPS;          // hops
 +
 +    // xid
 +    unsigned long xid = htonl(_dhcpTransactionId);
 +    memcpy(buffer + 4, &(xid), 4);
 +
 +    // 8, 9 - seconds elapsed
 +    buffer[8] = ((secondsElapsed & 0xff00) >> 8);
 +    buffer[9] = (secondsElapsed & 0x00ff);
 +
 +    // flags
 +    unsigned short flags = htons(DHCP_FLAGSBROADCAST);
 +    memcpy(buffer + 10, &(flags), 2);
 +
 +    // ciaddr: already zeroed
 +    // yiaddr: already zeroed
 +    // siaddr: already zeroed
 +    // giaddr: already zeroed
 +
 +    //put data in W5100 transmit buffer
 +    _dhcpUdpSocket.write(buffer, 28);
 +
 +    memset(buffer, 0, 32); // clear local buffer
 +
 +    memcpy(buffer, _dhcpMacAddr, 6); // chaddr
 +
 +    //put data in W5100 transmit buffer
 +    _dhcpUdpSocket.write(buffer, 16);
 +
 +    memset(buffer, 0, 32); // clear local buffer
 +
 +    // leave zeroed out for sname && file
 +    // put in W5100 transmit buffer x 6 (192 bytes)
 +  
 +    for(int i = 0; i < 6; i++) {
 +        _dhcpUdpSocket.write(buffer, 32);
 +    }
 +  
 +    // OPT - Magic Cookie
 +    buffer[0] = (uint8_t)((MAGIC_COOKIE >> 24)& 0xFF);
 +    buffer[1] = (uint8_t)((MAGIC_COOKIE >> 16)& 0xFF);
 +    buffer[2] = (uint8_t)((MAGIC_COOKIE >> 8)& 0xFF);
 +    buffer[3] = (uint8_t)(MAGIC_COOKIE& 0xFF);
 +
 +    // OPT - message type
 +    buffer[4] = dhcpMessageType;
 +    buffer[5] = 0x01;
 +    buffer[6] = messageType; //DHCP_REQUEST;
 +
 +    // OPT - client identifier
 +    buffer[7] = dhcpClientIdentifier;
 +    buffer[8] = 0x07;
 +    buffer[9] = 0x01;
 +    memcpy(buffer + 10, _dhcpMacAddr, 6);
 +
 +    // OPT - host name
 +    buffer[16] = hostName;
 +    buffer[17] = strlen(HOST_NAME) + 6; // length of hostname + last 3 bytes of mac address
 +    strcpy((char*)&(buffer[18]), HOST_NAME);
 +
 +    printByte((char*)&(buffer[24]), _dhcpMacAddr[3]);
 +    printByte((char*)&(buffer[26]), _dhcpMacAddr[4]);
 +    printByte((char*)&(buffer[28]), _dhcpMacAddr[5]);
 +
 +    //put data in W5100 transmit buffer
 +    _dhcpUdpSocket.write(buffer, 30);
 +
 +    if(messageType == DHCP_REQUEST)
 +    {
 +        buffer[0] = dhcpRequestedIPaddr;
 +        buffer[1] = 0x04;
 +        buffer[2] = _dhcpLocalIp[0];
 +        buffer[3] = _dhcpLocalIp[1];
 +        buffer[4] = _dhcpLocalIp[2];
 +        buffer[5] = _dhcpLocalIp[3];
 +
 +        buffer[6] = dhcpServerIdentifier;
 +        buffer[7] = 0x04;
 +        buffer[8] = _dhcpDhcpServerIp[0];
 +        buffer[9] = _dhcpDhcpServerIp[1];
 +        buffer[10] = _dhcpDhcpServerIp[2];
 +        buffer[11] = _dhcpDhcpServerIp[3];
 +
 +        //put data in W5100 transmit buffer
 +        _dhcpUdpSocket.write(buffer, 12);
 +    }
 +    
 +    buffer[0] = dhcpParamRequest;
 +    buffer[1] = 0x06;
 +    buffer[2] = subnetMask;
 +    buffer[3] = routersOnSubnet;
 +    buffer[4] = dns;
 +    buffer[5] = domainName;
 +    buffer[6] = dhcpT1value;
 +    buffer[7] = dhcpT2value;
 +    buffer[8] = endOption;
 +    
 +    //put data in W5100 transmit buffer
 +    _dhcpUdpSocket.write(buffer, 9);
 +
 +    _dhcpUdpSocket.endPacket();
 +}
 +
 +uint8_t DhcpClass::parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId)
 +{
 +    uint8_t type = 0;
 +    uint8_t opt_len = 0;
 +     
 +    unsigned long startTime = millis();
 +
 +    while(_dhcpUdpSocket.parsePacket() <= 0)
 +    {
 +        if((millis() - startTime) > responseTimeout)
 +        {
 +            return 255;
 +        }
 +        delay(50);
 +    }
 +    // start reading in the packet
 +    RIP_MSG_FIXED fixedMsg;
 +    _dhcpUdpSocket.read((uint8_t*)&fixedMsg, sizeof(RIP_MSG_FIXED));
 +  
 +    if(fixedMsg.op == DHCP_BOOTREPLY && _dhcpUdpSocket.remotePort() == DHCP_SERVER_PORT)
 +    {
 +        transactionId = ntohl(fixedMsg.xid);
 +        if(memcmp(fixedMsg.chaddr, _dhcpMacAddr, 6) != 0 || (transactionId < _dhcpInitialTransactionId) || (transactionId > _dhcpTransactionId))
 +        {
 +            // Need to read the rest of the packet here regardless
 +            _dhcpUdpSocket.flush();
 +            return 0;
 +        }
 +
 +        memcpy(_dhcpLocalIp, fixedMsg.yiaddr, 4);
 +
 +        // Skip to the option part
 +        // Doing this a byte at a time so we don't have to put a big buffer
 +        // on the stack (as we don't have lots of memory lying around)
 +        for (int i =0; i < (240 - (int)sizeof(RIP_MSG_FIXED)); i++)
 +        {
 +            _dhcpUdpSocket.read(); // we don't care about the returned byte
 +        }
 +
 +        while (_dhcpUdpSocket.available() > 0) 
 +        {
 +            switch (_dhcpUdpSocket.read()) 
 +            {
 +                case endOption :
 +                    break;
 +                    
 +                case padOption :
 +                    break;
 +                
 +                case dhcpMessageType :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    type = _dhcpUdpSocket.read();
 +                    break;
 +                
 +                case subnetMask :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read(_dhcpSubnetMask, 4);
 +                    break;
 +                
 +                case routersOnSubnet :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read(_dhcpGatewayIp, 4);
 +                    for (int i = 0; i < opt_len-4; i++)
 +                    {
 +                        _dhcpUdpSocket.read();
 +                    }
 +                    break;
 +                
 +                case dns :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read(_dhcpDnsServerIp, 4);
 +                    for (int i = 0; i < opt_len-4; i++)
 +                    {
 +                        _dhcpUdpSocket.read();
 +                    }
 +                    break;
 +                
 +                case dhcpServerIdentifier :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    if( *((uint32_t*)_dhcpDhcpServerIp) == 0 || 
 +                        IPAddress(_dhcpDhcpServerIp) == _dhcpUdpSocket.remoteIP() )
 +                    {
 +                        _dhcpUdpSocket.read(_dhcpDhcpServerIp, sizeof(_dhcpDhcpServerIp));
 +                    }
 +                    else
 +                    {
 +                        // Skip over the rest of this option
 +                        while (opt_len--)
 +                        {
 +                            _dhcpUdpSocket.read();
 +                        }
 +                    }
 +                    break;
 +
 +                case dhcpT1value : 
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read((uint8_t*)&_dhcpT1, sizeof(_dhcpT1));
 +                    _dhcpT1 = ntohl(_dhcpT1);
 +                    break;
 +
 +                case dhcpT2value : 
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read((uint8_t*)&_dhcpT2, sizeof(_dhcpT2));
 +                    _dhcpT2 = ntohl(_dhcpT2);
 +                    break;
 +
 +                case dhcpIPaddrLeaseTime :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    _dhcpUdpSocket.read((uint8_t*)&_dhcpLeaseTime, sizeof(_dhcpLeaseTime));
 +                    _dhcpLeaseTime = ntohl(_dhcpLeaseTime);
 +                    _renewInSec = _dhcpLeaseTime;
 +                    break;
 +
 +                default :
 +                    opt_len = _dhcpUdpSocket.read();
 +                    // Skip over the rest of this option
 +                    while (opt_len--)
 +                    {
 +                        _dhcpUdpSocket.read();
 +                    }
 +                    break;
 +            }
 +        }
 +    }
 +
 +    // Need to skip to end of the packet regardless here
 +    _dhcpUdpSocket.flush();
 +
 +    return type;
 +}
 +
 +
 +/*
 +    returns:
 +    0/DHCP_CHECK_NONE: nothing happened
 +    1/DHCP_CHECK_RENEW_FAIL: renew failed
 +    2/DHCP_CHECK_RENEW_OK: renew success
 +    3/DHCP_CHECK_REBIND_FAIL: rebind fail
 +    4/DHCP_CHECK_REBIND_OK: rebind success
 +*/
 +int DhcpClass::checkLease(){
 +    //this uses a signed / unsigned trick to deal with millis overflow
 +    unsigned long now = millis();
 +    signed long snow = (long)now;
 +    int rc=DHCP_CHECK_NONE;
 +    if (_lastCheck != 0){
 +        signed long factor;
 +        //calc how many ms past the timeout we are
 +        factor = snow - (long)_secTimeout;
 +        //if on or passed the timeout, reduce the counters
 +        if ( factor >= 0 ){
 +            //next timeout should be now plus 1000 ms minus parts of second in factor
 +            _secTimeout = snow + 1000 - factor % 1000;
 +            //how many seconds late are we, minimum 1
 +            factor = factor / 1000 +1;
 +            
 +            //reduce the counters by that mouch
 +            //if we can assume that the cycle time (factor) is fairly constant
 +            //and if the remainder is less than cycle time * 2 
 +            //do it early instead of late
 +            if(_renewInSec < factor*2 )
 +                _renewInSec = 0;
 +            else
 +                _renewInSec -= factor;
 +            
 +            if(_rebindInSec < factor*2 )
 +                _rebindInSec = 0;
 +            else
 +                _rebindInSec -= factor;
 +        }
 +
 +        //if we have a lease but should renew, do it
 +        if (_dhcp_state == STATE_DHCP_LEASED && _renewInSec <=0){
 +            _dhcp_state = STATE_DHCP_REREQUEST;
 +            rc = 1 + request_DHCP_lease();
 +        }
 +
 +        //if we have a lease or is renewing but should bind, do it
 +        if( (_dhcp_state == STATE_DHCP_LEASED || _dhcp_state == STATE_DHCP_START) && _rebindInSec <=0){
 +            //this should basically restart completely
 +            _dhcp_state = STATE_DHCP_START;
 +            reset_DHCP_lease();
 +            rc = 3 + request_DHCP_lease();
 +        }
 +    }
 +    else{
 +        _secTimeout = snow + 1000;
 +    }
 +
 +    _lastCheck = now;
 +    return rc;
 +}
 +
 +IPAddress DhcpClass::getLocalIp()
 +{
 +    return IPAddress(_dhcpLocalIp);
 +}
 +
 +IPAddress DhcpClass::getSubnetMask()
 +{
 +    return IPAddress(_dhcpSubnetMask);
 +}
 +
 +IPAddress DhcpClass::getGatewayIp()
 +{
 +    return IPAddress(_dhcpGatewayIp);
 +}
 +
 +IPAddress DhcpClass::getDhcpServerIp()
 +{
 +    return IPAddress(_dhcpDhcpServerIp);
 +}
 +
 +IPAddress DhcpClass::getDnsServerIp()
 +{
 +    return IPAddress(_dhcpDnsServerIp);
 +}
 +
 +void DhcpClass::printByte(char * buf, uint8_t n ) {
 +  char *str = &buf[1];
 +  buf[0]='0';
 +  do {
 +    unsigned long m = n;
 +    n /= 16;
 +    char c = m - 16 * n;
 +    *str-- = c < 10 ? c + '0' : c + 'A' - 10;
 +  } while(n);
 +}
 diff --git a/libraries/Ethernet/Dhcp.h b/libraries/Ethernet/Dhcp.h new file mode 100644 index 0000000..4a47936 --- /dev/null +++ b/libraries/Ethernet/Dhcp.h @@ -0,0 +1,178 @@ +// DHCP Library v0.3 - April 25, 2009
 +// Author: Jordan Terrell - blog.jordanterrell.com
 +
 +#ifndef Dhcp_h
 +#define Dhcp_h
 +
 +#include "EthernetUdp.h"
 +
 +/* DHCP state machine. */
 +#define STATE_DHCP_START 0
 +#define	STATE_DHCP_DISCOVER	1
 +#define	STATE_DHCP_REQUEST	2
 +#define	STATE_DHCP_LEASED	3
 +#define	STATE_DHCP_REREQUEST	4
 +#define	STATE_DHCP_RELEASE	5
 +
 +#define DHCP_FLAGSBROADCAST	0x8000
 +
 +/* UDP port numbers for DHCP */
 +#define	DHCP_SERVER_PORT	67	/* from server to client */
 +#define DHCP_CLIENT_PORT	68	/* from client to server */
 +
 +/* DHCP message OP code */
 +#define DHCP_BOOTREQUEST	1
 +#define DHCP_BOOTREPLY		2
 +
 +/* DHCP message type */
 +#define	DHCP_DISCOVER		1
 +#define DHCP_OFFER		  2
 +#define	DHCP_REQUEST		3
 +#define	DHCP_DECLINE		4
 +#define	DHCP_ACK		    5
 +#define DHCP_NAK		    6
 +#define	DHCP_RELEASE		7
 +#define DHCP_INFORM		  8
 +
 +#define DHCP_HTYPE10MB		1
 +#define DHCP_HTYPE100MB		2
 +
 +#define DHCP_HLENETHERNET	6
 +#define DHCP_HOPS		0
 +#define DHCP_SECS		0
 +
 +#define MAGIC_COOKIE		0x63825363
 +#define MAX_DHCP_OPT	16
 +
 +#define HOST_NAME "WIZnet"
 +#define DEFAULT_LEASE	(900) //default lease time in seconds
 +
 +#define DHCP_CHECK_NONE         (0)
 +#define DHCP_CHECK_RENEW_FAIL   (1)
 +#define DHCP_CHECK_RENEW_OK     (2)
 +#define DHCP_CHECK_REBIND_FAIL  (3)
 +#define DHCP_CHECK_REBIND_OK    (4)
 +
 +enum
 +{
 +	padOption		=	0,
 +	subnetMask		=	1,
 +	timerOffset		=	2,
 +	routersOnSubnet		=	3,
 +	/* timeServer		=	4,
 +	nameServer		=	5,*/
 +	dns			=	6,
 +	/*logServer		=	7,
 +	cookieServer		=	8,
 +	lprServer		=	9,
 +	impressServer		=	10,
 +	resourceLocationServer	=	11,*/
 +	hostName		=	12,
 +	/*bootFileSize		=	13,
 +	meritDumpFile		=	14,*/
 +	domainName		=	15,
 +	/*swapServer		=	16,
 +	rootPath		=	17,
 +	extentionsPath		=	18,
 +	IPforwarding		=	19,
 +	nonLocalSourceRouting	=	20,
 +	policyFilter		=	21,
 +	maxDgramReasmSize	=	22,
 +	defaultIPTTL		=	23,
 +	pathMTUagingTimeout	=	24,
 +	pathMTUplateauTable	=	25,
 +	ifMTU			=	26,
 +	allSubnetsLocal		=	27,
 +	broadcastAddr		=	28,
 +	performMaskDiscovery	=	29,
 +	maskSupplier		=	30,
 +	performRouterDiscovery	=	31,
 +	routerSolicitationAddr	=	32,
 +	staticRoute		=	33,
 +	trailerEncapsulation	=	34,
 +	arpCacheTimeout		=	35,
 +	ethernetEncapsulation	=	36,
 +	tcpDefaultTTL		=	37,
 +	tcpKeepaliveInterval	=	38,
 +	tcpKeepaliveGarbage	=	39,
 +	nisDomainName		=	40,
 +	nisServers		=	41,
 +	ntpServers		=	42,
 +	vendorSpecificInfo	=	43,
 +	netBIOSnameServer	=	44,
 +	netBIOSdgramDistServer	=	45,
 +	netBIOSnodeType		=	46,
 +	netBIOSscope		=	47,
 +	xFontServer		=	48,
 +	xDisplayManager		=	49,*/
 +	dhcpRequestedIPaddr	=	50,
 +	dhcpIPaddrLeaseTime	=	51,
 +	/*dhcpOptionOverload	=	52,*/
 +	dhcpMessageType		=	53,
 +	dhcpServerIdentifier	=	54,
 +	dhcpParamRequest	=	55,
 +	/*dhcpMsg			=	56,
 +	dhcpMaxMsgSize		=	57,*/
 +	dhcpT1value		=	58,
 +	dhcpT2value		=	59,
 +	/*dhcpClassIdentifier	=	60,*/
 +	dhcpClientIdentifier	=	61,
 +	endOption		=	255
 +};
 +
 +typedef struct _RIP_MSG_FIXED
 +{
 +	uint8_t  op; 
 +	uint8_t  htype; 
 +	uint8_t  hlen;
 +	uint8_t  hops;
 +	uint32_t xid;
 +	uint16_t secs;
 +	uint16_t flags;
 +	uint8_t  ciaddr[4];
 +	uint8_t  yiaddr[4];
 +	uint8_t  siaddr[4];
 +	uint8_t  giaddr[4];
 +	uint8_t  chaddr[6];
 +}RIP_MSG_FIXED;
 +
 +class DhcpClass {
 +private:
 +  uint32_t _dhcpInitialTransactionId;
 +  uint32_t _dhcpTransactionId;
 +  uint8_t  _dhcpMacAddr[6];
 +  uint8_t  _dhcpLocalIp[4];
 +  uint8_t  _dhcpSubnetMask[4];
 +  uint8_t  _dhcpGatewayIp[4];
 +  uint8_t  _dhcpDhcpServerIp[4];
 +  uint8_t  _dhcpDnsServerIp[4];
 +  uint32_t _dhcpLeaseTime;
 +  uint32_t _dhcpT1, _dhcpT2;
 +  signed long _renewInSec;
 +  signed long _rebindInSec;
 +  signed long _lastCheck;
 +  unsigned long _timeout;
 +  unsigned long _responseTimeout;
 +  unsigned long _secTimeout;
 +  uint8_t _dhcp_state;
 +  EthernetUDP _dhcpUdpSocket;
 +  
 +  int request_DHCP_lease();
 +  void reset_DHCP_lease();
 +  void presend_DHCP();
 +  void send_DHCP_MESSAGE(uint8_t, uint16_t);
 +  void printByte(char *, uint8_t);
 +  
 +  uint8_t parseDHCPResponse(unsigned long responseTimeout, uint32_t& transactionId);
 +public:
 +  IPAddress getLocalIp();
 +  IPAddress getSubnetMask();
 +  IPAddress getGatewayIp();
 +  IPAddress getDhcpServerIp();
 +  IPAddress getDnsServerIp();
 +  
 +  int beginWithDHCP(uint8_t *, unsigned long timeout = 60000, unsigned long responseTimeout = 4000);
 +  int checkLease();
 +};
 +
 +#endif
 diff --git a/libraries/Ethernet/Dns.cpp b/libraries/Ethernet/Dns.cpp new file mode 100644 index 0000000..b3c1a9d --- /dev/null +++ b/libraries/Ethernet/Dns.cpp @@ -0,0 +1,423 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield +// (c) Copyright 2009-2010 MCQN Ltd. +// Released under Apache License, version 2.0 + +#include "w5100.h" +#include "EthernetUdp.h" +#include "util.h" + +#include "Dns.h" +#include <string.h> +//#include <stdlib.h> +#include "Arduino.h" + + +#define SOCKET_NONE	255 +// Various flags and header field values for a DNS message +#define UDP_HEADER_SIZE	8 +#define DNS_HEADER_SIZE	12 +#define TTL_SIZE        4 +#define QUERY_FLAG               (0) +#define RESPONSE_FLAG            (1<<15) +#define QUERY_RESPONSE_MASK      (1<<15) +#define OPCODE_STANDARD_QUERY    (0) +#define OPCODE_INVERSE_QUERY     (1<<11) +#define OPCODE_STATUS_REQUEST    (2<<11) +#define OPCODE_MASK              (15<<11) +#define AUTHORITATIVE_FLAG       (1<<10) +#define TRUNCATION_FLAG          (1<<9) +#define RECURSION_DESIRED_FLAG   (1<<8) +#define RECURSION_AVAILABLE_FLAG (1<<7) +#define RESP_NO_ERROR            (0) +#define RESP_FORMAT_ERROR        (1) +#define RESP_SERVER_FAILURE      (2) +#define RESP_NAME_ERROR          (3) +#define RESP_NOT_IMPLEMENTED     (4) +#define RESP_REFUSED             (5) +#define RESP_MASK                (15) +#define TYPE_A                   (0x0001) +#define CLASS_IN                 (0x0001) +#define LABEL_COMPRESSION_MASK   (0xC0) +// Port number that DNS servers listen on +#define DNS_PORT        53 + +// Possible return codes from ProcessResponse +#define SUCCESS          1 +#define TIMED_OUT        -1 +#define INVALID_SERVER   -2 +#define TRUNCATED        -3 +#define INVALID_RESPONSE -4 + +void DNSClient::begin(const IPAddress& aDNSServer) +{ +    iDNSServer = aDNSServer; +    iRequestId = 0; +} + + +int DNSClient::inet_aton(const char* aIPAddrString, IPAddress& aResult) +{ +    // See if we've been given a valid IP address +    const char* p =aIPAddrString; +    while (*p && +           ( (*p == '.') || (*p >= '0') || (*p <= '9') )) +    { +        p++; +    } + +    if (*p == '\0') +    { +        // It's looking promising, we haven't found any invalid characters +        p = aIPAddrString; +        int segment =0; +        int segmentValue =0; +        while (*p && (segment < 4)) +        { +            if (*p == '.') +            { +                // We've reached the end of a segment +                if (segmentValue > 255) +                { +                    // You can't have IP address segments that don't fit in a byte +                    return 0; +                } +                else +                { +                    aResult[segment] = (byte)segmentValue; +                    segment++; +                    segmentValue = 0; +                } +            } +            else +            { +                // Next digit +                segmentValue = (segmentValue*10)+(*p - '0'); +            } +            p++; +        } +        // We've reached the end of address, but there'll still be the last +        // segment to deal with +        if ((segmentValue > 255) || (segment > 3)) +        { +            // You can't have IP address segments that don't fit in a byte, +            // or more than four segments +            return 0; +        } +        else +        { +            aResult[segment] = (byte)segmentValue; +            return 1; +        } +    } +    else +    { +        return 0; +    } +} + +int DNSClient::getHostByName(const char* aHostname, IPAddress& aResult) +{ +    int ret =0; + +    // See if it's a numeric IP address +    if (inet_aton(aHostname, aResult)) +    { +        // It is, our work here is done +        return 1; +    } + +    // Check we've got a valid DNS server to use +    if (iDNSServer == INADDR_NONE) +    { +        return INVALID_SERVER; +    } +	 +    // Find a socket to use +    if (iUdp.begin(1024+(millis() & 0xF)) == 1) +    { +        // Try up to three times +        int retries = 0; +//        while ((retries < 3) && (ret <= 0)) +        { +            // Send DNS request +            ret = iUdp.beginPacket(iDNSServer, DNS_PORT); +            if (ret != 0) +            { +                // Now output the request data +                ret = BuildRequest(aHostname); +                if (ret != 0) +                { +                    // And finally send the request +                    ret = iUdp.endPacket(); +                    if (ret != 0) +                    { +                        // Now wait for a response +                        int wait_retries = 0; +                        ret = TIMED_OUT; +                        while ((wait_retries < 3) && (ret == TIMED_OUT)) +                        { +                            ret = ProcessResponse(5000, aResult); +                            wait_retries++; +                        } +                    } +                } +            } +            retries++; +        } + +        // We're done with the socket now +        iUdp.stop(); +    } + +    return ret; +} + +uint16_t DNSClient::BuildRequest(const char* aName) +{ +    // Build header +    //                                    1  1  1  1  1  1 +    //      0  1  2  3  4  5  6  7  8  9  0  1  2  3  4  5 +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |                      ID                       | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |QR|   Opcode  |AA|TC|RD|RA|   Z    |   RCODE   | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |                    QDCOUNT                    | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |                    ANCOUNT                    | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |                    NSCOUNT                    | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    //    |                    ARCOUNT                    | +    //    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +    // As we only support one request at a time at present, we can simplify +    // some of this header +    iRequestId = millis(); // generate a random ID +    uint16_t twoByteBuffer; + +    // FIXME We should also check that there's enough space available to write to, rather +    // FIXME than assume there's enough space (as the code does at present) +    iUdp.write((uint8_t*)&iRequestId, sizeof(iRequestId)); + +    twoByteBuffer = htons(QUERY_FLAG | OPCODE_STANDARD_QUERY | RECURSION_DESIRED_FLAG); +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + +    twoByteBuffer = htons(1);  // One question record +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + +    twoByteBuffer = 0;  // Zero answer records +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); +    // and zero additional records +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + +    // Build question +    const char* start =aName; +    const char* end =start; +    uint8_t len; +    // Run through the name being requested +    while (*end) +    { +        // Find out how long this section of the name is +        end = start; +        while (*end && (*end != '.') ) +        { +            end++; +        } + +        if (end-start > 0) +        { +            // Write out the size of this section +            len = end-start; +            iUdp.write(&len, sizeof(len)); +            // And then write out the section +            iUdp.write((uint8_t*)start, end-start); +        } +        start = end+1; +    } + +    // We've got to the end of the question name, so +    // terminate it with a zero-length section +    len = 0; +    iUdp.write(&len, sizeof(len)); +    // Finally the type and class of question +    twoByteBuffer = htons(TYPE_A); +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); + +    twoByteBuffer = htons(CLASS_IN);  // Internet class of question +    iUdp.write((uint8_t*)&twoByteBuffer, sizeof(twoByteBuffer)); +    // Success!  Everything buffered okay +    return 1; +} + + +uint16_t DNSClient::ProcessResponse(uint16_t aTimeout, IPAddress& aAddress) +{ +    uint32_t startTime = millis(); + +    // Wait for a response packet +    while(iUdp.parsePacket() <= 0) +    { +        if((millis() - startTime) > aTimeout) +            return TIMED_OUT; +        delay(50); +    } + +    // We've had a reply! +    // Read the UDP header +    uint8_t header[DNS_HEADER_SIZE]; // Enough space to reuse for the DNS header +    // Check that it's a response from the right server and the right port +    if ( (iDNSServer != iUdp.remoteIP()) ||  +        (iUdp.remotePort() != DNS_PORT) ) +    { +        // It's not from who we expected +        return INVALID_SERVER; +    } + +    // Read through the rest of the response +    if (iUdp.available() < DNS_HEADER_SIZE) +    { +        return TRUNCATED; +    } +    iUdp.read(header, DNS_HEADER_SIZE); + +    uint16_t header_flags = htons(*((uint16_t*)&header[2])); +    // Check that it's a response to this request +    if ( ( iRequestId != (*((uint16_t*)&header[0])) ) || +        ((header_flags & QUERY_RESPONSE_MASK) != (uint16_t)RESPONSE_FLAG) ) +    { +        // Mark the entire packet as read +        iUdp.flush(); +        return INVALID_RESPONSE; +    } +    // Check for any errors in the response (or in our request) +    // although we don't do anything to get round these +    if ( (header_flags & TRUNCATION_FLAG) || (header_flags & RESP_MASK) ) +    { +        // Mark the entire packet as read +        iUdp.flush(); +        return -5; //INVALID_RESPONSE; +    } + +    // And make sure we've got (at least) one answer +    uint16_t answerCount = htons(*((uint16_t*)&header[6])); +    if (answerCount == 0 ) +    { +        // Mark the entire packet as read +        iUdp.flush(); +        return -6; //INVALID_RESPONSE; +    } + +    // Skip over any questions +    for (uint16_t i =0; i < htons(*((uint16_t*)&header[4])); i++) +    { +        // Skip over the name +        uint8_t len; +        do +        { +            iUdp.read(&len, sizeof(len)); +            if (len > 0) +            { +                // Don't need to actually read the data out for the string, just +                // advance ptr to beyond it +                while(len--) +                { +                    iUdp.read(); // we don't care about the returned byte +                } +            } +        } while (len != 0); + +        // Now jump over the type and class +        for (int i =0; i < 4; i++) +        { +            iUdp.read(); // we don't care about the returned byte +        } +    } + +    // Now we're up to the bit we're interested in, the answer +    // There might be more than one answer (although we'll just use the first +    // type A answer) and some authority and additional resource records but +    // we're going to ignore all of them. + +    for (uint16_t i =0; i < answerCount; i++) +    { +        // Skip the name +        uint8_t len; +        do +        { +            iUdp.read(&len, sizeof(len)); +            if ((len & LABEL_COMPRESSION_MASK) == 0) +            { +                // It's just a normal label +                if (len > 0) +                { +                    // And it's got a length +                    // Don't need to actually read the data out for the string, +                    // just advance ptr to beyond it +                    while(len--) +                    { +                        iUdp.read(); // we don't care about the returned byte +                    } +                } +            } +            else +            { +                // This is a pointer to a somewhere else in the message for the +                // rest of the name.  We don't care about the name, and RFC1035 +                // says that a name is either a sequence of labels ended with a +                // 0 length octet or a pointer or a sequence of labels ending in +                // a pointer.  Either way, when we get here we're at the end of +                // the name +                // Skip over the pointer +                iUdp.read(); // we don't care about the returned byte +                // And set len so that we drop out of the name loop +                len = 0; +            } +        } while (len != 0); + +        // Check the type and class +        uint16_t answerType; +        uint16_t answerClass; +        iUdp.read((uint8_t*)&answerType, sizeof(answerType)); +        iUdp.read((uint8_t*)&answerClass, sizeof(answerClass)); + +        // Ignore the Time-To-Live as we don't do any caching +        for (int i =0; i < TTL_SIZE; i++) +        { +            iUdp.read(); // we don't care about the returned byte +        } + +        // And read out the length of this answer +        // Don't need header_flags anymore, so we can reuse it here +        iUdp.read((uint8_t*)&header_flags, sizeof(header_flags)); + +        if ( (htons(answerType) == TYPE_A) && (htons(answerClass) == CLASS_IN) ) +        { +            if (htons(header_flags) != 4) +            { +                // It's a weird size +                // Mark the entire packet as read +                iUdp.flush(); +                return -9;//INVALID_RESPONSE; +            } +            iUdp.read(aAddress.raw_address(), 4); +            return SUCCESS; +        } +        else +        { +            // This isn't an answer type we're after, move onto the next one +            for (uint16_t i =0; i < htons(header_flags); i++) +            { +                iUdp.read(); // we don't care about the returned byte +            } +        } +    } + +    // Mark the entire packet as read +    iUdp.flush(); + +    // If we get here then we haven't found an answer +    return -10;//INVALID_RESPONSE; +} + diff --git a/libraries/Ethernet/Dns.h b/libraries/Ethernet/Dns.h new file mode 100644 index 0000000..6bcb98a --- /dev/null +++ b/libraries/Ethernet/Dns.h @@ -0,0 +1,41 @@ +// Arduino DNS client for WizNet5100-based Ethernet shield
 +// (c) Copyright 2009-2010 MCQN Ltd.
 +// Released under Apache License, version 2.0
 +
 +#ifndef DNSClient_h
 +#define DNSClient_h
 +
 +#include <EthernetUdp.h>
 +
 +class DNSClient
 +{
 +public:
 +    // ctor
 +    void begin(const IPAddress& aDNSServer);
 +
 +    /** Convert a numeric IP address string into a four-byte IP address.
 +        @param aIPAddrString IP address to convert
 +        @param aResult IPAddress structure to store the returned IP address
 +        @result 1 if aIPAddrString was successfully converted to an IP address,
 +                else error code
 +    */
 +    int inet_aton(const char *aIPAddrString, IPAddress& aResult);
 +
 +    /** Resolve the given hostname to an IP address.
 +        @param aHostname Name to be resolved
 +        @param aResult IPAddress structure to store the returned IP address
 +        @result 1 if aIPAddrString was successfully converted to an IP address,
 +                else error code
 +    */
 +    int getHostByName(const char* aHostname, IPAddress& aResult);
 +
 +protected:
 +    uint16_t BuildRequest(const char* aName);
 +    uint16_t ProcessResponse(uint16_t aTimeout, IPAddress& aAddress);
 +
 +    IPAddress iDNSServer;
 +    uint16_t iRequestId;
 +    EthernetUDP iUdp;
 +};
 +
 +#endif
 diff --git a/libraries/Ethernet/Ethernet.cpp b/libraries/Ethernet/Ethernet.cpp new file mode 100644 index 0000000..c31a85f --- /dev/null +++ b/libraries/Ethernet/Ethernet.cpp @@ -0,0 +1,122 @@ +#include "w5100.h" +#include "Ethernet.h" +#include "Dhcp.h" + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +uint8_t EthernetClass::_state[MAX_SOCK_NUM] = {  +  0, 0, 0, 0 }; +uint16_t EthernetClass::_server_port[MAX_SOCK_NUM] = {  +  0, 0, 0, 0 }; + +int EthernetClass::begin(uint8_t *mac_address) +{ +  static DhcpClass s_dhcp; +  _dhcp = &s_dhcp; + + +  // Initialise the basic info +  W5100.init(); +  W5100.setMACAddress(mac_address); +  W5100.setIPAddress(IPAddress(0,0,0,0).raw_address()); + +  // Now try to get our config info from a DHCP server +  int ret = _dhcp->beginWithDHCP(mac_address); +  if(ret == 1) +  { +    // We've successfully found a DHCP server and got our configuration info, so set things +    // accordingly +    W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); +    W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); +    W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); +    _dnsServerAddress = _dhcp->getDnsServerIp(); +  } + +  return ret; +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip) +{ +  // Assume the DNS server will be the machine on the same network as the local IP +  // but with last octet being '1' +  IPAddress dns_server = local_ip; +  dns_server[3] = 1; +  begin(mac_address, local_ip, dns_server); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server) +{ +  // Assume the gateway will be the machine on the same network as the local IP +  // but with last octet being '1' +  IPAddress gateway = local_ip; +  gateway[3] = 1; +  begin(mac_address, local_ip, dns_server, gateway); +} + +void EthernetClass::begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway) +{ +  IPAddress subnet(255, 255, 255, 0); +  begin(mac_address, local_ip, dns_server, gateway, subnet); +} + +void EthernetClass::begin(uint8_t *mac, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet) +{ +  W5100.init(); +  W5100.setMACAddress(mac); +  W5100.setIPAddress(local_ip._address); +  W5100.setGatewayIp(gateway._address); +  W5100.setSubnetMask(subnet._address); +  _dnsServerAddress = dns_server; +} + +int EthernetClass::maintain(){ +  int rc = DHCP_CHECK_NONE; +  if(_dhcp != NULL){ +    //we have a pointer to dhcp, use it +    rc = _dhcp->checkLease(); +    switch ( rc ){ +      case DHCP_CHECK_NONE: +        //nothing done +        break; +      case DHCP_CHECK_RENEW_OK: +      case DHCP_CHECK_REBIND_OK: +        //we might have got a new IP. +        W5100.setIPAddress(_dhcp->getLocalIp().raw_address()); +        W5100.setGatewayIp(_dhcp->getGatewayIp().raw_address()); +        W5100.setSubnetMask(_dhcp->getSubnetMask().raw_address()); +        _dnsServerAddress = _dhcp->getDnsServerIp(); +        break; +      default: +        //this is actually a error, it will retry though +        break; +    } +  } +  return rc; +} + +IPAddress EthernetClass::localIP() +{ +  IPAddress ret; +  W5100.getIPAddress(ret.raw_address()); +  return ret; +} + +IPAddress EthernetClass::subnetMask() +{ +  IPAddress ret; +  W5100.getSubnetMask(ret.raw_address()); +  return ret; +} + +IPAddress EthernetClass::gatewayIP() +{ +  IPAddress ret; +  W5100.getGatewayIp(ret.raw_address()); +  return ret; +} + +IPAddress EthernetClass::dnsServerIP() +{ +  return _dnsServerAddress; +} + +EthernetClass Ethernet; diff --git a/libraries/Ethernet/Ethernet.h b/libraries/Ethernet/Ethernet.h new file mode 100644 index 0000000..2a07ff3 --- /dev/null +++ b/libraries/Ethernet/Ethernet.h @@ -0,0 +1,41 @@ +#ifndef ethernet_h +#define ethernet_h + +#include <inttypes.h> +//#include "w5100.h" +#include "IPAddress.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dhcp.h" + +#define MAX_SOCK_NUM 4 + +class EthernetClass { +private: +  IPAddress _dnsServerAddress; +  DhcpClass* _dhcp; +public: +  static uint8_t _state[MAX_SOCK_NUM]; +  static uint16_t _server_port[MAX_SOCK_NUM]; +  // Initialise the Ethernet shield to use the provided MAC address and gain the rest of the +  // configuration through DHCP. +  // Returns 0 if the DHCP configuration failed, and 1 if it succeeded +  int begin(uint8_t *mac_address); +  void begin(uint8_t *mac_address, IPAddress local_ip); +  void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server); +  void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway); +  void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet); +  int maintain(); + +  IPAddress localIP(); +  IPAddress subnetMask(); +  IPAddress gatewayIP(); +  IPAddress dnsServerIP(); + +  friend class EthernetClient; +  friend class EthernetServer; +}; + +extern EthernetClass Ethernet; + +#endif diff --git a/libraries/Ethernet/EthernetClient.cpp b/libraries/Ethernet/EthernetClient.cpp new file mode 100644 index 0000000..9885efb --- /dev/null +++ b/libraries/Ethernet/EthernetClient.cpp @@ -0,0 +1,165 @@ +#include "w5100.h" +#include "socket.h" + +extern "C" { +  #include "string.h" +} + +#include "Arduino.h" + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" +#include "Dns.h" + +uint16_t EthernetClient::_srcport = 1024; + +EthernetClient::EthernetClient() : _sock(MAX_SOCK_NUM) { +} + +EthernetClient::EthernetClient(uint8_t sock) : _sock(sock) { +} + +int EthernetClient::connect(const char* host, uint16_t port) { +  // Look up the host first +  int ret = 0; +  DNSClient dns; +  IPAddress remote_addr; + +  dns.begin(Ethernet.dnsServerIP()); +  ret = dns.getHostByName(host, remote_addr); +  if (ret == 1) { +    return connect(remote_addr, port); +  } else { +    return ret; +  } +} + +int EthernetClient::connect(IPAddress ip, uint16_t port) { +  if (_sock != MAX_SOCK_NUM) +    return 0; + +  for (int i = 0; i < MAX_SOCK_NUM; i++) { +    uint8_t s = W5100.readSnSR(i); +    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { +      _sock = i; +      break; +    } +  } + +  if (_sock == MAX_SOCK_NUM) +    return 0; + +  _srcport++; +  if (_srcport == 0) _srcport = 1024; +  socket(_sock, SnMR::TCP, _srcport, 0); + +  if (!::connect(_sock, rawIPAddress(ip), port)) { +    _sock = MAX_SOCK_NUM; +    return 0; +  } + +  while (status() != SnSR::ESTABLISHED) { +    delay(1); +    if (status() == SnSR::CLOSED) { +      _sock = MAX_SOCK_NUM; +      return 0; +    } +  } + +  return 1; +} + +size_t EthernetClient::write(uint8_t b) { +  return write(&b, 1); +} + +size_t EthernetClient::write(const uint8_t *buf, size_t size) { +  if (_sock == MAX_SOCK_NUM) { +    setWriteError(); +    return 0; +  } +  if (!send(_sock, buf, size)) { +    setWriteError(); +    return 0; +  } +  return size; +} + +int EthernetClient::available() { +  if (_sock != MAX_SOCK_NUM) +    return W5100.getRXReceivedSize(_sock); +  return 0; +} + +int EthernetClient::read() { +  uint8_t b; +  if ( recv(_sock, &b, 1) > 0 ) +  { +    // recv worked +    return b; +  } +  else +  { +    // No data available +    return -1; +  } +} + +int EthernetClient::read(uint8_t *buf, size_t size) { +  return recv(_sock, buf, size); +} + +int EthernetClient::peek() { +  uint8_t b; +  // Unlike recv, peek doesn't check to see if there's any data available, so we must +  if (!available()) +    return -1; +  ::peek(_sock, &b); +  return b; +} + +void EthernetClient::flush() { +  while (available()) +    read(); +} + +void EthernetClient::stop() { +  if (_sock == MAX_SOCK_NUM) +    return; + +  // attempt to close the connection gracefully (send a FIN to other side) +  disconnect(_sock); +  unsigned long start = millis(); + +  // wait a second for the connection to close +  while (status() != SnSR::CLOSED && millis() - start < 1000) +    delay(1); + +  // if it hasn't closed, close it forcefully +  if (status() != SnSR::CLOSED) +    close(_sock); + +  EthernetClass::_server_port[_sock] = 0; +  _sock = MAX_SOCK_NUM; +} + +uint8_t EthernetClient::connected() { +  if (_sock == MAX_SOCK_NUM) return 0; +   +  uint8_t s = status(); +  return !(s == SnSR::LISTEN || s == SnSR::CLOSED || s == SnSR::FIN_WAIT || +    (s == SnSR::CLOSE_WAIT && !available())); +} + +uint8_t EthernetClient::status() { +  if (_sock == MAX_SOCK_NUM) return SnSR::CLOSED; +  return W5100.readSnSR(_sock); +} + +// the next function allows us to use the client returned by +// EthernetServer::available() as the condition in an if-statement. + +EthernetClient::operator bool() { +  return _sock != MAX_SOCK_NUM; +} diff --git a/libraries/Ethernet/EthernetClient.h b/libraries/Ethernet/EthernetClient.h new file mode 100644 index 0000000..44740fe --- /dev/null +++ b/libraries/Ethernet/EthernetClient.h @@ -0,0 +1,37 @@ +#ifndef ethernetclient_h +#define ethernetclient_h +#include "Arduino.h"	 +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class EthernetClient : public Client { + +public: +  EthernetClient(); +  EthernetClient(uint8_t sock); + +  uint8_t status(); +  virtual int connect(IPAddress ip, uint16_t port); +  virtual int connect(const char *host, uint16_t port); +  virtual size_t write(uint8_t); +  virtual size_t write(const uint8_t *buf, size_t size); +  virtual int available(); +  virtual int read(); +  virtual int read(uint8_t *buf, size_t size); +  virtual int peek(); +  virtual void flush(); +  virtual void stop(); +  virtual uint8_t connected(); +  virtual operator bool(); + +  friend class EthernetServer; +   +  using Print::write; + +private: +  static uint16_t _srcport; +  uint8_t _sock; +}; + +#endif diff --git a/libraries/Ethernet/EthernetServer.cpp b/libraries/Ethernet/EthernetServer.cpp new file mode 100644 index 0000000..0308b92 --- /dev/null +++ b/libraries/Ethernet/EthernetServer.cpp @@ -0,0 +1,91 @@ +#include "w5100.h" +#include "socket.h" +extern "C" { +#include "string.h" +} + +#include "Ethernet.h" +#include "EthernetClient.h" +#include "EthernetServer.h" + +EthernetServer::EthernetServer(uint16_t port) +{ +  _port = port; +} + +void EthernetServer::begin() +{ +  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { +    EthernetClient client(sock); +    if (client.status() == SnSR::CLOSED) { +      socket(sock, SnMR::TCP, _port, 0); +      listen(sock); +      EthernetClass::_server_port[sock] = _port; +      break; +    } +  }   +} + +void EthernetServer::accept() +{ +  int listening = 0; + +  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { +    EthernetClient client(sock); + +    if (EthernetClass::_server_port[sock] == _port) { +      if (client.status() == SnSR::LISTEN) { +        listening = 1; +      }  +      else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) { +        client.stop(); +      } +    }  +  } + +  if (!listening) { +    begin(); +  } +} + +EthernetClient EthernetServer::available() +{ +  accept(); + +  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { +    EthernetClient client(sock); +    if (EthernetClass::_server_port[sock] == _port && +        (client.status() == SnSR::ESTABLISHED || +         client.status() == SnSR::CLOSE_WAIT)) { +      if (client.available()) { +        // XXX: don't always pick the lowest numbered socket. +        return client; +      } +    } +  } + +  return EthernetClient(MAX_SOCK_NUM); +} + +size_t EthernetServer::write(uint8_t b)  +{ +  return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size)  +{ +  size_t n = 0; +   +  accept(); + +  for (int sock = 0; sock < MAX_SOCK_NUM; sock++) { +    EthernetClient client(sock); + +    if (EthernetClass::_server_port[sock] == _port && +      client.status() == SnSR::ESTABLISHED) { +      n += client.write(buffer, size); +    } +  } +   +  return n; +} diff --git a/libraries/Ethernet/EthernetServer.h b/libraries/Ethernet/EthernetServer.h new file mode 100644 index 0000000..86ccafe --- /dev/null +++ b/libraries/Ethernet/EthernetServer.h @@ -0,0 +1,22 @@ +#ifndef ethernetserver_h +#define ethernetserver_h + +#include "Server.h" + +class EthernetClient; + +class EthernetServer :  +public Server { +private: +  uint16_t _port; +  void accept(); +public: +  EthernetServer(uint16_t); +  EthernetClient available(); +  virtual void begin(); +  virtual size_t write(uint8_t); +  virtual size_t write(const uint8_t *buf, size_t size); +  using Print::write; +}; + +#endif diff --git a/libraries/Ethernet/EthernetUdp.cpp b/libraries/Ethernet/EthernetUdp.cpp new file mode 100644 index 0000000..3760052 --- /dev/null +++ b/libraries/Ethernet/EthernetUdp.cpp @@ -0,0 +1,218 @@ +/* + *  Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + *  This version only offers minimal wrapping of socket.c/socket.h + *  Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/  + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#include "w5100.h" +#include "socket.h" +#include "Ethernet.h" +#include "Udp.h" +#include "Dns.h" + +/* Constructor */ +EthernetUDP::EthernetUDP() : _sock(MAX_SOCK_NUM) {} + +/* Start EthernetUDP socket, listening at local port PORT */ +uint8_t EthernetUDP::begin(uint16_t port) { +  if (_sock != MAX_SOCK_NUM) +    return 0; + +  for (int i = 0; i < MAX_SOCK_NUM; i++) { +    uint8_t s = W5100.readSnSR(i); +    if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT) { +      _sock = i; +      break; +    } +  } + +  if (_sock == MAX_SOCK_NUM) +    return 0; + +  _port = port; +  _remaining = 0; +  socket(_sock, SnMR::UDP, _port, 0); + +  return 1; +} + +/* return number of bytes available in the current packet, +   will return zero if parsePacket hasn't been called yet */ +int EthernetUDP::available() { +  return _remaining; +} + +/* Release any resources being used by this EthernetUDP instance */ +void EthernetUDP::stop() +{ +  if (_sock == MAX_SOCK_NUM) +    return; + +  close(_sock); + +  EthernetClass::_server_port[_sock] = 0; +  _sock = MAX_SOCK_NUM; +} + +int EthernetUDP::beginPacket(const char *host, uint16_t port) +{ +  // Look up the host first +  int ret = 0; +  DNSClient dns; +  IPAddress remote_addr; + +  dns.begin(Ethernet.dnsServerIP()); +  ret = dns.getHostByName(host, remote_addr); +  if (ret == 1) { +    return beginPacket(remote_addr, port); +  } else { +    return ret; +  } +} + +int EthernetUDP::beginPacket(IPAddress ip, uint16_t port) +{ +  _offset = 0; +  return startUDP(_sock, rawIPAddress(ip), port); +} + +int EthernetUDP::endPacket() +{ +  return sendUDP(_sock); +} + +size_t EthernetUDP::write(uint8_t byte) +{ +  return write(&byte, 1); +} + +size_t EthernetUDP::write(const uint8_t *buffer, size_t size) +{ +  uint16_t bytes_written = bufferData(_sock, _offset, buffer, size); +  _offset += bytes_written; +  return bytes_written; +} + +int EthernetUDP::parsePacket() +{ +  // discard any remaining bytes in the last packet +  flush(); + +  if (W5100.getRXReceivedSize(_sock) > 0) +  { +    //HACK - hand-parse the UDP packet using TCP recv method +    uint8_t tmpBuf[8]; +    int ret =0;  +    //read 8 header bytes and get IP and port from it +    ret = recv(_sock,tmpBuf,8); +    if (ret > 0) +    { +      _remoteIP = tmpBuf; +      _remotePort = tmpBuf[4]; +      _remotePort = (_remotePort << 8) + tmpBuf[5]; +      _remaining = tmpBuf[6]; +      _remaining = (_remaining << 8) + tmpBuf[7]; + +      // When we get here, any remaining bytes are the data +      ret = _remaining; +    } +    return ret; +  } +  // There aren't any packets available +  return 0; +} + +int EthernetUDP::read() +{ +  uint8_t byte; + +  if ((_remaining > 0) && (recv(_sock, &byte, 1) > 0)) +  { +    // We read things without any problems +    _remaining--; +    return byte; +  } + +  // If we get here, there's no data available +  return -1; +} + +int EthernetUDP::read(unsigned char* buffer, size_t len) +{ + +  if (_remaining > 0) +  { + +    int got; + +    if (_remaining <= len) +    { +      // data should fit in the buffer +      got = recv(_sock, buffer, _remaining); +    } +    else +    { +      // too much data for the buffer,  +      // grab as much as will fit +      got = recv(_sock, buffer, len); +    } + +    if (got > 0) +    { +      _remaining -= got; +      return got; +    } + +  } + +  // If we get here, there's no data available or recv failed +  return -1; + +} + +int EthernetUDP::peek() +{ +  uint8_t b; +  // Unlike recv, peek doesn't check to see if there's any data available, so we must. +  // If the user hasn't called parsePacket yet then return nothing otherwise they +  // may get the UDP header +  if (!_remaining) +    return -1; +  ::peek(_sock, &b); +  return b; +} + +void EthernetUDP::flush() +{ +  // could this fail (loop endlessly) if _remaining > 0 and recv in read fails? +  // should only occur if recv fails after telling us the data is there, lets +  // hope the w5100 always behaves :) + +  while (_remaining) +  { +    read(); +  } +} + diff --git a/libraries/Ethernet/EthernetUdp.h b/libraries/Ethernet/EthernetUdp.h new file mode 100644 index 0000000..8a6b7ab --- /dev/null +++ b/libraries/Ethernet/EthernetUdp.h @@ -0,0 +1,99 @@ +/* + *  Udp.cpp: Library to send/receive UDP packets with the Arduino ethernet shield. + *  This version only offers minimal wrapping of socket.c/socket.h + *  Drop Udp.h/.cpp into the Ethernet library directory at hardware/libraries/Ethernet/  + * + * NOTE: UDP is fast, but has some important limitations (thanks to Warren Gray for mentioning these) + * 1) UDP does not guarantee the order in which assembled UDP packets are received. This + * might not happen often in practice, but in larger network topologies, a UDP + * packet can be received out of sequence.  + * 2) UDP does not guard against lost packets - so packets *can* disappear without the sender being + * aware of it. Again, this may not be a concern in practice on small local networks. + * For more information, see http://www.cafeaulait.org/course/week12/35.html + * + * MIT License: + * Copyright (c) 2008 Bjoern Hartmann + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + *  + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * bjoern@cs.stanford.edu 12/30/2008 + */ + +#ifndef ethernetudp_h +#define ethernetudp_h + +#include <Udp.h> + +#define UDP_TX_PACKET_MAX_SIZE 24 + +class EthernetUDP : public UDP { +private: +  uint8_t _sock;  // socket ID for Wiz5100 +  uint16_t _port; // local port to listen on +  IPAddress _remoteIP; // remote IP address for the incoming packet whilst it's being processed +  uint16_t _remotePort; // remote port for the incoming packet whilst it's being processed +  uint16_t _offset; // offset into the packet being sent +  uint16_t _remaining; // remaining bytes of incoming packet yet to be processed + +public: +  EthernetUDP();  // Constructor +  virtual uint8_t begin(uint16_t);	// initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use +  virtual void stop();  // Finish with the UDP socket + +  // Sending UDP packets +   +  // Start building up a packet to send to the remote host specific in ip and port +  // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port +  virtual int beginPacket(IPAddress ip, uint16_t port); +  // Start building up a packet to send to the remote host specific in host and port +  // Returns 1 if successful, 0 if there was a problem resolving the hostname or port +  virtual int beginPacket(const char *host, uint16_t port); +  // Finish off this packet and send it +  // Returns 1 if the packet was sent successfully, 0 if there was an error +  virtual int endPacket(); +  // Write a single byte into the packet +  virtual size_t write(uint8_t); +  // Write size bytes from buffer into the packet +  virtual size_t write(const uint8_t *buffer, size_t size); +   +  using Print::write; + +  // Start processing the next available incoming packet +  // Returns the size of the packet in bytes, or 0 if no packets are available +  virtual int parsePacket(); +  // Number of bytes remaining in the current packet +  virtual int available(); +  // Read a single byte from the current packet +  virtual int read(); +  // Read up to len bytes from the current packet and place them into buffer +  // Returns the number of bytes read, or 0 if none are available +  virtual int read(unsigned char* buffer, size_t len); +  // Read up to len characters from the current packet and place them into buffer +  // Returns the number of characters read, or 0 if none are available +  virtual int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); }; +  // Return the next byte from the current packet without moving on to the next byte +  virtual int peek(); +  virtual void flush();	// Finish reading the current packet + +  // Return the IP address of the host who sent the current incoming packet +  virtual IPAddress remoteIP() { return _remoteIP; }; +  // Return the port of the host who sent the current incoming packet +  virtual uint16_t remotePort() { return _remotePort; }; +}; + +#endif diff --git a/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino new file mode 100644 index 0000000..bfbcb6d --- /dev/null +++ b/libraries/Ethernet/examples/BarometricPressureWebServer/BarometricPressureWebServer.ino @@ -0,0 +1,222 @@ +/* +  SCP1000 Barometric Pressure Sensor Display +  + Serves the output of a Barometric Pressure Sensor as a web page. + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ +  + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip +  + Circuit: + SCP1000 sensor attached to pins 6,7, and 11 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 +  + created 31 July 2010 + by Tom Igoe + */ + +#include <Ethernet.h> +// the sensor communicates using SPI, so include the library: +#include <SPI.h> + + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +// assign an IP address for the controller: +IPAddress ip(192,168,1,20); +IPAddress gateway(192,168,1,1);	 +IPAddress subnet(255, 255, 255, 0); + + +// Initialize the Ethernet server library +// with the IP address and port you want to use  +// (port 80 is default for HTTP): +EthernetServer server(80); + + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F;      //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure +const int TEMPERATURE = 0x21;   //16 bit temperature reading + +// pins used for the connection with the sensor +// the others you need are controlled by the SPI library): +const int dataReadyPin = 6;  +const int chipSelectPin = 7; + +float temperature = 0.0; +long pressure = 0; +long lastReadingTime = 0; + +void setup() { +  // start the SPI library: +  SPI.begin(); + +  // start the Ethernet connection and the server: +  Ethernet.begin(mac, ip); +  server.begin(); + +  // initalize the  data ready and chip select pins: +  pinMode(dataReadyPin, INPUT); +  pinMode(chipSelectPin, OUTPUT); + +  Serial.begin(9600); + +  //Configure SCP1000 for low noise configuration: +  writeRegister(0x02, 0x2D); +  writeRegister(0x01, 0x03); +  writeRegister(0x03, 0x02); + +  // give the sensor and Ethernet shield time to set up: +  delay(1000); + +  //Set the sensor to high resolution mode tp start readings: +  writeRegister(0x03, 0x0A); + +} + +void loop() {  +  // check for a reading no more than once a second. +  if (millis() - lastReadingTime > 1000){ +    // if there's a reading ready, read it: +    // don't do anything until the data ready pin is high: +    if (digitalRead(dataReadyPin) == HIGH) { +      getData(); +      // timestamp the last time you got a reading: +      lastReadingTime = millis(); +    } +  } + +  // listen for incoming Ethernet connections: +  listenForEthernetClients(); +} + + +void getData() { +  Serial.println("Getting reading"); +  //Read the temperature data +  int tempData = readRegister(0x21, 2); + +  // convert the temperature to celsius and display it: +  temperature = (float)tempData / 20.0; + +  //Read the pressure data highest 3 bits: +  byte  pressureDataHigh = readRegister(0x1F, 1);    +  pressureDataHigh &= 0b00000111; //you only needs bits 2 to 0 + +  //Read the pressure data lower 16 bits: +  unsigned int pressureDataLow = readRegister(0x20, 2);     +  //combine the two parts into one 19-bit number: +  pressure = ((pressureDataHigh << 16) | pressureDataLow)/4; + +  Serial.print("Temperature: "); +  Serial.print(temperature); +  Serial.println(" degrees C"); +  Serial.print("Pressure: " + String(pressure)); +  Serial.println(" Pa"); +} + +void listenForEthernetClients() { +  // listen for incoming clients +  EthernetClient client = server.available(); +  if (client) { +    Serial.println("Got a client"); +    // an http request ends with a blank line +    boolean currentLineIsBlank = true; +    while (client.connected()) { +      if (client.available()) { +        char c = client.read(); +        // if you've gotten to the end of the line (received a newline +        // character) and the line is blank, the http request has ended, +        // so you can send a reply +        if (c == '\n' && currentLineIsBlank) { +          // send a standard http response header +          client.println("HTTP/1.1 200 OK"); +          client.println("Content-Type: text/html"); +          client.println(); +          // print the current readings, in HTML format: +          client.print("Temperature: "); +          client.print(temperature); +          client.print(" degrees C"); +          client.println("<br />"); +          client.print("Pressure: " + String(pressure)); +          client.print(" Pa"); +          client.println("<br />");   +          break; +        } +        if (c == '\n') { +          // you're starting a new line +          currentLineIsBlank = true; +        }  +        else if (c != '\r') { +          // you've gotten a character on the current line +          currentLineIsBlank = false; +        } +      } +    } +    // give the web browser time to receive the data +    delay(1); +    // close the connection: +    client.stop(); +  } +}  + + +//Send a write command to SCP1000 +void writeRegister(byte registerName, byte registerValue) { +  // SCP1000 expects the register name in the upper 6 bits +  // of the byte: +  registerName <<= 2; +  // command (read or write) goes in the lower two bits: +  registerName |= 0b00000010; //Write command + +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW);  + +  SPI.transfer(registerName); //Send register location +  SPI.transfer(registerValue); //Send value to record into register + +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH);  +} + + +//Read register from the SCP1000: +unsigned int readRegister(byte registerName, int numBytes) { +  byte inByte = 0;           // incoming from  the SPI read +  unsigned int result = 0;   // result to return  + +  // SCP1000 expects the register name in the upper 6 bits +  // of the byte: +  registerName <<=  2; +  // command (read or write) goes in the lower two bits: +  registerName &= 0b11111100; //Read command + +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW);  +  // send the device the register you want to read: +  int command = SPI.transfer(registerName);  +  // send a value of 0 to read the first byte returned: +  inByte = SPI.transfer(0x00);  +   +  result = inByte; +  // if there's more than one byte returned,  +  // shift the first byte then get the second byte: +  if (numBytes > 1){ +    result = inByte << 8; +    inByte = SPI.transfer(0x00);  +    result = result |inByte; +  } +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH);  +  // return the result: +  return(result); +} diff --git a/libraries/Ethernet/examples/ChatServer/ChatServer.ino b/libraries/Ethernet/examples/ChatServer/ChatServer.ino new file mode 100644 index 0000000..d50e5a6 --- /dev/null +++ b/libraries/Ethernet/examples/ChatServer/ChatServer.ino @@ -0,0 +1,79 @@ +/* + Chat  Server +  + A simple server that distributes any incoming messages to all + connected clients.  To use telnet to  your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield.  +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) +  + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,1, 177); +IPAddress gateway(192,168,1, 1); +IPAddress subnet(255, 255, 0, 0); + + +// telnet defaults to port 23 +EthernetServer server(23); +boolean alreadyConnected = false; // whether or not the client was connected previously + +void setup() { +  // initialize the ethernet device +  Ethernet.begin(mac, ip, gateway, subnet); +  // start listening for clients +  server.begin(); + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  Serial.print("Chat server address:"); +  Serial.println(Ethernet.localIP()); +} + +void loop() { +  // wait for a new client: +  EthernetClient client = server.available(); + +  // when the client sends the first byte, say hello: +  if (client) { +    if (!alreadyConnected) { +      // clead out the input buffer: +      client.flush();     +      Serial.println("We have a new client"); +      client.println("Hello, client!");  +      alreadyConnected = true; +    }  + +    if (client.available() > 0) { +      // read the bytes incoming from the client: +      char thisChar = client.read(); +      // echo the bytes back to the client: +      server.write(thisChar); +      // echo the bytes to the server as well: +      Serial.write(thisChar); +    } +  } +} + + + diff --git a/libraries/Ethernet/examples/CosmClient/CosmClient.ino b/libraries/Ethernet/examples/CosmClient/CosmClient.ino new file mode 100644 index 0000000..ec74278 --- /dev/null +++ b/libraries/Ethernet/examples/CosmClient/CosmClient.ino @@ -0,0 +1,161 @@ +/* +  Cosm sensor client +  + This sketch connects an analog sensor to Cosm (http://www.cosm.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. +  + This example has been updated to use version 2.0 of the cosm.com API.  + To make it work, create a feed with a datastream, and give it the ID + sensor1. Or change the code below to match your feed. +  +  + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 15 March 2010 + updated 14 May 2012 + by Tom Igoe with input from Usman Haque and Joe Saavedra +  +http://arduino.cc/en/Tutorial/CosmClient + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +#define APIKEY         "YOUR API KEY GOES HERE" // replace your Cosm api key here +#define FEEDID         00000 // replace your feed ID +#define USERAGENT      "My Project" // user agent is the project name + +// assign a MAC address for the ethernet controller. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +// fill in your address here: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(10,0,1,20); + +// initialize the library instance: +EthernetClient client; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(216,52,233,121);      // numeric IP for api.cosm.com +char server[] = "api.cosm.com";   // name address for cosm API + +unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds +boolean lastConnected = false;                    // state of the connection last time through the main loop +const unsigned long postingInterval = 10L*1000L;  // delay between updates to cosm.com +						  // the "L" is needed to use long type numbers + + +void setup() { +  // start serial port: +  Serial.begin(9600); + // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // DHCP failed, so use a fixed IP address: +    Ethernet.begin(mac, ip); +  } +} + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data: +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(sensorReading); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(int thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.cosm.com"); +    client.print("X-ApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); + +    // calculate the length of the sensor reading in bytes: +    // 8 bytes for "sensor1," + number of digits of the data: +    int thisLength = 8 + getLength(thisData); +    client.println(thisLength); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.print("sensor1,"); +    client.println(thisData); +   +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +   // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + + +// This method calculates the number of digits in the +// sensor reading.  Since each digit of the ASCII decimal +// representation is a byte, the number of digits equals +// the number of bytes: + +int getLength(int someValue) { +  // there's at least one byte: +  int digits = 1; +  // continually divide the value by ten,  +  // adding one to the digit count for each +  // time you divide, until you're at 0: +  int dividend = someValue /10; +  while (dividend > 0) { +    dividend = dividend /10; +    digits++; +  } +  // return the number of digits: +  return digits; +} + diff --git a/libraries/Ethernet/examples/CosmClientString/CosmClientString.ino b/libraries/Ethernet/examples/CosmClientString/CosmClientString.ino new file mode 100644 index 0000000..e619924 --- /dev/null +++ b/libraries/Ethernet/examples/CosmClientString/CosmClientString.ino @@ -0,0 +1,146 @@ +/* +  Cosm sensor client with Strings +  + This sketch connects an analog sensor to Cosm (http://www.cosm.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. +  + This example has been updated to use version 2.0 of the Cosm.com API.  + To make it work, create a feed with two datastreams, and give them the IDs + sensor1 and sensor2. Or change the code below to match your feed. +  + This example uses the String library, which is part of the Arduino core from + version 0019.   +  + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 15 March 2010 + updated 14 May 2012 + by Tom Igoe with input from Usman Haque and Joe Saavedra +  + http://arduino.cc/en/Tutorial/CosmClientString + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <Ethernet.h> + + +#define APIKEY         "YOUR API KEY GOES HERE" // replace your Cosm api key here +#define FEEDID         00000 // replace your feed ID +#define USERAGENT      "My Project" // user agent is the project name + +// assign a MAC address for the ethernet controller. +// fill in your address here: +  byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +   +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(10,0,1,20); + +// initialize the library instance: +EthernetClient client; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(216,52,233,121);      // numeric IP for api.cosm.com +char server[] = "api.cosm.com";   // name address for Cosm API + +unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds +boolean lastConnected = false;                    // state of the connection last time through the main loop +const unsigned long postingInterval = 10L*1000L;  // delay between updates to Cosm.com +						  // the "L" is needed to use long type numbers +void setup() { +  // start serial port: +  Serial.begin(9600); +  // give the ethernet module time to boot up: +  delay(1000); +  // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // DHCP failed, so use a fixed IP address: +    Ethernet.begin(mac, ip); +  } +} + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    +  // convert the data to a String to send it: + +  String dataString = "sensor1,"; +  dataString += sensorReading; + +  // you can append multiple readings to this String if your +  // Cosm feed is set up to handle multiple values: +  int otherSensorReading = analogRead(A1); +  dataString += "\nsensor2,"; +  dataString += otherSensorReading; + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data:  +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(dataString); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(String thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.cosm.com"); +    client.print("X-ApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); +    client.println(thisData.length()); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.println(thisData); +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +  // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + diff --git a/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino new file mode 100644 index 0000000..5eaaf24 --- /dev/null +++ b/libraries/Ethernet/examples/DhcpAddressPrinter/DhcpAddressPrinter.ino @@ -0,0 +1,59 @@ +/* +  DHCP-based IP printer +  + This sketch uses the DHCP extensions to the Ethernet library + to get an IP address via DHCP and print the address obtained. + using an Arduino Wiznet Ethernet shield.  +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 12 April 2011 + modified 9 Apr 2012 + by Tom Igoe +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = {   +  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; + +// Initialize the Ethernet client library +// with the IP address and port of the server  +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +  // this check is only needed on the Leonardo: +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + +  // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // no point in carrying on, so do nothing forevermore: +    for(;;) +      ; +  } +  // print your local IP address: +  Serial.print("My IP address: "); +  for (byte thisByte = 0; thisByte < 4; thisByte++) { +    // print the value of each byte of the IP address: +    Serial.print(Ethernet.localIP()[thisByte], DEC); +    Serial.print(".");  +  } +  Serial.println(); +} + +void loop() { + +} + + diff --git a/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino b/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino new file mode 100644 index 0000000..09cbd43 --- /dev/null +++ b/libraries/Ethernet/examples/DhcpChatServer/DhcpChatServer.ino @@ -0,0 +1,87 @@ +/* + DHCP Chat  Server +  + A simple server that distributes any incoming messages to all + connected clients.  To use telnet to  your device's IP address and type. + You can see the client's input in the serial monitor as well. + Using an Arduino Wiznet Ethernet shield.  +  + THis version attempts to get an IP address using DHCP +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 21 May 2011 + modified 9 Apr 2012 + by Tom Igoe + Based on ChatServer example by David A. Mellis +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network. +// gateway and subnet are optional: +byte mac[] = {  +  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; +IPAddress ip(192,168,1, 177); +IPAddress gateway(192,168,1, 1); +IPAddress subnet(255, 255, 0, 0); + +// telnet defaults to port 23 +EthernetServer server(23); +boolean gotAMessage = false; // whether or not you got a message from the client yet + +void setup() { +  // Open serial communications and wait for port to open: +  Serial.begin(9600); +  // this check is only needed on the Leonardo: +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // start the Ethernet connection: +  Serial.println("Trying to get an IP address using DHCP"); +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // initialize the ethernet device not using DHCP: +    Ethernet.begin(mac, ip, gateway, subnet); +  } +  // print your local IP address: +  Serial.print("My IP address: "); +  ip = Ethernet.localIP(); +  for (byte thisByte = 0; thisByte < 4; thisByte++) { +    // print the value of each byte of the IP address: +    Serial.print(ip[thisByte], DEC); +    Serial.print(".");  +  } +  Serial.println(); +  // start listening for clients +  server.begin(); +  +} + +void loop() { +  // wait for a new client: +  EthernetClient client = server.available(); + +  // when the client sends the first byte, say hello: +  if (client) { +    if (!gotAMessage) { +      Serial.println("We have a new client"); +      client.println("Hello, client!");  +      gotAMessage = true; +    } + +    // read the bytes incoming from the client: +    char thisChar = client.read(); +    // echo the bytes back to the client: +    server.write(thisChar); +    // echo the bytes to the server as well: +    Serial.print(thisChar); +  } +} + diff --git a/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.ino b/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.ino new file mode 100644 index 0000000..c14abf4 --- /dev/null +++ b/libraries/Ethernet/examples/DnsWebClient/DnsWebClient.ino @@ -0,0 +1,81 @@ +/* +  DNS and DHCP-based Web client +  + This sketch connects to a website (http://www.google.com) + using an Arduino Wiznet Ethernet shield.  +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe, based on work by Adrian McEwen +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = {  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; +char serverName[] = "www.google.com"; + +// Initialize the Ethernet client library +// with the IP address and port of the server  +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // no point in carrying on, so do nothing forevermore: +    while(true); +  } +  // give the Ethernet shield a second to initialize: +  delay(1000); +  Serial.println("connecting..."); + +  // if you get a connection, report back via serial: +   +  if (client.connect(serverName, 80)) { +    Serial.println("connected"); +    // Make a HTTP request: +    client.println("GET /search?q=arduino HTTP/1.0"); +    client.println(); +  }  +  else { +    // kf you didn't get a connection to the server: +    Serial.println("connection failed"); +  } +} + +void loop() +{ +  // if there are incoming bytes available  +  // from the server, read them and print them: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if the server's disconnected, stop the client: +  if (!client.connected()) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); + +    // do nothing forevermore: +    while(true); +  } +} + diff --git a/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino b/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino new file mode 100644 index 0000000..dfd2d40 --- /dev/null +++ b/libraries/Ethernet/examples/PachubeClient/PachubeClient.ino @@ -0,0 +1,163 @@ +/* +  Pachube sensor client +  + This sketch connects an analog sensor to Pachube (http://www.pachube.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. +  + This example has been updated to use version 2.0 of the Pachube.com API.  + To make it work, create a feed with a datastream, and give it the ID + sensor1. Or change the code below to match your feed. +  +  + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 15 March 2010 + modified 9 Apr 2012 + by Tom Igoe with input from Usman Haque and Joe Saavedra +  +http://arduino.cc/en/Tutorial/PachubeClient + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +#define APIKEY         "YOUR API KEY GOES HERE" // replace your pachube api key here +#define FEEDID         00000 // replace your feed ID +#define USERAGENT      "My Project" // user agent is the project name + +// assign a MAC address for the ethernet controller. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +// fill in your address here: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(10,0,1,20); +// initialize the library instance: +EthernetClient client; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +IPAddress server(216,52,233,122);      // numeric IP for api.pachube.com +//char server[] = "api.pachube.com";   // name address for pachube API + +unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds +boolean lastConnected = false;                 // state of the connection last time through the main loop +const unsigned long postingInterval = 10*1000; //delay between updates to Pachube.com + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + + // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // DHCP failed, so use a fixed IP address: +    Ethernet.begin(mac, ip); +  } +} + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data: +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(sensorReading); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(int thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.pachube.com"); +    client.print("X-PachubeApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); + +    // calculate the length of the sensor reading in bytes: +    // 8 bytes for "sensor1," + number of digits of the data: +    int thisLength = 8 + getLength(thisData); +    client.println(thisLength); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.print("sensor1,"); +    client.println(thisData); +   +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +   // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + + +// This method calculates the number of digits in the +// sensor reading.  Since each digit of the ASCII decimal +// representation is a byte, the number of digits equals +// the number of bytes: + +int getLength(int someValue) { +  // there's at least one byte: +  int digits = 1; +  // continually divide the value by ten,  +  // adding one to the digit count for each +  // time you divide, until you're at 0: +  int dividend = someValue /10; +  while (dividend > 0) { +    dividend = dividend /10; +    digits++; +  } +  // return the number of digits: +  return digits; +} + diff --git a/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino new file mode 100644 index 0000000..2a96e9f --- /dev/null +++ b/libraries/Ethernet/examples/PachubeClientString/PachubeClientString.ino @@ -0,0 +1,152 @@ +/* +  Cosm sensor client with Strings +  + This sketch connects an analog sensor to Cosm (http://www.cosm.com) + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. +  + This example has been updated to use version 2.0 of the Cosm.com API.  + To make it work, create a feed with two datastreams, and give them the IDs + sensor1 and sensor2. Or change the code below to match your feed. +  + This example uses the String library, which is part of the Arduino core from + version 0019.   +  + Circuit: + * Analog sensor attached to analog in 0 + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 15 March 2010 + modified 9 Apr 2012 + by Tom Igoe with input from Usman Haque and Joe Saavedra +  + http://arduino.cc/en/Tutorial/CosmClientString + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <Ethernet.h> + + +/#define APIKEY         "YOUR API KEY GOES HERE" // replace your Cosm api key here +#define FEEDID         00000 // replace your feed ID +#define USERAGENT      "My Project" // user agent is the project name + + +// assign a MAC address for the ethernet controller. +// fill in your address here: +  byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; + +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(10,0,1,20); + +// initialize the library instance: +EthernetClient client; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +IPAddress server(216,52,233,121);      // numeric IP for api.cosm.com +//char server[] = "api.cosm.com";   // name address for Cosm API + +unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds +boolean lastConnected = false;                 // state of the connection last time through the main loop +const unsigned long postingInterval = 10*1000;  //delay between updates to Cosm.com + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // give the ethernet module time to boot up: +  delay(1000); +  // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // DHCP failed, so use a fixed IP address: +    Ethernet.begin(mac, ip); +  } +} + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    +  // convert the data to a String to send it: + +  String dataString = "sensor1,"; +  dataString += sensorReading; + +  // you can append multiple readings to this String if your +  // Cosm feed is set up to handle multiple values: +  int otherSensorReading = analogRead(A1); +  dataString += "\nsensor2,"; +  dataString += otherSensorReading; + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data:  +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(dataString); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(String thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.cosm.com"); +    client.print("X-CosmApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); +    client.println(thisData.length()); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.println(thisData); +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +  // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + diff --git a/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino b/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino new file mode 100644 index 0000000..3457125 --- /dev/null +++ b/libraries/Ethernet/examples/TelnetClient/TelnetClient.ino @@ -0,0 +1,93 @@ +/* +  Telnet client +  + This sketch connects to a a telnet server (http://www.google.com) + using an Arduino Wiznet Ethernet shield.  You'll need a telnet server  + to test this with. + Processing's ChatServer example (part of the network library) works well,  + running on port 10002. It can be found as part of the examples + in the Processing application, available at  + http://processing.org/ +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 14 Sep 2010 + modified 9 Apr 2012 + by Tom Igoe +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = {   +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,1,177); + +// Enter the IP address of the server you're connecting to: +IPAddress server(1,1,1,1);  + +// Initialize the Ethernet client library +// with the IP address and port of the server  +// that you want to connect to (port 23 is default for telnet; +// if you're using Processing's ChatServer, use  port 10002): +EthernetClient client; + +void setup() { +  // start the Ethernet connection: +  Ethernet.begin(mac, ip); + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // give the Ethernet shield a second to initialize: +  delay(1000); +  Serial.println("connecting..."); + +  // if you get a connection, report back via serial: +  if (client.connect(server, 10002)) { +    Serial.println("connected"); +  }  +  else { +    // if you didn't get a connection to the server: +    Serial.println("connection failed"); +  } +} + +void loop() +{ +  // if there are incoming bytes available  +  // from the server, read them and print them: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // as long as there are bytes in the serial queue, +  // read them and send them out the socket if it's open: +  while (Serial.available() > 0) { +    char inChar = Serial.read(); +    if (client.connected()) { +      client.print(inChar);  +    } +  } + +  // if the server's disconnected, stop the client: +  if (!client.connected()) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +    // do nothing: +    while(true); +  } +} + + + + diff --git a/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino new file mode 100644 index 0000000..3587d72 --- /dev/null +++ b/libraries/Ethernet/examples/TwitterClient/TwitterClient.ino @@ -0,0 +1,135 @@ +/* +  Twitter Client with Strings +  + This sketch connects to Twitter using an Ethernet shield. It parses the XML + returned, and looks for <text>this is a tweet</text> +  + You can use the Arduino Ethernet shield, or the Adafruit Ethernet shield,  + either one will work, as long as it's got a Wiznet Ethernet module on board. +  + This example uses the DHCP routines in the Ethernet library which is part of the  + Arduino core from version 1.0 beta 1 +  + This example uses the String library, which is part of the Arduino core from + version 0019.   +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 21 May 2011 + modified 9 Apr 2012 + by Tom Igoe +  + This code is in the public domain. +  + */ +#include <SPI.h> +#include <Ethernet.h> + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = {  +  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 }; +IPAddress ip(192,168,1,20); + +// initialize the library instance: +EthernetClient client; + +const unsigned long requestInterval = 60000;  // delay between requests + +char serverName[] = "api.twitter.com";  // twitter URL + +boolean requested;                   // whether you've made a request since connecting +unsigned long lastAttemptTime = 0;            // last time you connected to the server, in milliseconds + +String currentLine = "";            // string to hold the text from server +String tweet = "";                  // string to hold the tweet +boolean readingTweet = false;       // if you're currently reading the tweet + +void setup() { +  // reserve space for the strings: +  currentLine.reserve(256); +  tweet.reserve(150); + + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // attempt a DHCP connection: +  Serial.println("Attempting to get an IP address using DHCP:"); +  if (!Ethernet.begin(mac)) { +    // if DHCP fails, start with a hard-coded address: +    Serial.println("failed to get an IP address using DHCP, trying manually"); +    Ethernet.begin(mac, ip); +  } +  Serial.print("My address:"); +  Serial.println(Ethernet.localIP()); +  // connect to Twitter: +  connectToServer(); +} + + + +void loop() +{ +  if (client.connected()) { +    if (client.available()) { +      // read incoming bytes: +      char inChar = client.read(); + +      // add incoming byte to end of line: +      currentLine += inChar;  + +      // if you get a newline, clear the line: +      if (inChar == '\n') { +        currentLine = ""; +      }  +      // if the current line ends with <text>, it will +      // be followed by the tweet: +      if ( currentLine.endsWith("<text>")) { +        // tweet is beginning. Clear the tweet string: +        readingTweet = true;  +        tweet = ""; +      } +      // if you're currently reading the bytes of a tweet, +      // add them to the tweet String: +      if (readingTweet) { +        if (inChar != '<') { +          tweet += inChar; +        }  +        else { +          // if you got a "<" character, +          // you've reached the end of the tweet: +          readingTweet = false; +          Serial.println(tweet);    +          // close the connection to the server: +          client.stop();  +        } +      } +    }    +  } +  else if (millis() - lastAttemptTime > requestInterval) { +    // if you're not connected, and two minutes have passed since +    // your last connection, then attempt to connect again: +    connectToServer(); +  } +} + +void connectToServer() { +  // attempt to connect, and wait a millisecond: +  Serial.println("connecting to server..."); +  if (client.connect(serverName, 80)) { +    Serial.println("making HTTP request..."); +    // make HTTP GET request to twitter: +    client.println("GET /1/statuses/user_timeline.xml?screen_name=arduino&count=1 HTTP/1.1"); +    client.println("HOST: api.twitter.com"); +    client.println(); +  } +  // note the time of this connect attempt: +  lastAttemptTime = millis(); +}    + diff --git a/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino new file mode 100644 index 0000000..4d4045c --- /dev/null +++ b/libraries/Ethernet/examples/UDPSendReceiveString/UDPSendReceiveString.ino @@ -0,0 +1,118 @@ +/* +  UDPSendReceive.pde: + This sketch receives UDP message strings, prints them to the serial port + and sends an "acknowledge" string back to the sender +  + A Processing sketch is included at the end of file that can be used to send  + and received messages for testing with a computer. +  + created 21 Aug 2010 + by Michael Margolis +  + This code is in the public domain. + */ + + +#include <SPI.h>         // needed for Arduino versions later than 0018 +#include <Ethernet.h> +#include <EthernetUdp.h>         // UDP library from: bjoern@cs.stanford.edu 12/30/2008 + + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = {   +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192, 168, 1, 177); + +unsigned int localPort = 8888;      // local port to listen on + +// buffers for receiving and sending data +char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, +char  ReplyBuffer[] = "acknowledged";       // a string to send back + +// An EthernetUDP instance to let us send and receive packets over UDP +EthernetUDP Udp; + +void setup() { +  // start the Ethernet and UDP: +  Ethernet.begin(mac,ip); +  Udp.begin(localPort); + +  Serial.begin(9600); +} + +void loop() { +  // if there's data available, read a packet +  int packetSize = Udp.parsePacket(); +  if(packetSize) +  { +    Serial.print("Received packet of size "); +    Serial.println(packetSize); +    Serial.print("From "); +    IPAddress remote = Udp.remoteIP(); +    for (int i =0; i < 4; i++) +    { +      Serial.print(remote[i], DEC); +      if (i < 3) +      { +        Serial.print("."); +      } +    } +    Serial.print(", port "); +    Serial.println(Udp.remotePort()); + +    // read the packet into packetBufffer +    Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE); +    Serial.println("Contents:"); +    Serial.println(packetBuffer); + +    // send a reply, to the IP address and port that sent us the packet we received +    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort()); +    Udp.write(ReplyBuffer); +    Udp.endPacket(); +  } +  delay(10); +} + + +/* +  Processing sketch to run with this example + ===================================================== +  + // Processing UDP example to send and receive string data from Arduino  + // press any key to send the "Hello Arduino" message +  +  + 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.1.177";	// the remote IP address + int port        = 8888;		// the destination port +  + udp.send("Hello World", 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();    + } + */ + + diff --git a/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino new file mode 100644 index 0000000..93ffe39 --- /dev/null +++ b/libraries/Ethernet/examples/UdpNtpClient/UdpNtpClient.ino @@ -0,0 +1,141 @@ +/* + + Udp NTP Client +  + Get the time from a Network Time Protocol (NTP) time server + Demonstrates use of UDP sendPacket and ReceivePacket  + For more on NTP time servers and the messages needed to communicate with them,  + see http://en.wikipedia.org/wiki/Network_Time_Protocol +  + created 4 Sep 2010  + by Michael Margolis + modified 9 Apr 2012 + by Tom Igoe +  + This code is in the public domain. + + */ + +#include <SPI.h>          +#include <Ethernet.h> +#include <EthernetUdp.h> + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = {   +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; + +unsigned int localPort = 8888;      // local port to listen for UDP packets + +IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server + +const int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the message + +byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets  + +// A UDP instance to let us send and receive packets over UDP +EthernetUDP Udp; + +void setup()  +{ + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // start Ethernet and UDP +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // no point in carrying on, so do nothing forevermore: +    for(;;) +      ; +  } +  Udp.begin(localPort); +} + +void loop() +{ +  sendNTPpacket(timeServer); // send an NTP packet to a time server + +    // wait to see if a reply is available +  delay(1000);   +  if ( Udp.parsePacket() ) {   +    // We've received a packet, read the data from it +    Udp.read(packetBuffer,NTP_PACKET_SIZE);  // read the packet into the buffer + +    //the timestamp starts at byte 40 of the received packet and is four bytes, +    // or two words, long. First, esxtract the two words: + +    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); +    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);   +    // combine the four bytes (two words) into a long integer +    // this is NTP time (seconds since Jan 1 1900): +    unsigned long secsSince1900 = highWord << 16 | lowWord;   +    Serial.print("Seconds since Jan 1 1900 = " ); +    Serial.println(secsSince1900);                + +    // now convert NTP time into everyday time: +    Serial.print("Unix time = "); +    // Unix time starts on Jan 1 1970. In seconds, that's 2208988800: +    const unsigned long seventyYears = 2208988800UL;      +    // subtract seventy years: +    unsigned long epoch = secsSince1900 - seventyYears;   +    // print Unix time: +    Serial.println(epoch);                                + + +    // print the hour, minute and second: +    Serial.print("The UTC time is ");       // UTC is the time at Greenwich Meridian (GMT) +    Serial.print((epoch  % 86400L) / 3600); // print the hour (86400 equals secs per day) +    Serial.print(':');   +    if ( ((epoch % 3600) / 60) < 10 ) { +      // In the first 10 minutes of each hour, we'll want a leading '0' +      Serial.print('0'); +    } +    Serial.print((epoch  % 3600) / 60); // print the minute (3600 equals secs per minute) +    Serial.print(':');  +    if ( (epoch % 60) < 10 ) { +      // In the first 10 seconds of each minute, we'll want a leading '0' +      Serial.print('0'); +    } +    Serial.println(epoch %60); // print the second +  } +  // wait ten seconds before asking for the time again +  delay(10000);  +} + +// send an NTP request to the time server at the given address  +unsigned long sendNTPpacket(IPAddress& address) +{ +  // set all bytes in the buffer to 0 +  memset(packetBuffer, 0, NTP_PACKET_SIZE);  +  // Initialize values needed to form NTP request +  // (see URL above for details on the packets) +  packetBuffer[0] = 0b11100011;   // LI, Version, Mode +  packetBuffer[1] = 0;     // Stratum, or type of clock +  packetBuffer[2] = 6;     // Polling Interval +  packetBuffer[3] = 0xEC;  // Peer Clock Precision +  // 8 bytes of zero for Root Delay & Root Dispersion +  packetBuffer[12]  = 49;  +  packetBuffer[13]  = 0x4E; +  packetBuffer[14]  = 49; +  packetBuffer[15]  = 52; + +  // all NTP fields have been given values, now +  // you can send a packet requesting a timestamp: 		    +  Udp.beginPacket(address, 123); //NTP requests are to port 123 +  Udp.write(packetBuffer,NTP_PACKET_SIZE); +  Udp.endPacket();  +} + + + + + + + + + + diff --git a/libraries/Ethernet/examples/WebClient/WebClient.ino b/libraries/Ethernet/examples/WebClient/WebClient.ino new file mode 100644 index 0000000..5d5d7f2 --- /dev/null +++ b/libraries/Ethernet/examples/WebClient/WebClient.ino @@ -0,0 +1,80 @@ +/* +  Web client +  + This sketch connects to a website (http://www.google.com) + using an Arduino Wiznet Ethernet shield.  +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 18 Dec 2009 + modified 9 Apr 2012 + by David A. Mellis +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address for your controller below. +// Newer Ethernet shields have a MAC address printed on a sticker on the shield +byte mac[] = {  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress server(173,194,33,104); // Google + +// Initialize the Ethernet client library +// with the IP address and port of the server  +// that you want to connect to (port 80 is default for HTTP): +EthernetClient client; + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + +  // start the Ethernet connection: +  if (Ethernet.begin(mac) == 0) { +    Serial.println("Failed to configure Ethernet using DHCP"); +    // no point in carrying on, so do nothing forevermore: +    for(;;) +      ; +  } +  // give the Ethernet shield a second to initialize: +  delay(1000); +  Serial.println("connecting..."); + +  // if you get a connection, report back via serial: +  if (client.connect(server, 80)) { +    Serial.println("connected"); +    // Make a HTTP request: +    client.println("GET /search?q=arduino HTTP/1.0"); +    client.println(); +  }  +  else { +    // kf you didn't get a connection to the server: +    Serial.println("connection failed"); +  } +} + +void loop() +{ +  // if there are incoming bytes available  +  // from the server, read them and print them: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if the server's disconnected, stop the client: +  if (!client.connected()) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); + +    // do nothing forevermore: +    for(;;) +      ; +  } +} + diff --git a/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino b/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino new file mode 100644 index 0000000..650f74e --- /dev/null +++ b/libraries/Ethernet/examples/WebClientRepeating/WebClientRepeating.ino @@ -0,0 +1,111 @@ +/* +  Repeating Web client +  + This sketch connects to a a web server and makes a request + using a Wiznet Ethernet shield. You can use the Arduino Ethernet shield, or + the Adafruit Ethernet shield, either one will work, as long as it's got + a Wiznet Ethernet module on board. +  + This example uses DNS, by assigning the Ethernet client with a MAC address, + IP address, and DNS address. +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 +  + created 19 Apr 2012 + by Tom Igoe +  + http://arduino.cc/en/Tutorial/WebClientRepeating + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// assign a MAC address for the ethernet controller. +// fill in your address here: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; +// fill in an available IP address on your network here, +// for manual configuration: +IPAddress ip(10,0,0,20); + +// fill in your Domain Name Server address here: +IPAddress myDns(1,1,1,1); + +// initialize the library instance: +EthernetClient client; + +char server[] = "www.arduino.cc"; + +unsigned long lastConnectionTime = 0;             // last time you connected to the server, in milliseconds +boolean lastConnected = false;                    // state of the connection last time through the main loop +const unsigned long postingInterval = 60L*1000L;  // delay between updates, in milliseconds +						  // the "L" is needed to use long type numbers + +void setup() { +  // start serial port: +  Serial.begin(9600); +  // give the ethernet module time to boot up: +  delay(1000); +  // start the Ethernet connection using a fixed IP address and DNS server: +  Ethernet.begin(mac, ip, myDns); +  // print the Ethernet board/shield's IP address: +  Serial.print("My IP address: "); +  Serial.println(Ethernet.localIP()); +} + +void loop() { +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  if (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data: +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    httpRequest(); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void httpRequest() { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.println("GET /latest.txt HTTP/1.1"); +    client.println("Host: www.arduino.cc"); +    client.println("User-Agent: arduino-ethernet"); +    client.println("Connection: close"); +    client.println(); + +    // note the time that the connection was made: +    lastConnectionTime = millis(); +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println("disconnecting."); +    client.stop(); +  } +} + + + + diff --git a/libraries/Ethernet/examples/WebServer/WebServer.ino b/libraries/Ethernet/examples/WebServer/WebServer.ino new file mode 100644 index 0000000..ce8dbb1 --- /dev/null +++ b/libraries/Ethernet/examples/WebServer/WebServer.ino @@ -0,0 +1,101 @@ +/* +  Web Server +  + A simple web server that shows the value of the analog input pins. + using an Arduino Wiznet Ethernet shield.  +  + Circuit: + * Ethernet shield attached to pins 10, 11, 12, 13 + * Analog inputs attached to pins A0 through A5 (optional) +  + created 18 Dec 2009 + by David A. Mellis + modified 9 Apr 2012 + by Tom Igoe +  + */ + +#include <SPI.h> +#include <Ethernet.h> + +// Enter a MAC address and IP address for your controller below. +// The IP address will be dependent on your local network: +byte mac[] = {  +  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; +IPAddress ip(192,168,1, 177); + +// Initialize the Ethernet server library +// with the IP address and port you want to use  +// (port 80 is default for HTTP): +EthernetServer server(80); + +void setup() { + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // start the Ethernet connection and the server: +  Ethernet.begin(mac, ip); +  server.begin(); +  Serial.print("server is at "); +  Serial.println(Ethernet.localIP()); +} + + +void loop() { +  // listen for incoming clients +  EthernetClient client = server.available(); +  if (client) { +    Serial.println("new client"); +    // an http request ends with a blank line +    boolean currentLineIsBlank = true; +    while (client.connected()) { +      if (client.available()) { +        char c = client.read(); +        Serial.write(c); +        // if you've gotten to the end of the line (received a newline +        // character) and the line is blank, the http request has ended, +        // so you can send a reply +        if (c == '\n' && currentLineIsBlank) { +          // send a standard http response header +          client.println("HTTP/1.1 200 OK"); +          client.println("Content-Type: text/html"); +          client.println("Connnection: close"); +          client.println(); +          client.println("<!DOCTYPE HTML>"); +          client.println("<html>"); +                    // add a meta refresh tag, so the browser pulls again every 5 seconds: +          client.println("<meta http-equiv=\"refresh\" content=\"5\">"); +          // output the value of each analog input pin +          for (int analogChannel = 0; analogChannel < 6; analogChannel++) { +            int sensorReading = analogRead(analogChannel); +            client.print("analog input "); +            client.print(analogChannel); +            client.print(" is "); +            client.print(sensorReading); +            client.println("<br />");        +          } +          client.println("</html>"); +          break; +        } +        if (c == '\n') { +          // you're starting a new line +          currentLineIsBlank = true; +        }  +        else if (c != '\r') { +          // you've gotten a character on the current line +          currentLineIsBlank = false; +        } +      } +    } +    // give the web browser time to receive the data +    delay(1); +    // close the connection: +    client.stop(); +    Serial.println("client disonnected"); +  } +} + diff --git a/libraries/Ethernet/keywords.txt b/libraries/Ethernet/keywords.txt new file mode 100644 index 0000000..6b37cbe --- /dev/null +++ b/libraries/Ethernet/keywords.txt @@ -0,0 +1,37 @@ +####################################### +# Syntax Coloring Map For Ethernet +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Ethernet	KEYWORD1 +EthernetClient	KEYWORD1 +EthernetServer	KEYWORD1 +IPAddress	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +status	KEYWORD2 +connect	KEYWORD2 +write	KEYWORD2 +available	KEYWORD2 +read	KEYWORD2 +peek	KEYWORD2 +flush	KEYWORD2 +stop	KEYWORD2 +connected	KEYWORD2 +begin	KEYWORD2 +beginPacket	KEYWORD2 +endPacket	KEYWORD2 +parsePacket	KEYWORD2 +remoteIP	KEYWORD2 +remotePort	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Ethernet/util.h b/libraries/Ethernet/util.h new file mode 100644 index 0000000..5042e82 --- /dev/null +++ b/libraries/Ethernet/util.h @@ -0,0 +1,13 @@ +#ifndef UTIL_H +#define UTIL_H + +#define htons(x) ( ((x)<<8) | (((x)>>8)&0xFF) ) +#define ntohs(x) htons(x) + +#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \ +                   ((x)<< 8 & 0x00FF0000UL) | \ +                   ((x)>> 8 & 0x0000FF00UL) | \ +                   ((x)>>24 & 0x000000FFUL) ) +#define ntohl(x) htonl(x) + +#endif diff --git a/libraries/Ethernet/utility/socket.cpp b/libraries/Ethernet/utility/socket.cpp new file mode 100644 index 0000000..fd3e442 --- /dev/null +++ b/libraries/Ethernet/utility/socket.cpp @@ -0,0 +1,400 @@ +#include "w5100.h" +#include "socket.h" + +static uint16_t local_port; + +/** + * @brief	This Socket function initialize the channel in perticular mode, and set the port and wait for W5100 done it. + * @return 	1 for success else 0. + */ +uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag) +{ +  if ((protocol == SnMR::TCP) || (protocol == SnMR::UDP) || (protocol == SnMR::IPRAW) || (protocol == SnMR::MACRAW) || (protocol == SnMR::PPPOE)) +  { +    close(s); +    W5100.writeSnMR(s, protocol | flag); +    if (port != 0) { +      W5100.writeSnPORT(s, port); +    }  +    else { +      local_port++; // if don't set the source port, set local_port number. +      W5100.writeSnPORT(s, local_port); +    } + +    W5100.execCmdSn(s, Sock_OPEN); +     +    return 1; +  } + +  return 0; +} + + +/** + * @brief	This function close the socket and parameter is "s" which represent the socket number + */ +void close(SOCKET s) +{ +  W5100.execCmdSn(s, Sock_CLOSE); +  W5100.writeSnIR(s, 0xFF); +} + + +/** + * @brief	This function established  the connection for the channel in passive (server) mode. This function waits for the request from the peer. + * @return	1 for success else 0. + */ +uint8_t listen(SOCKET s) +{ +  if (W5100.readSnSR(s) != SnSR::INIT) +    return 0; +  W5100.execCmdSn(s, Sock_LISTEN); +  return 1; +} + + +/** + * @brief	This function established  the connection for the channel in Active (client) mode.  + * 		This function waits for the untill the connection is established. + * 		 + * @return	1 for success else 0. + */ +uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port) +{ +  if  +    ( +  ((addr[0] == 0xFF) && (addr[1] == 0xFF) && (addr[2] == 0xFF) && (addr[3] == 0xFF)) || +    ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || +    (port == 0x00)  +    )  +    return 0; + +  // set destination IP +  W5100.writeSnDIPR(s, addr); +  W5100.writeSnDPORT(s, port); +  W5100.execCmdSn(s, Sock_CONNECT); + +  return 1; +} + + + +/** + * @brief	This function used for disconnect the socket and parameter is "s" which represent the socket number + * @return	1 for success else 0. + */ +void disconnect(SOCKET s) +{ +  W5100.execCmdSn(s, Sock_DISCON); +} + + +/** + * @brief	This function used to send the data in TCP mode + * @return	1 for success else 0. + */ +uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len) +{ +  uint8_t status=0; +  uint16_t ret=0; +  uint16_t freesize=0; + +  if (len > W5100.SSIZE)  +    ret = W5100.SSIZE; // check size not to exceed MAX size. +  else  +    ret = len; + +  // if freebuf is available, start. +  do  +  { +    freesize = W5100.getTXFreeSize(s); +    status = W5100.readSnSR(s); +    if ((status != SnSR::ESTABLISHED) && (status != SnSR::CLOSE_WAIT)) +    { +      ret = 0;  +      break; +    } +  }  +  while (freesize < ret); + +  // copy data +  W5100.send_data_processing(s, (uint8_t *)buf, ret); +  W5100.execCmdSn(s, Sock_SEND); + +  /* +2008.01 bj */ +  while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )  +  { +    /* m2008.01 [bj] : reduce code */ +    if ( W5100.readSnSR(s) == SnSR::CLOSED ) +    { +      close(s); +      return 0; +    } +  } +  /* +2008.01 bj */ +  W5100.writeSnIR(s, SnIR::SEND_OK); +  return ret; +} + + +/** + * @brief	This function is an application I/F function which is used to receive the data in TCP mode. + * 		It continues to wait for data as much as the application wants to receive. + * 		 + * @return	received data size for success else -1. + */ +int16_t recv(SOCKET s, uint8_t *buf, int16_t len) +{ +  // Check how much data is available +  int16_t ret = W5100.getRXReceivedSize(s); +  if ( ret == 0 ) +  { +    // No data available. +    uint8_t status = W5100.readSnSR(s); +    if ( status == SnSR::LISTEN || status == SnSR::CLOSED || status == SnSR::CLOSE_WAIT ) +    { +      // The remote end has closed its side of the connection, so this is the eof state +      ret = 0; +    } +    else +    { +      // The connection is still up, but there's no data waiting to be read +      ret = -1; +    } +  } +  else if (ret > len) +  { +    ret = len; +  } + +  if ( ret > 0 ) +  { +    W5100.recv_data_processing(s, buf, ret); +    W5100.execCmdSn(s, Sock_RECV); +  } +  return ret; +} + + +/** + * @brief	Returns the first byte in the receive queue (no checking) + * 		 + * @return + */ +uint16_t peek(SOCKET s, uint8_t *buf) +{ +  W5100.recv_data_processing(s, buf, 1, 1); + +  return 1; +} + + +/** + * @brief	This function is an application I/F function which is used to send the data for other then TCP mode.  + * 		Unlike TCP transmission, The peer's destination address and the port is needed. + * 		 + * @return	This function return send data size for success else -1. + */ +uint16_t sendto(SOCKET s, const uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t port) +{ +  uint16_t ret=0; + +  if (len > W5100.SSIZE) ret = W5100.SSIZE; // check size not to exceed MAX size. +  else ret = len; + +  if +    ( +  ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || +    ((port == 0x00)) ||(ret == 0) +    )  +  { +    /* +2008.01 [bj] : added return value */ +    ret = 0; +  } +  else +  { +    W5100.writeSnDIPR(s, addr); +    W5100.writeSnDPORT(s, port); + +    // copy data +    W5100.send_data_processing(s, (uint8_t *)buf, ret); +    W5100.execCmdSn(s, Sock_SEND); + +    /* +2008.01 bj */ +    while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )  +    { +      if (W5100.readSnIR(s) & SnIR::TIMEOUT) +      { +        /* +2008.01 [bj]: clear interrupt */ +        W5100.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); /* clear SEND_OK & TIMEOUT */ +        return 0; +      } +    } + +    /* +2008.01 bj */ +    W5100.writeSnIR(s, SnIR::SEND_OK); +  } +  return ret; +} + + +/** + * @brief	This function is an application I/F function which is used to receive the data in other then + * 	TCP mode. This function is used to receive UDP, IP_RAW and MAC_RAW mode, and handle the header as well.  + * 	 + * @return	This function return received data size for success else -1. + */ +uint16_t recvfrom(SOCKET s, uint8_t *buf, uint16_t len, uint8_t *addr, uint16_t *port) +{ +  uint8_t head[8]; +  uint16_t data_len=0; +  uint16_t ptr=0; + +  if ( len > 0 ) +  { +    ptr = W5100.readSnRX_RD(s); +    switch (W5100.readSnMR(s) & 0x07) +    { +    case SnMR::UDP : +      W5100.read_data(s, (uint8_t *)ptr, head, 0x08); +      ptr += 8; +      // read peer's IP address, port number. +      addr[0] = head[0]; +      addr[1] = head[1]; +      addr[2] = head[2]; +      addr[3] = head[3]; +      *port = head[4]; +      *port = (*port << 8) + head[5]; +      data_len = head[6]; +      data_len = (data_len << 8) + head[7]; + +      W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy. +      ptr += data_len; + +      W5100.writeSnRX_RD(s, ptr); +      break; + +    case SnMR::IPRAW : +      W5100.read_data(s, (uint8_t *)ptr, head, 0x06); +      ptr += 6; + +      addr[0] = head[0]; +      addr[1] = head[1]; +      addr[2] = head[2]; +      addr[3] = head[3]; +      data_len = head[4]; +      data_len = (data_len << 8) + head[5]; + +      W5100.read_data(s, (uint8_t *)ptr, buf, data_len); // data copy. +      ptr += data_len; + +      W5100.writeSnRX_RD(s, ptr); +      break; + +    case SnMR::MACRAW: +      W5100.read_data(s,(uint8_t*)ptr,head,2); +      ptr+=2; +      data_len = head[0]; +      data_len = (data_len<<8) + head[1] - 2; + +      W5100.read_data(s,(uint8_t*) ptr,buf,data_len); +      ptr += data_len; +      W5100.writeSnRX_RD(s, ptr); +      break; + +    default : +      break; +    } +    W5100.execCmdSn(s, Sock_RECV); +  } +  return data_len; +} + + +uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len) +{ +  uint8_t status=0; +  uint16_t ret=0; + +  if (len > W5100.SSIZE)  +    ret = W5100.SSIZE; // check size not to exceed MAX size. +  else  +    ret = len; + +  if (ret == 0) +    return 0; + +  W5100.send_data_processing(s, (uint8_t *)buf, ret); +  W5100.execCmdSn(s, Sock_SEND); + +  while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )  +  { +    status = W5100.readSnSR(s); +    if (W5100.readSnIR(s) & SnIR::TIMEOUT) +    { +      /* in case of igmp, if send fails, then socket closed */ +      /* if you want change, remove this code. */ +      close(s); +      return 0; +    } +  } + +  W5100.writeSnIR(s, SnIR::SEND_OK); +  return ret; +} + +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len) +{ +  uint16_t ret =0; +  if (len > W5100.getTXFreeSize(s)) +  { +    ret = W5100.getTXFreeSize(s); // check size not to exceed MAX size. +  } +  else +  { +    ret = len; +  } +  W5100.send_data_processing_offset(s, offset, buf, ret); +  return ret; +} + +int startUDP(SOCKET s, uint8_t* addr, uint16_t port) +{ +  if +    ( +     ((addr[0] == 0x00) && (addr[1] == 0x00) && (addr[2] == 0x00) && (addr[3] == 0x00)) || +     ((port == 0x00)) +    )  +  { +    return 0; +  } +  else +  { +    W5100.writeSnDIPR(s, addr); +    W5100.writeSnDPORT(s, port); +    return 1; +  } +} + +int sendUDP(SOCKET s) +{ +  W5100.execCmdSn(s, Sock_SEND); +		 +  /* +2008.01 bj */ +  while ( (W5100.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK )  +  { +    if (W5100.readSnIR(s) & SnIR::TIMEOUT) +    { +      /* +2008.01 [bj]: clear interrupt */ +      W5100.writeSnIR(s, (SnIR::SEND_OK|SnIR::TIMEOUT)); +      return 0; +    } +  } + +  /* +2008.01 bj */	 +  W5100.writeSnIR(s, SnIR::SEND_OK); + +  /* Sent ok */ +  return 1; +} + diff --git a/libraries/Ethernet/utility/socket.h b/libraries/Ethernet/utility/socket.h new file mode 100644 index 0000000..45e0fb3 --- /dev/null +++ b/libraries/Ethernet/utility/socket.h @@ -0,0 +1,41 @@ +#ifndef	_SOCKET_H_ +#define	_SOCKET_H_ + +#include "w5100.h" + +extern uint8_t socket(SOCKET s, uint8_t protocol, uint16_t port, uint8_t flag); // Opens a socket(TCP or UDP or IP_RAW mode) +extern void close(SOCKET s); // Close socket +extern uint8_t connect(SOCKET s, uint8_t * addr, uint16_t port); // Establish TCP connection (Active connection) +extern void disconnect(SOCKET s); // disconnect the connection +extern uint8_t listen(SOCKET s);	// Establish TCP connection (Passive connection) +extern uint16_t send(SOCKET s, const uint8_t * buf, uint16_t len); // Send data (TCP) +extern int16_t recv(SOCKET s, uint8_t * buf, int16_t len);	// Receive data (TCP) +extern uint16_t peek(SOCKET s, uint8_t *buf); +extern uint16_t sendto(SOCKET s, const uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port); // Send data (UDP/IP RAW) +extern uint16_t recvfrom(SOCKET s, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port); // Receive data (UDP/IP RAW) + +extern uint16_t igmpsend(SOCKET s, const uint8_t * buf, uint16_t len); + +// Functions to allow buffered UDP send (i.e. where the UDP datagram is built up over a +// number of calls before being sent +/* +  @brief This function sets up a UDP datagram, the data for which will be provided by one +  or more calls to bufferData and then finally sent with sendUDP. +  @return 1 if the datagram was successfully set up, or 0 if there was an error +*/ +extern int startUDP(SOCKET s, uint8_t* addr, uint16_t port); +/* +  @brief This function copies up to len bytes of data from buf into a UDP datagram to be +  sent later by sendUDP.  Allows datagrams to be built up from a series of bufferData calls. +  @return Number of bytes successfully buffered +*/ +uint16_t bufferData(SOCKET s, uint16_t offset, const uint8_t* buf, uint16_t len); +/* +  @brief Send a UDP datagram built up from a sequence of startUDP followed by one or more +  calls to bufferData. +  @return 1 if the datagram was successfully sent, or 0 if there was an error +*/ +int sendUDP(SOCKET s); + +#endif +/* _SOCKET_H_ */ diff --git a/libraries/Ethernet/utility/w5100.cpp b/libraries/Ethernet/utility/w5100.cpp new file mode 100644 index 0000000..9c748fd --- /dev/null +++ b/libraries/Ethernet/utility/w5100.cpp @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include <stdio.h> +#include <string.h> +#include <avr/interrupt.h> + +#include "w5100.h" + +// W5100 controller instance +W5100Class W5100; + +#define TX_RX_MAX_BUF_SIZE 2048 +#define TX_BUF 0x1100 +#define RX_BUF (TX_BUF + TX_RX_MAX_BUF_SIZE) + +#define TXBUF_BASE 0x4000 +#define RXBUF_BASE 0x6000 + +void W5100Class::init(void) +{ +  delay(300); + +  SPI.begin(); +  initSS(); +   +  writeMR(1<<RST); +  writeTMSR(0x55); +  writeRMSR(0x55); + +  for (int i=0; i<MAX_SOCK_NUM; i++) { +    SBASE[i] = TXBUF_BASE + SSIZE * i; +    RBASE[i] = RXBUF_BASE + RSIZE * i; +  } +} + +uint16_t W5100Class::getTXFreeSize(SOCKET s) +{ +  uint16_t val=0, val1=0; +  do { +    val1 = readSnTX_FSR(s); +    if (val1 != 0) +      val = readSnTX_FSR(s); +  }  +  while (val != val1); +  return val; +} + +uint16_t W5100Class::getRXReceivedSize(SOCKET s) +{ +  uint16_t val=0,val1=0; +  do { +    val1 = readSnRX_RSR(s); +    if (val1 != 0) +      val = readSnRX_RSR(s); +  }  +  while (val != val1); +  return val; +} + + +void W5100Class::send_data_processing(SOCKET s, const uint8_t *data, uint16_t len) +{ +  // This is same as having no offset in a call to send_data_processing_offset +  send_data_processing_offset(s, 0, data, len); +} + +void W5100Class::send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len) +{ +  uint16_t ptr = readSnTX_WR(s); +  ptr += data_offset; +  uint16_t offset = ptr & SMASK; +  uint16_t dstAddr = offset + SBASE[s]; + +  if (offset + len > SSIZE)  +  { +    // Wrap around circular buffer +    uint16_t size = SSIZE - offset; +    write(dstAddr, data, size); +    write(SBASE[s], data + size, len - size); +  }  +  else { +    write(dstAddr, data, len); +  } + +  ptr += len; +  writeSnTX_WR(s, ptr); +} + + +void W5100Class::recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek) +{ +  uint16_t ptr; +  ptr = readSnRX_RD(s); +  read_data(s, (uint8_t *)ptr, data, len); +  if (!peek) +  { +    ptr += len; +    writeSnRX_RD(s, ptr); +  } +} + +void W5100Class::read_data(SOCKET s, volatile uint8_t *src, volatile uint8_t *dst, uint16_t len) +{ +  uint16_t size; +  uint16_t src_mask; +  uint16_t src_ptr; + +  src_mask = (uint16_t)src & RMASK; +  src_ptr = RBASE[s] + src_mask; + +  if( (src_mask + len) > RSIZE )  +  { +    size = RSIZE - src_mask; +    read(src_ptr, (uint8_t *)dst, size); +    dst += size; +    read(RBASE[s], (uint8_t *) dst, len - size); +  }  +  else +    read(src_ptr, (uint8_t *) dst, len); +} + + +uint8_t W5100Class::write(uint16_t _addr, uint8_t _data) +{ +  setSS();   +  SPI.transfer(0xF0); +  SPI.transfer(_addr >> 8); +  SPI.transfer(_addr & 0xFF); +  SPI.transfer(_data); +  resetSS(); +  return 1; +} + +uint16_t W5100Class::write(uint16_t _addr, const uint8_t *_buf, uint16_t _len) +{ +  for (uint16_t i=0; i<_len; i++) +  { +    setSS();     +    SPI.transfer(0xF0); +    SPI.transfer(_addr >> 8); +    SPI.transfer(_addr & 0xFF); +    _addr++; +    SPI.transfer(_buf[i]); +    resetSS(); +  } +  return _len; +} + +uint8_t W5100Class::read(uint16_t _addr) +{ +  setSS();   +  SPI.transfer(0x0F); +  SPI.transfer(_addr >> 8); +  SPI.transfer(_addr & 0xFF); +  uint8_t _data = SPI.transfer(0); +  resetSS(); +  return _data; +} + +uint16_t W5100Class::read(uint16_t _addr, uint8_t *_buf, uint16_t _len) +{ +  for (uint16_t i=0; i<_len; i++) +  { +    setSS(); +    SPI.transfer(0x0F); +    SPI.transfer(_addr >> 8); +    SPI.transfer(_addr & 0xFF); +    _addr++; +    _buf[i] = SPI.transfer(0); +    resetSS(); +  } +  return _len; +} + +void W5100Class::execCmdSn(SOCKET s, SockCMD _cmd) { +  // Send command to socket +  writeSnCR(s, _cmd); +  // Wait for command to complete +  while (readSnCR(s)) +    ; +} diff --git a/libraries/Ethernet/utility/w5100.h b/libraries/Ethernet/utility/w5100.h new file mode 100644 index 0000000..8dccd9f --- /dev/null +++ b/libraries/Ethernet/utility/w5100.h @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef	W5100_H_INCLUDED +#define	W5100_H_INCLUDED + +#include <avr/pgmspace.h> +#include <SPI.h> + +#define MAX_SOCK_NUM 4 + +typedef uint8_t SOCKET; + +#define IDM_OR  0x8000 +#define IDM_AR0 0x8001 +#define IDM_AR1 0x8002 +#define IDM_DR  0x8003 +/* +class MR { +public: +  static const uint8_t RST   = 0x80; +  static const uint8_t PB    = 0x10; +  static const uint8_t PPPOE = 0x08; +  static const uint8_t LB    = 0x04; +  static const uint8_t AI    = 0x02; +  static const uint8_t IND   = 0x01; +}; +*/ +/* +class IR { +public: +  static const uint8_t CONFLICT = 0x80; +  static const uint8_t UNREACH  = 0x40; +  static const uint8_t PPPoE    = 0x20; +  static const uint8_t SOCK0    = 0x01; +  static const uint8_t SOCK1    = 0x02; +  static const uint8_t SOCK2    = 0x04; +  static const uint8_t SOCK3    = 0x08; +  static inline uint8_t SOCK(SOCKET ch) { return (0x01 << ch); }; +}; +*/ + +class SnMR { +public: +  static const uint8_t CLOSE  = 0x00; +  static const uint8_t TCP    = 0x01; +  static const uint8_t UDP    = 0x02; +  static const uint8_t IPRAW  = 0x03; +  static const uint8_t MACRAW = 0x04; +  static const uint8_t PPPOE  = 0x05; +  static const uint8_t ND     = 0x20; +  static const uint8_t MULTI  = 0x80; +}; + +enum SockCMD { +  Sock_OPEN      = 0x01, +  Sock_LISTEN    = 0x02, +  Sock_CONNECT   = 0x04, +  Sock_DISCON    = 0x08, +  Sock_CLOSE     = 0x10, +  Sock_SEND      = 0x20, +  Sock_SEND_MAC  = 0x21, +  Sock_SEND_KEEP = 0x22, +  Sock_RECV      = 0x40 +}; + +/*class SnCmd { +public: +  static const uint8_t OPEN      = 0x01; +  static const uint8_t LISTEN    = 0x02; +  static const uint8_t CONNECT   = 0x04; +  static const uint8_t DISCON    = 0x08; +  static const uint8_t CLOSE     = 0x10; +  static const uint8_t SEND      = 0x20; +  static const uint8_t SEND_MAC  = 0x21; +  static const uint8_t SEND_KEEP = 0x22; +  static const uint8_t RECV      = 0x40; +}; +*/ + +class SnIR { +public: +  static const uint8_t SEND_OK = 0x10; +  static const uint8_t TIMEOUT = 0x08; +  static const uint8_t RECV    = 0x04; +  static const uint8_t DISCON  = 0x02; +  static const uint8_t CON     = 0x01; +}; + +class SnSR { +public: +  static const uint8_t CLOSED      = 0x00; +  static const uint8_t INIT        = 0x13; +  static const uint8_t LISTEN      = 0x14; +  static const uint8_t SYNSENT     = 0x15; +  static const uint8_t SYNRECV     = 0x16; +  static const uint8_t ESTABLISHED = 0x17; +  static const uint8_t FIN_WAIT    = 0x18; +  static const uint8_t CLOSING     = 0x1A; +  static const uint8_t TIME_WAIT   = 0x1B; +  static const uint8_t CLOSE_WAIT  = 0x1C; +  static const uint8_t LAST_ACK    = 0x1D; +  static const uint8_t UDP         = 0x22; +  static const uint8_t IPRAW       = 0x32; +  static const uint8_t MACRAW      = 0x42; +  static const uint8_t PPPOE       = 0x5F; +}; + +class IPPROTO { +public: +  static const uint8_t IP   = 0; +  static const uint8_t ICMP = 1; +  static const uint8_t IGMP = 2; +  static const uint8_t GGP  = 3; +  static const uint8_t TCP  = 6; +  static const uint8_t PUP  = 12; +  static const uint8_t UDP  = 17; +  static const uint8_t IDP  = 22; +  static const uint8_t ND   = 77; +  static const uint8_t RAW  = 255; +}; + +class W5100Class { + +public: +  void init(); + +  /** +   * @brief	This function is being used for copy the data form Receive buffer of the chip to application buffer. +   *  +   * It calculate the actual physical address where one has to read +   * the data from Receive buffer. Here also take care of the condition while it exceed +   * the Rx memory uper-bound of socket. +   */ +  void read_data(SOCKET s, volatile uint8_t * src, volatile uint8_t * dst, uint16_t len); +   +  /** +   * @brief	 This function is being called by send() and sendto() function also.  +   *  +   * This function read the Tx write pointer register and after copy the data in buffer update the Tx write pointer +   * register. User should read upper byte first and lower byte later to get proper value. +   */ +  void send_data_processing(SOCKET s, const uint8_t *data, uint16_t len); +  /** +   * @brief A copy of send_data_processing that uses the provided ptr for the +   *        write offset.  Only needed for the "streaming" UDP API, where +   *        a single UDP packet is built up over a number of calls to +   *        send_data_processing_ptr, because TX_WR doesn't seem to get updated +   *        correctly in those scenarios +   * @param ptr value to use in place of TX_WR.  If 0, then the value is read +   *        in from TX_WR +   * @return New value for ptr, to be used in the next call +   */ +// FIXME Update documentation +  void send_data_processing_offset(SOCKET s, uint16_t data_offset, const uint8_t *data, uint16_t len); + +  /** +   * @brief	This function is being called by recv() also. +   *  +   * This function read the Rx read pointer register +   * and after copy the data from receive buffer update the Rx write pointer register. +   * User should read upper byte first and lower byte later to get proper value. +   */ +  void recv_data_processing(SOCKET s, uint8_t *data, uint16_t len, uint8_t peek = 0); + +  inline void setGatewayIp(uint8_t *_addr); +  inline void getGatewayIp(uint8_t *_addr); + +  inline void setSubnetMask(uint8_t *_addr); +  inline void getSubnetMask(uint8_t *_addr); + +  inline void setMACAddress(uint8_t * addr); +  inline void getMACAddress(uint8_t * addr); + +  inline void setIPAddress(uint8_t * addr); +  inline void getIPAddress(uint8_t * addr); + +  inline void setRetransmissionTime(uint16_t timeout); +  inline void setRetransmissionCount(uint8_t _retry); + +  void execCmdSn(SOCKET s, SockCMD _cmd); +   +  uint16_t getTXFreeSize(SOCKET s); +  uint16_t getRXReceivedSize(SOCKET s); +   + +  // W5100 Registers +  // --------------- +private: +  static uint8_t write(uint16_t _addr, uint8_t _data); +  static uint16_t write(uint16_t addr, const uint8_t *buf, uint16_t len); +  static uint8_t read(uint16_t addr); +  static uint16_t read(uint16_t addr, uint8_t *buf, uint16_t len); +   +#define __GP_REGISTER8(name, address)             \ +  static inline void write##name(uint8_t _data) { \ +    write(address, _data);                        \ +  }                                               \ +  static inline uint8_t read##name() {            \ +    return read(address);                         \ +  } +#define __GP_REGISTER16(name, address)            \ +  static void write##name(uint16_t _data) {       \ +    write(address,   _data >> 8);                 \ +    write(address+1, _data & 0xFF);               \ +  }                                               \ +  static uint16_t read##name() {                  \ +    uint16_t res = read(address);                 \ +    res = (res << 8) + read(address + 1);         \ +    return res;                                   \ +  } +#define __GP_REGISTER_N(name, address, size)      \ +  static uint16_t write##name(uint8_t *_buff) {   \ +    return write(address, _buff, size);           \ +  }                                               \ +  static uint16_t read##name(uint8_t *_buff) {    \ +    return read(address, _buff, size);            \ +  } + +public: +  __GP_REGISTER8 (MR,     0x0000);    // Mode +  __GP_REGISTER_N(GAR,    0x0001, 4); // Gateway IP address +  __GP_REGISTER_N(SUBR,   0x0005, 4); // Subnet mask address +  __GP_REGISTER_N(SHAR,   0x0009, 6); // Source MAC address +  __GP_REGISTER_N(SIPR,   0x000F, 4); // Source IP address +  __GP_REGISTER8 (IR,     0x0015);    // Interrupt +  __GP_REGISTER8 (IMR,    0x0016);    // Interrupt Mask +  __GP_REGISTER16(RTR,    0x0017);    // Timeout address +  __GP_REGISTER8 (RCR,    0x0019);    // Retry count +  __GP_REGISTER8 (RMSR,   0x001A);    // Receive memory size +  __GP_REGISTER8 (TMSR,   0x001B);    // Transmit memory size +  __GP_REGISTER8 (PATR,   0x001C);    // Authentication type address in PPPoE mode +  __GP_REGISTER8 (PTIMER, 0x0028);    // PPP LCP Request Timer +  __GP_REGISTER8 (PMAGIC, 0x0029);    // PPP LCP Magic Number +  __GP_REGISTER_N(UIPR,   0x002A, 4); // Unreachable IP address in UDP mode +  __GP_REGISTER16(UPORT,  0x002E);    // Unreachable Port address in UDP mode +   +#undef __GP_REGISTER8 +#undef __GP_REGISTER16 +#undef __GP_REGISTER_N + +  // W5100 Socket registers +  // ---------------------- +private: +  static inline uint8_t readSn(SOCKET _s, uint16_t _addr); +  static inline uint8_t writeSn(SOCKET _s, uint16_t _addr, uint8_t _data); +  static inline uint16_t readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); +  static inline uint16_t writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t len); + +  static const uint16_t CH_BASE = 0x0400; +  static const uint16_t CH_SIZE = 0x0100; + +#define __SOCKET_REGISTER8(name, address)                    \ +  static inline void write##name(SOCKET _s, uint8_t _data) { \ +    writeSn(_s, address, _data);                             \ +  }                                                          \ +  static inline uint8_t read##name(SOCKET _s) {              \ +    return readSn(_s, address);                              \ +  } +#define __SOCKET_REGISTER16(name, address)                   \ +  static void write##name(SOCKET _s, uint16_t _data) {       \ +    writeSn(_s, address,   _data >> 8);                      \ +    writeSn(_s, address+1, _data & 0xFF);                    \ +  }                                                          \ +  static uint16_t read##name(SOCKET _s) {                    \ +    uint16_t res = readSn(_s, address);                      \ +    uint16_t res2 = readSn(_s,address + 1);                  \ +    res = res << 8;                                          \ +    res2 = res2 & 0xFF;                                      \ +    res = res | res2;                                        \ +    return res;                                              \ +  } +#define __SOCKET_REGISTER_N(name, address, size)             \ +  static uint16_t write##name(SOCKET _s, uint8_t *_buff) {   \ +    return writeSn(_s, address, _buff, size);                \ +  }                                                          \ +  static uint16_t read##name(SOCKET _s, uint8_t *_buff) {    \ +    return readSn(_s, address, _buff, size);                 \ +  } +   +public: +  __SOCKET_REGISTER8(SnMR,        0x0000)        // Mode +  __SOCKET_REGISTER8(SnCR,        0x0001)        // Command +  __SOCKET_REGISTER8(SnIR,        0x0002)        // Interrupt +  __SOCKET_REGISTER8(SnSR,        0x0003)        // Status +  __SOCKET_REGISTER16(SnPORT,     0x0004)        // Source Port +  __SOCKET_REGISTER_N(SnDHAR,     0x0006, 6)     // Destination Hardw Addr +  __SOCKET_REGISTER_N(SnDIPR,     0x000C, 4)     // Destination IP Addr +  __SOCKET_REGISTER16(SnDPORT,    0x0010)        // Destination Port +  __SOCKET_REGISTER16(SnMSSR,     0x0012)        // Max Segment Size +  __SOCKET_REGISTER8(SnPROTO,     0x0014)        // Protocol in IP RAW Mode +  __SOCKET_REGISTER8(SnTOS,       0x0015)        // IP TOS +  __SOCKET_REGISTER8(SnTTL,       0x0016)        // IP TTL +  __SOCKET_REGISTER16(SnTX_FSR,   0x0020)        // TX Free Size +  __SOCKET_REGISTER16(SnTX_RD,    0x0022)        // TX Read Pointer +  __SOCKET_REGISTER16(SnTX_WR,    0x0024)        // TX Write Pointer +  __SOCKET_REGISTER16(SnRX_RSR,   0x0026)        // RX Free Size +  __SOCKET_REGISTER16(SnRX_RD,    0x0028)        // RX Read Pointer +  __SOCKET_REGISTER16(SnRX_WR,    0x002A)        // RX Write Pointer (supported?) +   +#undef __SOCKET_REGISTER8 +#undef __SOCKET_REGISTER16 +#undef __SOCKET_REGISTER_N + + +private: +  static const uint8_t  RST = 7; // Reset BIT + +  static const int SOCKETS = 4; +  static const uint16_t SMASK = 0x07FF; // Tx buffer MASK +  static const uint16_t RMASK = 0x07FF; // Rx buffer MASK +public: +  static const uint16_t SSIZE = 2048; // Max Tx buffer size +private: +  static const uint16_t RSIZE = 2048; // Max Rx buffer size +  uint16_t SBASE[SOCKETS]; // Tx buffer base address +  uint16_t RBASE[SOCKETS]; // Rx buffer base address + +private: +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +  inline static void initSS()    { DDRB  |=  _BV(4); }; +  inline static void setSS()     { PORTB &= ~_BV(4); }; +  inline static void resetSS()   { PORTB |=  _BV(4); }; +#elif defined(__AVR_ATmega32U4__) +  inline static void initSS()    { DDRB  |=  _BV(6); }; +  inline static void setSS()     { PORTB &= ~_BV(6); }; +  inline static void resetSS()   { PORTB |=  _BV(6); };  +#elif defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB162__) +  inline static void initSS()    { DDRB  |=  _BV(0); }; +  inline static void setSS()     { PORTB &= ~_BV(0); }; +  inline static void resetSS()   { PORTB |=  _BV(0); };  +#else +  inline static void initSS()    { DDRB  |=  _BV(2); }; +  inline static void setSS()     { PORTB &= ~_BV(2); }; +  inline static void resetSS()   { PORTB |=  _BV(2); }; +#endif + +}; + +extern W5100Class W5100; + +uint8_t W5100Class::readSn(SOCKET _s, uint16_t _addr) { +  return read(CH_BASE + _s * CH_SIZE + _addr); +} + +uint8_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t _data) { +  return write(CH_BASE + _s * CH_SIZE + _addr, _data); +} + +uint16_t W5100Class::readSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { +  return read(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +uint16_t W5100Class::writeSn(SOCKET _s, uint16_t _addr, uint8_t *_buf, uint16_t _len) { +  return write(CH_BASE + _s * CH_SIZE + _addr, _buf, _len); +} + +void W5100Class::getGatewayIp(uint8_t *_addr) { +  readGAR(_addr); +} + +void W5100Class::setGatewayIp(uint8_t *_addr) { +  writeGAR(_addr); +} + +void W5100Class::getSubnetMask(uint8_t *_addr) { +  readSUBR(_addr); +} + +void W5100Class::setSubnetMask(uint8_t *_addr) { +  writeSUBR(_addr); +} + +void W5100Class::getMACAddress(uint8_t *_addr) { +  readSHAR(_addr); +} + +void W5100Class::setMACAddress(uint8_t *_addr) { +  writeSHAR(_addr); +} + +void W5100Class::getIPAddress(uint8_t *_addr) { +  readSIPR(_addr); +} + +void W5100Class::setIPAddress(uint8_t *_addr) { +  writeSIPR(_addr); +} + +void W5100Class::setRetransmissionTime(uint16_t _timeout) { +  writeRTR(_timeout); +} + +void W5100Class::setRetransmissionCount(uint8_t _retry) { +  writeRCR(_retry); +} + +#endif diff --git a/libraries/Firmata/Boards.h b/libraries/Firmata/Boards.h new file mode 100644 index 0000000..06f69c6 --- /dev/null +++ b/libraries/Firmata/Boards.h @@ -0,0 +1,366 @@ +/* Boards.h - Hardware Abstraction Layer for Firmata library */ + +#ifndef Firmata_Boards_h +#define Firmata_Boards_h + +#include <inttypes.h> + +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h"	// for digitalRead, digitalWrite, etc +#else +#include "WProgram.h" +#endif + +// Normally Servo.h must be included before Firmata.h (which then includes +// this file).  If Servo.h wasn't included, this allows the code to still +// compile, but without support for any Servos.  Hopefully that's what the +// user intended by not including Servo.h +#ifndef MAX_SERVOS +#define MAX_SERVOS 0 +#endif + +/* +    Firmata Hardware Abstraction Layer + +Firmata is built on top of the hardware abstraction functions of Arduino, +specifically digitalWrite, digitalRead, analogWrite, analogRead, and  +pinMode.  While these functions offer simple integer pin numbers, Firmata +needs more information than is provided by Arduino.  This file provides +all other hardware specific details.  To make Firmata support a new board, +only this file should require editing. + +The key concept is every "pin" implemented by Firmata may be mapped to +any pin as implemented by Arduino.  Usually a simple 1-to-1 mapping is +best, but such mapping should not be assumed.  This hardware abstraction +layer allows Firmata to implement any number of pins which map onto the +Arduino implemented pins in almost any arbitrary way. + + +General Constants: + +These constants provide basic information Firmata requires. + +TOTAL_PINS: The total number of pins Firmata implemented by Firmata. +    Usually this will match the number of pins the Arduino functions +    implement, including any pins pins capable of analog or digital. +    However, Firmata may implement any number of pins.  For example, +    on Arduino Mini with 8 analog inputs, 6 of these may be used +    for digital functions, and 2 are analog only.  On such boards, +    Firmata can implement more pins than Arduino's pinMode() +    function, in order to accommodate those special pins.  The +    Firmata protocol supports a maximum of 128 pins, so this +    constant must not exceed 128. + +TOTAL_ANALOG_PINS: The total number of analog input pins implemented. +    The Firmata protocol allows up to 16 analog inputs, accessed +    using offsets 0 to 15.  Because Firmata presents the analog +    inputs using different offsets than the actual pin numbers +    (a legacy of Arduino's analogRead function, and the way the +    analog input capable pins are physically labeled on all +    Arduino boards), the total number of analog input signals +    must be specified.  16 is the maximum. + +VERSION_BLINK_PIN: When Firmata starts up, it will blink the version +    number.  This constant is the Arduino pin number where a +    LED is connected. + + +Pin Mapping Macros: + +These macros provide the mapping between pins as implemented by +Firmata protocol and the actual pin numbers used by the Arduino +functions.  Even though such mappings are often simple, pin +numbers received by Firmata protocol should always be used as +input to these macros, and the result of the macro should be +used with with any Arduino function. + +When Firmata is extended to support a new pin mode or feature, +a pair of macros should be added and used for all hardware +access.  For simple 1:1 mapping, these macros add no actual +overhead, yet their consistent use allows source code which +uses them consistently to be easily adapted to all other boards +with different requirements. + +IS_PIN_XXXX(pin): The IS_PIN macros resolve to true or non-zero +    if a pin as implemented by Firmata corresponds to a pin +    that actually implements the named feature. + +PIN_TO_XXXX(pin): The PIN_TO macros translate pin numbers as +    implemented by Firmata to the pin numbers needed as inputs +    to the Arduino functions.  The corresponding IS_PIN macro +    should always be tested before using a PIN_TO macro, so +    these macros only need to handle valid Firmata pin +    numbers for the named feature. + + +Port Access Inline Funtions: + +For efficiency, Firmata protocol provides access to digital +input and output pins grouped by 8 bit ports.  When these +groups of 8 correspond to actual 8 bit ports as implemented +by the hardware, these inline functions can provide high +speed direct port access.  Otherwise, a default implementation +using 8 calls to digitalWrite or digitalRead is used. + +When porting Firmata to a new board, it is recommended to +use the default functions first and focus only on the constants +and macros above.  When those are working, if optimized port +access is desired, these inline functions may be extended. +The recommended approach defines a symbol indicating which +optimization to use, and then conditional complication is +used within these functions. + +readPort(port, bitmask):  Read an 8 bit port, returning the value. +   port:    The port number, Firmata pins port*8 to port*8+7 +   bitmask: The actual pins to read, indicated by 1 bits. + +writePort(port, value, bitmask):  Write an 8 bit port. +   port:    The port number, Firmata pins port*8 to port*8+7 +   value:   The 8 bit value to write +   bitmask: The actual pins to write, indicated by 1 bits. +*/ + +/*============================================================================== + * Board Specific Configuration + *============================================================================*/ + +#ifndef digitalPinHasPWM +#define digitalPinHasPWM(p)     IS_PIN_DIGITAL(p) +#endif + +// Arduino Duemilanove, Diecimila, and NG +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +#if defined(NUM_ANALOG_INPUTS) && NUM_ANALOG_INPUTS == 6 +#define TOTAL_ANALOG_PINS       6 +#define TOTAL_PINS              20 // 14 digital + 6 analog +#else +#define TOTAL_ANALOG_PINS       8 +#define TOTAL_PINS              22 // 14 digital + 8 analog +#endif +#define VERSION_BLINK_PIN       13 +#define IS_PIN_DIGITAL(p)       ((p) >= 2 && (p) <= 19) +#define IS_PIN_ANALOG(p)        ((p) >= 14 && (p) < 14 + TOTAL_ANALOG_PINS) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 18 || (p) == 19) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 14) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         ((p) - 2) +#define ARDUINO_PINOUT_OPTIMIZE 1 + + +// Wiring (and board) +#elif defined(WIRING) +#define VERSION_BLINK_PIN       WLED +#define IS_PIN_DIGITAL(p)       ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= FIRST_ANALOG_PIN && (p) < (FIRST_ANALOG_PIN+TOTAL_ANALOG_PINS)) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == SDA || (p) == SCL) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - FIRST_ANALOG_PIN) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         (p)  + + +// old Arduinos +#elif defined(__AVR_ATmega8__) +#define TOTAL_ANALOG_PINS       6 +#define TOTAL_PINS              20 // 14 digital + 6 analog +#define VERSION_BLINK_PIN       13 +#define IS_PIN_DIGITAL(p)       ((p) >= 2 && (p) <= 19) +#define IS_PIN_ANALOG(p)        ((p) >= 14 && (p) <= 19) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         (IS_PIN_DIGITAL(p) && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 18 || (p) == 19) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 14) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         ((p) - 2) +#define ARDUINO_PINOUT_OPTIMIZE 1 + + +// Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define TOTAL_ANALOG_PINS       16 +#define TOTAL_PINS              70 // 54 digital + 16 analog +#define VERSION_BLINK_PIN       13 +#define IS_PIN_DIGITAL(p)       ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= 54 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 2 && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 20 || (p) == 21) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 54) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         ((p) - 2) + + +// Teensy 1.0 +#elif defined(__AVR_AT90USB162__) +#define TOTAL_ANALOG_PINS       0 +#define TOTAL_PINS              21 // 21 digital + no analog +#define VERSION_BLINK_PIN       6 +#define IS_PIN_DIGITAL(p)       ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        (0) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           (0) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        (0) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         (p) + + +// Teensy 2.0 +#elif defined(__AVR_ATmega32U4__) +#define TOTAL_ANALOG_PINS       12 +#define TOTAL_PINS              25 // 11 digital + 12 analog +#define VERSION_BLINK_PIN       11 +#define IS_PIN_DIGITAL(p)       ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= 11 && (p) <= 22) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 5 || (p) == 6) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        (((p)<22)?21-(p):11) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         (p) + + +// Teensy++ 1.0 and 2.0 +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +#define TOTAL_ANALOG_PINS       8 +#define TOTAL_PINS              46 // 38 digital + 8 analog +#define VERSION_BLINK_PIN       6 +#define IS_PIN_DIGITAL(p)       ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= 38 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 0 || (p) == 1) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 38) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         (p) + + +// Sanguino +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) +#define TOTAL_ANALOG_PINS       8 +#define TOTAL_PINS              32 // 24 digital + 8 analog +#define VERSION_BLINK_PIN       0 +#define IS_PIN_DIGITAL(p)       ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= 24 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 16 || (p) == 17) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 24) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         ((p) - 2) + + +// Illuminato +#elif defined(__AVR_ATmega645__) +#define TOTAL_ANALOG_PINS       6 +#define TOTAL_PINS              42 // 36 digital + 6 analog +#define VERSION_BLINK_PIN       13 +#define IS_PIN_DIGITAL(p)       ((p) >= 2 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p)        ((p) >= 36 && (p) < TOTAL_PINS) +#define IS_PIN_PWM(p)           digitalPinHasPWM(p) +#define IS_PIN_SERVO(p)         ((p) >= 0 && (p) < MAX_SERVOS) +#define IS_PIN_I2C(p)           ((p) == 4 || (p) == 5) +#define PIN_TO_DIGITAL(p)       (p) +#define PIN_TO_ANALOG(p)        ((p) - 36) +#define PIN_TO_PWM(p)           PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p)         ((p) - 2) + + +// anything else +#else +#error "Please edit Boards.h with a hardware abstraction for this board" +#endif + + +/*============================================================================== + * readPort() - Read an 8 bit port + *============================================================================*/ + +static inline unsigned char readPort(byte, byte) __attribute__((always_inline, unused)); +static inline unsigned char readPort(byte port, byte bitmask) +{ +#if defined(ARDUINO_PINOUT_OPTIMIZE) +	if (port == 0) return (PIND & 0xFC) & bitmask; // ignore Rx/Tx 0/1 +	if (port == 1) return ((PINB & 0x3F) | ((PINC & 0x03) << 6)) & bitmask; +	if (port == 2) return ((PINC & 0x3C) >> 2) & bitmask; +	return 0; +#else +	unsigned char out=0, pin=port*8; +	if (IS_PIN_DIGITAL(pin+0) && (bitmask & 0x01) && digitalRead(PIN_TO_DIGITAL(pin+0))) out |= 0x01; +	if (IS_PIN_DIGITAL(pin+1) && (bitmask & 0x02) && digitalRead(PIN_TO_DIGITAL(pin+1))) out |= 0x02; +	if (IS_PIN_DIGITAL(pin+2) && (bitmask & 0x04) && digitalRead(PIN_TO_DIGITAL(pin+2))) out |= 0x04; +	if (IS_PIN_DIGITAL(pin+3) && (bitmask & 0x08) && digitalRead(PIN_TO_DIGITAL(pin+3))) out |= 0x08; +	if (IS_PIN_DIGITAL(pin+4) && (bitmask & 0x10) && digitalRead(PIN_TO_DIGITAL(pin+4))) out |= 0x10; +	if (IS_PIN_DIGITAL(pin+5) && (bitmask & 0x20) && digitalRead(PIN_TO_DIGITAL(pin+5))) out |= 0x20; +	if (IS_PIN_DIGITAL(pin+6) && (bitmask & 0x40) && digitalRead(PIN_TO_DIGITAL(pin+6))) out |= 0x40; +	if (IS_PIN_DIGITAL(pin+7) && (bitmask & 0x80) && digitalRead(PIN_TO_DIGITAL(pin+7))) out |= 0x80; +	return out; +#endif +} + +/*============================================================================== + * writePort() - Write an 8 bit port, only touch pins specified by a bitmask + *============================================================================*/ + +static inline unsigned char writePort(byte, byte, byte) __attribute__((always_inline, unused)); +static inline unsigned char writePort(byte port, byte value, byte bitmask) +{ +#if defined(ARDUINO_PINOUT_OPTIMIZE) +	if (port == 0) { +		bitmask = bitmask & 0xFC;  // do not touch Tx & Rx pins +		byte valD = value & bitmask; +		byte maskD = ~bitmask; +		cli(); +		PORTD = (PORTD & maskD) | valD; +		sei(); +	} else if (port == 1) { +		byte valB = (value & bitmask) & 0x3F; +		byte valC = (value & bitmask) >> 6; +		byte maskB = ~(bitmask & 0x3F); +		byte maskC = ~((bitmask & 0xC0) >> 6); +		cli(); +		PORTB = (PORTB & maskB) | valB; +		PORTC = (PORTC & maskC) | valC; +		sei(); +	} else if (port == 2) { +		bitmask = bitmask & 0x0F; +		byte valC = (value & bitmask) << 2; +		byte maskC = ~(bitmask << 2); +		cli(); +		PORTC = (PORTC & maskC) | valC; +		sei(); +	} +#else +	byte pin=port*8; +	if ((bitmask & 0x01)) digitalWrite(PIN_TO_DIGITAL(pin+0), (value & 0x01)); +	if ((bitmask & 0x02)) digitalWrite(PIN_TO_DIGITAL(pin+1), (value & 0x02)); +	if ((bitmask & 0x04)) digitalWrite(PIN_TO_DIGITAL(pin+2), (value & 0x04)); +	if ((bitmask & 0x08)) digitalWrite(PIN_TO_DIGITAL(pin+3), (value & 0x08)); +	if ((bitmask & 0x10)) digitalWrite(PIN_TO_DIGITAL(pin+4), (value & 0x10)); +	if ((bitmask & 0x20)) digitalWrite(PIN_TO_DIGITAL(pin+5), (value & 0x20)); +	if ((bitmask & 0x40)) digitalWrite(PIN_TO_DIGITAL(pin+6), (value & 0x40)); +	if ((bitmask & 0x80)) digitalWrite(PIN_TO_DIGITAL(pin+7), (value & 0x80)); +#endif +} + + + + +#ifndef TOTAL_PORTS +#define TOTAL_PORTS             ((TOTAL_PINS + 7) / 8) +#endif + + +#endif /* Firmata_Boards_h */ + diff --git a/libraries/Firmata/Firmata.cpp b/libraries/Firmata/Firmata.cpp new file mode 100644 index 0000000..e81c10b --- /dev/null +++ b/libraries/Firmata/Firmata.cpp @@ -0,0 +1,444 @@ +/* +  Firmata.cpp - Firmata library +  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved. +  +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  See file LICENSE.txt for further informations on licensing terms. +*/ + +//****************************************************************************** +//* Includes +//****************************************************************************** + +#include "Firmata.h" +#include "HardwareSerial.h" + +extern "C" { +#include <string.h> +#include <stdlib.h> +} + +//****************************************************************************** +//* Support Functions +//****************************************************************************** + +void FirmataClass::sendValueAsTwo7bitBytes(int value) +{ +  FirmataSerial.write(value & B01111111); // LSB +  FirmataSerial.write(value >> 7 & B01111111); // MSB +} + +void FirmataClass::startSysex(void) +{ +  FirmataSerial.write(START_SYSEX); +} + +void FirmataClass::endSysex(void) +{ +  FirmataSerial.write(END_SYSEX); +} + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +FirmataClass::FirmataClass(Stream &s) : FirmataSerial(s) +{ +  firmwareVersionCount = 0; +  systemReset(); +} + +//****************************************************************************** +//* Public Methods +//****************************************************************************** + +/* begin method for overriding default serial bitrate */ +void FirmataClass::begin(void) +{ +  begin(57600); +} + +/* begin method for overriding default serial bitrate */ +void FirmataClass::begin(long speed) +{ +  Serial.begin(speed); +  FirmataSerial = Serial; +  blinkVersion(); +  printVersion(); +  printFirmwareVersion(); +} + +void FirmataClass::begin(Stream &s) +{ +  FirmataSerial = s; +  systemReset(); +  printVersion(); +  printFirmwareVersion(); +} + +// output the protocol version message to the serial port +void FirmataClass::printVersion(void) { +  FirmataSerial.write(REPORT_VERSION); +  FirmataSerial.write(FIRMATA_MAJOR_VERSION); +  FirmataSerial.write(FIRMATA_MINOR_VERSION); +} + +void FirmataClass::blinkVersion(void) +{ +  // flash the pin with the protocol version +  pinMode(VERSION_BLINK_PIN,OUTPUT); +  pin13strobe(FIRMATA_MAJOR_VERSION, 40, 210); +  delay(250); +  pin13strobe(FIRMATA_MINOR_VERSION, 40, 210); +  delay(125); +} + +void FirmataClass::printFirmwareVersion(void) +{ +  byte i; + +  if(firmwareVersionCount) { // make sure that the name has been set before reporting +    startSysex(); +    FirmataSerial.write(REPORT_FIRMWARE); +    FirmataSerial.write(firmwareVersionVector[0]); // major version number +    FirmataSerial.write(firmwareVersionVector[1]); // minor version number +    for(i=2; i<firmwareVersionCount; ++i) { +      sendValueAsTwo7bitBytes(firmwareVersionVector[i]); +    } +    endSysex(); +  } +} + +void FirmataClass::setFirmwareNameAndVersion(const char *name, byte major, byte minor) +{ +  const char *filename; +  char *extension; + +  // parse out ".cpp" and "applet/" that comes from using __FILE__ +  extension = strstr(name, ".cpp"); +  filename = strrchr(name, '/') + 1; //points to slash, +1 gets to start of filename +  // add two bytes for version numbers +  if(extension && filename) { +    firmwareVersionCount = extension - filename + 2; +  } else { +    firmwareVersionCount = strlen(name) + 2; +    filename = name; +  } +  firmwareVersionVector = (byte *) malloc(firmwareVersionCount); +  firmwareVersionVector[firmwareVersionCount] = 0; +  firmwareVersionVector[0] = major; +  firmwareVersionVector[1] = minor; +  strncpy((char*)firmwareVersionVector + 2, filename, firmwareVersionCount - 2); +  // alas, no snprintf on Arduino +  //    snprintf(firmwareVersionVector, MAX_DATA_BYTES, "%c%c%s",  +  //             (char)major, (char)minor, firmwareVersionVector); +} + +//------------------------------------------------------------------------------ +// Serial Receive Handling + +int FirmataClass::available(void) +{ +  return FirmataSerial.available(); +} + + +void FirmataClass::processSysexMessage(void) +{ +  switch(storedInputData[0]) { //first byte in buffer is command +  case REPORT_FIRMWARE: +    printFirmwareVersion(); +    break; +  case STRING_DATA: +    if(currentStringCallback) { +      byte bufferLength = (sysexBytesRead - 1) / 2; +      char *buffer = (char*)malloc(bufferLength * sizeof(char)); +      byte i = 1; +      byte j = 0; +      while(j < bufferLength) { +        buffer[j] = (char)storedInputData[i]; +        i++; +        buffer[j] += (char)(storedInputData[i] << 7); +        i++; +        j++; +      } +      (*currentStringCallback)(buffer); +    } +    break; +  default: +    if(currentSysexCallback) +      (*currentSysexCallback)(storedInputData[0], sysexBytesRead - 1, storedInputData + 1); +  } +} + +void FirmataClass::processInput(void) +{ +  int inputData = FirmataSerial.read(); // this is 'int' to handle -1 when no data +  int command; +     +  // TODO make sure it handles -1 properly + +  if (parsingSysex) { +    if(inputData == END_SYSEX) { +      //stop sysex byte       +      parsingSysex = false; +      //fire off handler function +      processSysexMessage(); +    } else { +      //normal data byte - add to buffer +      storedInputData[sysexBytesRead] = inputData; +      sysexBytesRead++; +    } +  } else if( (waitForData > 0) && (inputData < 128) ) {   +    waitForData--; +    storedInputData[waitForData] = inputData; +    if( (waitForData==0) && executeMultiByteCommand ) { // got the whole message +      switch(executeMultiByteCommand) { +      case ANALOG_MESSAGE: +        if(currentAnalogCallback) { +          (*currentAnalogCallback)(multiByteChannel, +                                   (storedInputData[0] << 7) +                                   + storedInputData[1]); +        } +        break; +      case DIGITAL_MESSAGE: +        if(currentDigitalCallback) { +          (*currentDigitalCallback)(multiByteChannel, +                                    (storedInputData[0] << 7) +                                    + storedInputData[1]); +        } +        break; +      case SET_PIN_MODE: +        if(currentPinModeCallback) +          (*currentPinModeCallback)(storedInputData[1], storedInputData[0]); +        break; +      case REPORT_ANALOG: +        if(currentReportAnalogCallback) +          (*currentReportAnalogCallback)(multiByteChannel,storedInputData[0]); +        break; +      case REPORT_DIGITAL: +        if(currentReportDigitalCallback) +          (*currentReportDigitalCallback)(multiByteChannel,storedInputData[0]); +        break; +      } +      executeMultiByteCommand = 0; +    }	 +  } else { +    // remove channel info from command byte if less than 0xF0 +    if(inputData < 0xF0) { +      command = inputData & 0xF0; +      multiByteChannel = inputData & 0x0F; +    } else { +      command = inputData; +      // commands in the 0xF* range don't use channel data +    } +    switch (command) { +    case ANALOG_MESSAGE: +    case DIGITAL_MESSAGE: +    case SET_PIN_MODE: +      waitForData = 2; // two data bytes needed +      executeMultiByteCommand = command; +      break; +    case REPORT_ANALOG: +    case REPORT_DIGITAL: +      waitForData = 1; // two data bytes needed +      executeMultiByteCommand = command; +      break; +    case START_SYSEX: +      parsingSysex = true; +      sysexBytesRead = 0; +      break; +    case SYSTEM_RESET: +      systemReset(); +      break; +    case REPORT_VERSION: +      Firmata.printVersion(); +      break; +    } +  } +} + +//------------------------------------------------------------------------------ +// Serial Send Handling + +// send an analog message +void FirmataClass::sendAnalog(byte pin, int value)  +{ +  // pin can only be 0-15, so chop higher bits +  FirmataSerial.write(ANALOG_MESSAGE | (pin & 0xF)); +  sendValueAsTwo7bitBytes(value); +} + +// send a single digital pin in a digital message +void FirmataClass::sendDigital(byte pin, int value)  +{ +  /* TODO add single pin digital messages to the protocol, this needs to +   * track the last digital data sent so that it can be sure to change just +   * one bit in the packet.  This is complicated by the fact that the +   * numbering of the pins will probably differ on Arduino, Wiring, and +   * other boards.  The DIGITAL_MESSAGE sends 14 bits at a time, but it is +   * probably easier to send 8 bit ports for any board with more than 14 +   * digital pins. +   */ + +  // TODO: the digital message should not be sent on the serial port every +  // time sendDigital() is called.  Instead, it should add it to an int +  // which will be sent on a schedule.  If a pin changes more than once +  // before the digital message is sent on the serial port, it should send a +  // digital message for each change. + +  //    if(value == 0) +  //        sendDigitalPortPair(); +} + + +// send 14-bits in a single digital message (protocol v1) +// send an 8-bit port in a single digital message (protocol v2) +void FirmataClass::sendDigitalPort(byte portNumber, int portData) +{ +  FirmataSerial.write(DIGITAL_MESSAGE | (portNumber & 0xF)); +  FirmataSerial.write((byte)portData % 128); // Tx bits 0-6 +  FirmataSerial.write(portData >> 7);  // Tx bits 7-13 +} + + +void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev)  +{ +  byte i; +  startSysex(); +  FirmataSerial.write(command); +  for(i=0; i<bytec; i++) { +    sendValueAsTwo7bitBytes(bytev[i]);         +  } +  endSysex(); +} + +void FirmataClass::sendString(byte command, const char* string)  +{ +  sendSysex(command, strlen(string), (byte *)string); +} + + +// send a string as the protocol string type +void FirmataClass::sendString(const char* string)  +{ +  sendString(STRING_DATA, string); +} + + +// Internal Actions///////////////////////////////////////////////////////////// + +// generic callbacks +void FirmataClass::attach(byte command, callbackFunction newFunction) +{ +  switch(command) { +  case ANALOG_MESSAGE: currentAnalogCallback = newFunction; break; +  case DIGITAL_MESSAGE: currentDigitalCallback = newFunction; break; +  case REPORT_ANALOG: currentReportAnalogCallback = newFunction; break; +  case REPORT_DIGITAL: currentReportDigitalCallback = newFunction; break; +  case SET_PIN_MODE: currentPinModeCallback = newFunction; break; +  } +} + +void FirmataClass::attach(byte command, systemResetCallbackFunction newFunction) +{ +  switch(command) { +  case SYSTEM_RESET: currentSystemResetCallback = newFunction; break; +  } +} + +void FirmataClass::attach(byte command, stringCallbackFunction newFunction) +{ +  switch(command) { +  case STRING_DATA: currentStringCallback = newFunction; break; +  } +} + +void FirmataClass::attach(byte command, sysexCallbackFunction newFunction) +{ +  currentSysexCallback = newFunction; +} + +void FirmataClass::detach(byte command) +{ +  switch(command) { +  case SYSTEM_RESET: currentSystemResetCallback = NULL; break; +  case STRING_DATA: currentStringCallback = NULL; break; +  case START_SYSEX: currentSysexCallback = NULL; break; +  default: +    attach(command, (callbackFunction)NULL); +  } +} + +// sysex callbacks +/* + * this is too complicated for analogReceive, but maybe for Sysex? + void FirmataClass::attachSysex(sysexFunction newFunction) + { + byte i; + byte tmpCount = analogReceiveFunctionCount; + analogReceiveFunction* tmpArray = analogReceiveFunctionArray; + analogReceiveFunctionCount++; + analogReceiveFunctionArray = (analogReceiveFunction*) calloc(analogReceiveFunctionCount, sizeof(analogReceiveFunction)); + for(i = 0; i < tmpCount; i++) { + analogReceiveFunctionArray[i] = tmpArray[i]; + } + analogReceiveFunctionArray[tmpCount] = newFunction; + free(tmpArray); + } +*/ + +//****************************************************************************** +//* Private Methods +//****************************************************************************** + + + +// resets the system state upon a SYSTEM_RESET message from the host software +void FirmataClass::systemReset(void) +{ +  byte i; + +  waitForData = 0; // this flag says the next serial input will be data +  executeMultiByteCommand = 0; // execute this after getting multi-byte data +  multiByteChannel = 0; // channel data for multiByteCommands + + +  for(i=0; i<MAX_DATA_BYTES; i++) { +    storedInputData[i] = 0; +  } + +  parsingSysex = false; +  sysexBytesRead = 0; + +  if(currentSystemResetCallback) +    (*currentSystemResetCallback)(); + +  //flush(); //TODO uncomment when Firmata is a subclass of HardwareSerial +} + + + +// ============================================================================= +// used for flashing the pin for the version number +void FirmataClass::pin13strobe(int count, int onInterval, int offInterval)  +{ +  byte i; +  pinMode(VERSION_BLINK_PIN, OUTPUT); +  for(i=0; i<count; i++) { +    delay(offInterval); +    digitalWrite(VERSION_BLINK_PIN, HIGH); +    delay(onInterval); +    digitalWrite(VERSION_BLINK_PIN, LOW); +  } +} + + +// make one instance for the user to use +FirmataClass Firmata(Serial); + + diff --git a/libraries/Firmata/Firmata.h b/libraries/Firmata/Firmata.h new file mode 100644 index 0000000..74f1ccc --- /dev/null +++ b/libraries/Firmata/Firmata.h @@ -0,0 +1,163 @@ +/* +  Firmata.h - Firmata library +  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved. +  +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  See file LICENSE.txt for further informations on licensing terms. +*/ + +#ifndef Firmata_h +#define Firmata_h + +#include "Boards.h"  /* Hardware Abstraction Layer + Wiring/Arduino */ + +/* Version numbers for the protocol.  The protocol is still changing, so these + * version numbers are important.  This number can be queried so that host + * software can test whether it will be compatible with the currently + * installed firmware. */ +#define FIRMATA_MAJOR_VERSION   2 // for non-compatible changes +#define FIRMATA_MINOR_VERSION   3 // for backwards compatible changes +#define FIRMATA_BUGFIX_VERSION  1 // for bugfix releases + +#define MAX_DATA_BYTES 32 // max number of data bytes in non-Sysex messages + +// message command bytes (128-255/0x80-0xFF) +#define DIGITAL_MESSAGE         0x90 // send data for a digital pin +#define ANALOG_MESSAGE          0xE0 // send data for an analog pin (or PWM) +#define REPORT_ANALOG           0xC0 // enable analog input by pin # +#define REPORT_DIGITAL          0xD0 // enable digital input by port pair +// +#define SET_PIN_MODE            0xF4 // set a pin to INPUT/OUTPUT/PWM/etc +// +#define REPORT_VERSION          0xF9 // report protocol version +#define SYSTEM_RESET            0xFF // reset from MIDI +// +#define START_SYSEX             0xF0 // start a MIDI Sysex message +#define END_SYSEX               0xF7 // end a MIDI Sysex message + +// extended command set using sysex (0-127/0x00-0x7F) +/* 0x00-0x0F reserved for user-defined commands */ +#define SERVO_CONFIG            0x70 // set max angle, minPulse, maxPulse, freq +#define STRING_DATA             0x71 // a string message with 14-bits per char +#define SHIFT_DATA              0x75 // a bitstream to/from a shift register +#define I2C_REQUEST             0x76 // send an I2C read/write request +#define I2C_REPLY               0x77 // a reply to an I2C read request +#define I2C_CONFIG              0x78 // config I2C settings such as delay times and power pins +#define EXTENDED_ANALOG         0x6F // analog write (PWM, Servo, etc) to any pin +#define PIN_STATE_QUERY         0x6D // ask for a pin's current mode and value +#define PIN_STATE_RESPONSE      0x6E // reply with pin's current mode and value +#define CAPABILITY_QUERY        0x6B // ask for supported modes and resolution of all pins +#define CAPABILITY_RESPONSE     0x6C // reply with supported modes and resolution +#define ANALOG_MAPPING_QUERY    0x69 // ask for mapping of analog to pin numbers +#define ANALOG_MAPPING_RESPONSE 0x6A // reply with mapping info +#define REPORT_FIRMWARE         0x79 // report name and version of the firmware +#define SAMPLING_INTERVAL       0x7A // set the poll rate of the main loop +#define SYSEX_NON_REALTIME      0x7E // MIDI Reserved for non-realtime messages +#define SYSEX_REALTIME          0x7F // MIDI Reserved for realtime messages +// these are DEPRECATED to make the naming more consistent +#define FIRMATA_STRING          0x71 // same as STRING_DATA +#define SYSEX_I2C_REQUEST       0x76 // same as I2C_REQUEST +#define SYSEX_I2C_REPLY         0x77 // same as I2C_REPLY +#define SYSEX_SAMPLING_INTERVAL 0x7A // same as SAMPLING_INTERVAL + +// pin modes +//#define INPUT                 0x00 // defined in wiring.h +//#define OUTPUT                0x01 // defined in wiring.h +#define ANALOG                  0x02 // analog pin in analogInput mode +#define PWM                     0x03 // digital pin in PWM output mode +#define SERVO                   0x04 // digital pin in Servo output mode +#define SHIFT                   0x05 // shiftIn/shiftOut mode +#define I2C                     0x06 // pin included in I2C setup +#define TOTAL_PIN_MODES         7 + +extern "C" { +// callback function types +    typedef void (*callbackFunction)(byte, int); +    typedef void (*systemResetCallbackFunction)(void); +    typedef void (*stringCallbackFunction)(char*); +    typedef void (*sysexCallbackFunction)(byte command, byte argc, byte*argv); +} + + +// TODO make it a subclass of a generic Serial/Stream base class +class FirmataClass +{ +public: +	FirmataClass(Stream &s); +/* Arduino constructors */ +    void begin(); +    void begin(long); +    void begin(Stream &s); +/* querying functions */ +	void printVersion(void); +    void blinkVersion(void); +    void printFirmwareVersion(void); +  //void setFirmwareVersion(byte major, byte minor);  // see macro below +    void setFirmwareNameAndVersion(const char *name, byte major, byte minor); +/* serial receive handling */ +    int available(void); +    void processInput(void); +/* serial send handling */ +	void sendAnalog(byte pin, int value); +	void sendDigital(byte pin, int value); // TODO implement this +	void sendDigitalPort(byte portNumber, int portData); +    void sendString(const char* string); +    void sendString(byte command, const char* string); +	void sendSysex(byte command, byte bytec, byte* bytev); +/* attach & detach callback functions to messages */ +    void attach(byte command, callbackFunction newFunction); +    void attach(byte command, systemResetCallbackFunction newFunction); +    void attach(byte command, stringCallbackFunction newFunction); +    void attach(byte command, sysexCallbackFunction newFunction); +    void detach(byte command); + +private: +    Stream &FirmataSerial; +/* firmware name and version */ +    byte firmwareVersionCount; +    byte *firmwareVersionVector; +/* input message handling */ +    byte waitForData; // this flag says the next serial input will be data +    byte executeMultiByteCommand; // execute this after getting multi-byte data +    byte multiByteChannel; // channel data for multiByteCommands +    byte storedInputData[MAX_DATA_BYTES]; // multi-byte data +/* sysex */ +    boolean parsingSysex; +    int sysexBytesRead; +/* callback functions */ +    callbackFunction currentAnalogCallback; +    callbackFunction currentDigitalCallback; +    callbackFunction currentReportAnalogCallback; +    callbackFunction currentReportDigitalCallback; +    callbackFunction currentPinModeCallback; +    systemResetCallbackFunction currentSystemResetCallback; +    stringCallbackFunction currentStringCallback; +    sysexCallbackFunction currentSysexCallback; + +/* private methods ------------------------------ */ +    void processSysexMessage(void); +	void systemReset(void); +    void pin13strobe(int count, int onInterval, int offInterval); +    void sendValueAsTwo7bitBytes(int value); +    void startSysex(void); +    void endSysex(void); +}; + +extern FirmataClass Firmata; + +/*============================================================================== + * MACROS + *============================================================================*/ + +/* shortcut for setFirmwareNameAndVersion() that uses __FILE__ to set the + * firmware name.  It needs to be a macro so that __FILE__ is included in the + * firmware source file rather than the library source file. + */ +#define setFirmwareVersion(x, y)   setFirmwareNameAndVersion(__FILE__, x, y) + +#endif /* Firmata_h */ + diff --git a/libraries/Firmata/LICENSE.txt b/libraries/Firmata/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/libraries/Firmata/LICENSE.txt @@ -0,0 +1,458 @@ + +		  GNU LESSER GENERAL PUBLIC LICENSE +		       Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL.  It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +  This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it.  You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + +  When we speak of free software, we are referring to freedom of use, +not price.  Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + +  To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights.  These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + +  For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you.  You must make sure that they, too, receive or can get the source +code.  If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it.  And you must show them these terms so they know their rights. + +  We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +  To protect each distributor, we want to make it very clear that +there is no warranty for the free library.  Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + +  Finally, software patents pose a constant threat to the existence of +any free program.  We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder.  Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + +  Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License.  This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License.  We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + +  When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library.  The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom.  The Lesser General +Public License permits more lax criteria for linking other code with +the library. + +  We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License.  It also provides other free software developers Less +of an advantage over competing non-free programs.  These disadvantages +are the reason we use the ordinary General Public License for many +libraries.  However, the Lesser license provides advantages in certain +special circumstances. + +  For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard.  To achieve this, non-free programs must be +allowed to use the library.  A more frequent case is that a free +library does the same job as widely used non-free libraries.  In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + +  In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software.  For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + +  Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + +  The precise terms and conditions for copying, distribution and +modification follow.  Pay close attention to the difference between a +"work based on the library" and a "work that uses the library".  The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +		  GNU LESSER GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + +  A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +  The "Library", below, refers to any such software library or work +which has been distributed under these terms.  A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language.  (Hereinafter, translation is +included without limitation in the term "modification".) + +  "Source code" for a work means the preferred form of the work for +making modifications to it.  For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +  Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it).  Whether that is true depends on what the Library does +and what the program that uses the Library does. +   +  1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +  You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +  2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) The modified work must itself be a software library. + +    b) You must cause the files modified to carry prominent notices +    stating that you changed the files and the date of any change. + +    c) You must cause the whole of the work to be licensed at no +    charge to all third parties under the terms of this License. + +    d) If a facility in the modified Library refers to a function or a +    table of data to be supplied by an application program that uses +    the facility, other than as an argument passed when the facility +    is invoked, then you must make a good faith effort to ensure that, +    in the event an application does not supply such function or +    table, the facility still operates, and performs whatever part of +    its purpose remains meaningful. + +    (For example, a function in a library to compute square roots has +    a purpose that is entirely well-defined independent of the +    application.  Therefore, Subsection 2d requires that any +    application-supplied function or table used by this function must +    be optional: if the application does not supply it, the square +    root function must still compute square roots.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library.  To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License.  (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.)  Do not make any other change in +these notices. + +  Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +  This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +  4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +  If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +  5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library".  Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +  However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library".  The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +  When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library.  The +threshold for this to be true is not precisely defined by law. + +  If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work.  (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +  Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +  6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +  You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License.  You must supply a copy of this License.  If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License.  Also, you must do one +of these things: + +    a) Accompany the work with the complete corresponding +    machine-readable source code for the Library including whatever +    changes were used in the work (which must be distributed under +    Sections 1 and 2 above); and, if the work is an executable linked +    with the Library, with the complete machine-readable "work that +    uses the Library", as object code and/or source code, so that the +    user can modify the Library and then relink to produce a modified +    executable containing the modified Library.  (It is understood +    that the user who changes the contents of definitions files in the +    Library will not necessarily be able to recompile the application +    to use the modified definitions.) + +    b) Use a suitable shared library mechanism for linking with the +    Library.  A suitable mechanism is one that (1) uses at run time a +    copy of the library already present on the user's computer system, +    rather than copying library functions into the executable, and (2) +    will operate properly with a modified version of the library, if +    the user installs one, as long as the modified version is +    interface-compatible with the version that the work was made with. + +    c) Accompany the work with a written offer, valid for at +    least three years, to give the same user the materials +    specified in Subsection 6a, above, for a charge no more +    than the cost of performing this distribution. + +    d) If distribution of the work is made by offering access to copy +    from a designated place, offer equivalent access to copy the above +    specified materials from the same place. + +    e) Verify that the user has already received a copy of these +    materials or that you have already sent this user a copy. + +  For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it.  However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +  It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system.  Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +  7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +    a) Accompany the combined library with a copy of the same work +    based on the Library, uncombined with any other library +    facilities.  This must be distributed under the terms of the +    Sections above. + +    b) Give prominent notice with the combined library of the fact +    that part of it is a work based on the Library, and explaining +    where to find the accompanying uncombined form of the same work. + +  8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License.  Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License.  However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +  9. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Library or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +  10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + +  11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all.  For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded.  In such case, this License incorporates the limitation as if +written in the body of this License. + +  13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number.  If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation.  If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +  14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission.  For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this.  Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +			    NO WARRANTY + +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/libraries/Firmata/TODO.txt b/libraries/Firmata/TODO.txt new file mode 100644 index 0000000..86c9858 --- /dev/null +++ b/libraries/Firmata/TODO.txt @@ -0,0 +1,14 @@ + +- make Firmata a subclass of HardwareSerial + +- per-pin digital callback, since the per-port callback is a bit complicated +  for beginners (maybe Firmata is not for beginners...) + +- simplify SimpleDigitalFirmata, take out the code that checks to see if the +  data has changed, since it is a bit complicated for this example.  Ideally +  this example would be based on a call + +- turn current SimpleDigitalFirmata into DigitalPortFirmata for a more complex +  example using the code which checks for changes before doing anything + +- test integration with Wiring diff --git a/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino b/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino new file mode 100644 index 0000000..bff7366 --- /dev/null +++ b/libraries/Firmata/examples/AllInputsFirmata/AllInputsFirmata.ino @@ -0,0 +1,90 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/*  + * This firmware reads all inputs and sends them as fast as it can.  It was + * inspired by the ease-of-use of the Arduino2Max program. + * + * This example code is in the public domain. + */ +#include <Firmata.h> + +byte pin; + +int analogValue; +int previousAnalogValues[TOTAL_ANALOG_PINS]; + +byte portStatus[TOTAL_PORTS];	// each bit: 1=pin is digital input, 0=other/ignore +byte previousPINs[TOTAL_PORTS]; + +/* timer variables */ +unsigned long currentMillis;     // store the current value from millis() +unsigned long previousMillis;    // for comparison with currentMillis +/* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you +   get long, random delays.  So only read analogs every 20ms or so */ +int samplingInterval = 19;      // how often to run the main loop (in ms) + +void sendPort(byte portNumber, byte portValue) +{ +  portValue = portValue & portStatus[portNumber]; +  if(previousPINs[portNumber] != portValue) { +    Firmata.sendDigitalPort(portNumber, portValue); +    previousPINs[portNumber] = portValue; +  } +} + +void setup() +{ +  byte i, port, status; + +  Firmata.setFirmwareVersion(0, 1); + +  for(pin = 0; pin < TOTAL_PINS; pin++) { +    if IS_PIN_DIGITAL(pin) pinMode(PIN_TO_DIGITAL(pin), INPUT); +  } + +  for (port=0; port<TOTAL_PORTS; port++) { +    status = 0; +    for (i=0; i<8; i++) { +      if (IS_PIN_DIGITAL(port * 8 + i)) status |= (1 << i); +    } +    portStatus[port] = status; +  } + +  Firmata.begin(57600); +} + +void loop() +{ +  byte i; + +  for (i=0; i<TOTAL_PORTS; i++) { +      sendPort(i, readPort(i, 0xff)); +  } +  /* make sure that the FTDI buffer doesn't go over 60 bytes, otherwise you +     get long, random delays.  So only read analogs every 20ms or so */ +  currentMillis = millis(); +  if(currentMillis - previousMillis > samplingInterval) { +    previousMillis += samplingInterval; +    while(Firmata.available()) { +      Firmata.processInput(); +    } +    for(pin = 0; pin < TOTAL_ANALOG_PINS; pin++) { +      analogValue = analogRead(pin); +      if(analogValue != previousAnalogValues[pin]) { +        Firmata.sendAnalog(pin, analogValue);  +        previousAnalogValues[pin] = analogValue; +      } +    } +  } +} + + diff --git a/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino new file mode 100644 index 0000000..ff1d664 --- /dev/null +++ b/libraries/Firmata/examples/AnalogFirmata/AnalogFirmata.ino @@ -0,0 +1,94 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* This firmware supports as many analog ports as possible, all analog inputs, + * four PWM outputs, and two with servo support. + * + * This example code is in the public domain. + */ +#include <Servo.h> +#include <Firmata.h> + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* servos */ +Servo servo9, servo10; // one instance per pin +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting +int analogPin = 0; // counter for reading analog pins +/* timer variables */ +unsigned long currentMillis;     // store the current value from millis() +unsigned long previousMillis;    // for comparison with currentMillis + + +/*============================================================================== + * FUNCTIONS                                                                 + *============================================================================*/ + +void analogWriteCallback(byte pin, int value) +{ +    switch(pin) { +    case 9: servo9.write(value); break; +    case 10: servo10.write(value); break; +    case 3:  +    case 5:  +    case 6:  +    case 11: // PWM pins +        analogWrite(pin, value);  +        break; +    } +} +// ----------------------------------------------------------------------------- +// sets bits in a bit array (int) to toggle the reporting of the analogIns +void reportAnalogCallback(byte pin, int value) +{ +    if(value == 0) { +        analogInputsToReport = analogInputsToReport &~ (1 << pin); +    } +    else { // everything but 0 enables reporting of that pin +        analogInputsToReport = analogInputsToReport | (1 << pin); +    } +    // TODO: save status to EEPROM here, if changed +} + +/*============================================================================== + * SETUP() + *============================================================================*/ +void setup()  +{ +    Firmata.setFirmwareVersion(0, 2); +    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); +    Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + +    servo9.attach(9); +    servo10.attach(10); +    Firmata.begin(57600); +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop()  +{ +    while(Firmata.available()) +        Firmata.processInput(); +    currentMillis = millis(); +    if(currentMillis - previousMillis > 20) {   +        previousMillis += 20;                   // run this every 20ms +        for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { +            if( analogInputsToReport & (1 << analogPin) )  +                Firmata.sendAnalog(analogPin, analogRead(analogPin)); +        } +    } +} + diff --git a/libraries/Firmata/examples/EchoString/EchoString.ino b/libraries/Firmata/examples/EchoString/EchoString.ino new file mode 100644 index 0000000..5079697 --- /dev/null +++ b/libraries/Firmata/examples/EchoString/EchoString.ino @@ -0,0 +1,46 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* This sketch accepts strings and raw sysex messages and echos them back. + * + * This example code is in the public domain. + */ +#include <Firmata.h> + +byte analogPin; + +void stringCallback(char *myString) +{ +    Firmata.sendString(myString); +} + + +void sysexCallback(byte command, byte argc, byte*argv) +{ +    Firmata.sendSysex(command, argc, argv); +} + +void setup() +{ +    Firmata.setFirmwareVersion(0, 1); +    Firmata.attach(STRING_DATA, stringCallback); +    Firmata.attach(START_SYSEX, sysexCallback); +    Firmata.begin(57600); +} + +void loop() +{ +    while(Firmata.available()) { +        Firmata.processInput(); +    } +} + + diff --git a/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino new file mode 100644 index 0000000..1da8963 --- /dev/null +++ b/libraries/Firmata/examples/I2CFirmata/I2CFirmata.ino @@ -0,0 +1,228 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* + Copyright (C) 2009 Jeff Hoefs.  All rights reserved. + Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved. +  + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. +  + See file LICENSE.txt for further informations on licensing terms. + */ + +#include <Wire.h> +#include <Firmata.h> + + +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 + +#define MAX_QUERIES 8 + +unsigned long currentMillis;     // store the current value from millis() +unsigned long previousMillis;    // for comparison with currentMillis +unsigned int samplingInterval = 32;  // default sampling interval is 33ms +unsigned int i2cReadDelayTime = 0;  // default delay time between i2c read request and Wire.requestFrom() +unsigned int powerPinsEnabled = 0;  // use as boolean to prevent enablePowerPins from being called more than once + +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +struct i2c_device_info { +  byte addr; +  byte reg; +  byte bytes; +}; + +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean readingContinuously = false; +byte queryIndex = 0; + +void readAndReportData(byte address, int theRegister, byte numBytes) +{ +  if (theRegister != REGISTER_NOT_SPECIFIED) { +    Wire.beginTransmission(address); +    Wire.write((byte)theRegister); +    Wire.endTransmission(); +    delayMicroseconds(i2cReadDelayTime);  // delay is necessary for some devices such as WiiNunchuck +  }  +  else { +    theRegister = 0;  // fill the register with a dummy value +  } + +  Wire.requestFrom(address, numBytes); + +  // check to be sure correct number of bytes were returned by slave +  if(numBytes == Wire.available()) { +    i2cRxData[0] = address; +    i2cRxData[1] = theRegister; +    for (int i = 0; i < numBytes; i++) { +      i2cRxData[2 + i] = Wire.read(); +    } +    // send slave address, register and received bytes +    Firmata.sendSysex(I2C_REPLY, numBytes + 2, i2cRxData); +  } +  else { +    if(numBytes > Wire.available()) { +      Firmata.sendString("I2C Read Error: Too many bytes received"); +    } else { +      Firmata.sendString("I2C Read Error: Too few bytes received");  +    } +  } +   +} + +void sysexCallback(byte command, byte argc, byte *argv) +{ +  byte mode; +  byte slaveAddress; +  byte slaveRegister; +  byte data; +  int  delayTime; + +  if (command == I2C_REQUEST) { +    mode = argv[1] & I2C_READ_WRITE_MODE_MASK; +    slaveAddress = argv[0]; + +    switch(mode) { +    case I2C_WRITE: +      Wire.beginTransmission(slaveAddress); +      for (byte i = 2; i < argc; i += 2) { +        data = argv[i] + (argv[i + 1] << 7); +        Wire.write(data); +      } +      Wire.endTransmission(); +      delayMicroseconds(70); // TODO is this needed? +      break; +    case I2C_READ: +      if (argc == 6) { +        // a slave register is specified +        slaveRegister = argv[2] + (argv[3] << 7); +        data = argv[4] + (argv[5] << 7);  // bytes to read +        readAndReportData(slaveAddress, (int)slaveRegister, data); +      }  +      else { +        // a slave register is NOT specified +        data = argv[2] + (argv[3] << 7);  // bytes to read +        readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); +      } +      break; +    case I2C_READ_CONTINUOUSLY: +      if ((queryIndex + 1) >= MAX_QUERIES) { +        // too many queries, just ignore +        Firmata.sendString("too many queries"); +        break; +      } +      query[queryIndex].addr = slaveAddress; +      query[queryIndex].reg = argv[2] + (argv[3] << 7); +      query[queryIndex].bytes = argv[4] + (argv[5] << 7); +      readingContinuously = true; +      queryIndex++; +      break; +    case I2C_STOP_READING: +      readingContinuously = false; +      queryIndex = 0; +      break; +    default: +      break; +    } +  } +  else if (command == SAMPLING_INTERVAL) { +    samplingInterval = argv[0] + (argv[1] << 7); + +    if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { +      samplingInterval = MINIMUM_SAMPLING_INTERVAL; +    } + +    samplingInterval -= 1; +    Firmata.sendString("sampling interval"); +  } + +  else if (command == I2C_CONFIG) { +    delayTime = (argv[4] + (argv[5] << 7));                        // MSB +    delayTime = (delayTime << 8) + (argv[2] + (argv[3] << 7));     // add LSB + +    if((argv[0] + (argv[1] << 7)) > 0) { +      enablePowerPins(PORTC3, PORTC2); +    } + +    if(delayTime > 0) { +      i2cReadDelayTime = delayTime; +    } + +    if(argc > 6) { +      // If you extend I2C_Config, handle your data here +    } + +  } +} + +void systemResetCallback() +{ +  readingContinuously = false; +  queryIndex = 0; +} + +/* reference: BlinkM_funcs.h by Tod E. Kurt, ThingM, http://thingm.com/ */ +// Enables Pins A2 and A3 to be used as GND and Power +// so that I2C devices can be plugged directly +// into Arduino header (pins A2 - A5) +static void enablePowerPins(byte pwrpin, byte gndpin) +{ +  if(powerPinsEnabled == 0) { +    DDRC |= _BV(pwrpin) | _BV(gndpin); +    PORTC &=~ _BV(gndpin); +    PORTC |=  _BV(pwrpin); +    powerPinsEnabled = 1; +    Firmata.sendString("Power pins enabled"); +    delay(100); +  } +} + +void setup() +{ +  Firmata.setFirmwareVersion(2, 0); + +  Firmata.attach(START_SYSEX, sysexCallback); +  Firmata.attach(SYSTEM_RESET, systemResetCallback); + +  for (int i = 0; i < TOTAL_PINS; ++i) { +    pinMode(i, OUTPUT); +  } + +  Firmata.begin(57600);   +  Wire.begin(); +} + +void loop() +{ +  while (Firmata.available()) { +    Firmata.processInput(); +  } + +  currentMillis = millis(); +  if (currentMillis - previousMillis > samplingInterval) { +    previousMillis += samplingInterval; + +    for (byte i = 0; i < queryIndex; i++) { +      readAndReportData(query[i].addr, query[i].reg, query[i].bytes); +    } +  } +} diff --git a/libraries/Firmata/examples/OldStandardFirmata/LICENSE.txt b/libraries/Firmata/examples/OldStandardFirmata/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/libraries/Firmata/examples/OldStandardFirmata/LICENSE.txt @@ -0,0 +1,458 @@ + +		  GNU LESSER GENERAL PUBLIC LICENSE +		       Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL.  It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +  This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it.  You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + +  When we speak of free software, we are referring to freedom of use, +not price.  Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + +  To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights.  These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + +  For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you.  You must make sure that they, too, receive or can get the source +code.  If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it.  And you must show them these terms so they know their rights. + +  We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +  To protect each distributor, we want to make it very clear that +there is no warranty for the free library.  Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + +  Finally, software patents pose a constant threat to the existence of +any free program.  We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder.  Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + +  Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License.  This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License.  We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + +  When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library.  The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom.  The Lesser General +Public License permits more lax criteria for linking other code with +the library. + +  We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License.  It also provides other free software developers Less +of an advantage over competing non-free programs.  These disadvantages +are the reason we use the ordinary General Public License for many +libraries.  However, the Lesser license provides advantages in certain +special circumstances. + +  For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard.  To achieve this, non-free programs must be +allowed to use the library.  A more frequent case is that a free +library does the same job as widely used non-free libraries.  In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + +  In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software.  For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + +  Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + +  The precise terms and conditions for copying, distribution and +modification follow.  Pay close attention to the difference between a +"work based on the library" and a "work that uses the library".  The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +		  GNU LESSER GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + +  A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +  The "Library", below, refers to any such software library or work +which has been distributed under these terms.  A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language.  (Hereinafter, translation is +included without limitation in the term "modification".) + +  "Source code" for a work means the preferred form of the work for +making modifications to it.  For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +  Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it).  Whether that is true depends on what the Library does +and what the program that uses the Library does. +   +  1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +  You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +  2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) The modified work must itself be a software library. + +    b) You must cause the files modified to carry prominent notices +    stating that you changed the files and the date of any change. + +    c) You must cause the whole of the work to be licensed at no +    charge to all third parties under the terms of this License. + +    d) If a facility in the modified Library refers to a function or a +    table of data to be supplied by an application program that uses +    the facility, other than as an argument passed when the facility +    is invoked, then you must make a good faith effort to ensure that, +    in the event an application does not supply such function or +    table, the facility still operates, and performs whatever part of +    its purpose remains meaningful. + +    (For example, a function in a library to compute square roots has +    a purpose that is entirely well-defined independent of the +    application.  Therefore, Subsection 2d requires that any +    application-supplied function or table used by this function must +    be optional: if the application does not supply it, the square +    root function must still compute square roots.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library.  To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License.  (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.)  Do not make any other change in +these notices. + +  Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +  This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +  4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +  If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +  5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library".  Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +  However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library".  The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +  When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library.  The +threshold for this to be true is not precisely defined by law. + +  If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work.  (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +  Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +  6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +  You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License.  You must supply a copy of this License.  If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License.  Also, you must do one +of these things: + +    a) Accompany the work with the complete corresponding +    machine-readable source code for the Library including whatever +    changes were used in the work (which must be distributed under +    Sections 1 and 2 above); and, if the work is an executable linked +    with the Library, with the complete machine-readable "work that +    uses the Library", as object code and/or source code, so that the +    user can modify the Library and then relink to produce a modified +    executable containing the modified Library.  (It is understood +    that the user who changes the contents of definitions files in the +    Library will not necessarily be able to recompile the application +    to use the modified definitions.) + +    b) Use a suitable shared library mechanism for linking with the +    Library.  A suitable mechanism is one that (1) uses at run time a +    copy of the library already present on the user's computer system, +    rather than copying library functions into the executable, and (2) +    will operate properly with a modified version of the library, if +    the user installs one, as long as the modified version is +    interface-compatible with the version that the work was made with. + +    c) Accompany the work with a written offer, valid for at +    least three years, to give the same user the materials +    specified in Subsection 6a, above, for a charge no more +    than the cost of performing this distribution. + +    d) If distribution of the work is made by offering access to copy +    from a designated place, offer equivalent access to copy the above +    specified materials from the same place. + +    e) Verify that the user has already received a copy of these +    materials or that you have already sent this user a copy. + +  For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it.  However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +  It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system.  Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +  7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +    a) Accompany the combined library with a copy of the same work +    based on the Library, uncombined with any other library +    facilities.  This must be distributed under the terms of the +    Sections above. + +    b) Give prominent notice with the combined library of the fact +    that part of it is a work based on the Library, and explaining +    where to find the accompanying uncombined form of the same work. + +  8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License.  Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License.  However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +  9. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Library or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +  10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + +  11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all.  For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded.  In such case, this License incorporates the limitation as if +written in the body of this License. + +  13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number.  If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation.  If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +  14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission.  For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this.  Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +			    NO WARRANTY + +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino b/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino new file mode 100644 index 0000000..d306c70 --- /dev/null +++ b/libraries/Firmata/examples/OldStandardFirmata/OldStandardFirmata.ino @@ -0,0 +1,239 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* +  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved. +  +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. +  +  See file LICENSE.txt for further informations on licensing terms. + */ + +/*  + * This is an old version of StandardFirmata (v2.0).  It is kept here because + * its the last version that works on an ATMEGA8 chip.  Also, it can be used + * for host software that has not been updated to a newer version of the + * protocol.  It also uses the old baud rate of 115200 rather than 57600. + */ + +#include <EEPROM.h> +#include <Firmata.h> + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting +int analogPin = 0; // counter for reading analog pins + +/* digital pins */ +byte reportPINs[TOTAL_PORTS];   // PIN == input port +byte previousPINs[TOTAL_PORTS]; // PIN == input port +byte pinStatus[TOTAL_PINS]; // store pin status, default OUTPUT +byte portStatus[TOTAL_PORTS]; + +/* timer variables */ +unsigned long currentMillis;     // store the current value from millis() +unsigned long previousMillis;    // for comparison with currentMillis + + +/*============================================================================== + * FUNCTIONS                                                                 + *============================================================================*/ + +void outputPort(byte portNumber, byte portValue) +{ +  portValue = portValue &~ portStatus[portNumber]; +  if(previousPINs[portNumber] != portValue) { +        Firmata.sendDigitalPort(portNumber, portValue);  +        previousPINs[portNumber] = portValue; +        Firmata.sendDigitalPort(portNumber, portValue);  +    } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void)  +{ +    byte i, tmp; +    for(i=0; i < TOTAL_PORTS; i++) { +        if(reportPINs[i]) { +            switch(i) { +            case 0: outputPort(0, PIND &~ B00000011); break; // ignore Rx/Tx 0/1 +            case 1: outputPort(1, PINB); break; +            case 2: outputPort(2, PINC); break; +            } +        } +    } +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) { +    byte port = 0; +    byte offset = 0; + +    if (pin < 8) { +      port = 0; +      offset = 0; +    } else if (pin < 14) { +      port = 1; +      offset = 8;      +    } else if (pin < 22) { +      port = 2; +      offset = 14; +    } + +    if(pin > 1) { // ignore RxTx (pins 0 and 1) +        pinStatus[pin] = mode; +        switch(mode) { +        case INPUT: +            pinMode(pin, INPUT); +            portStatus[port] = portStatus[port] &~ (1 << (pin - offset)); +            break; +        case OUTPUT: +            digitalWrite(pin, LOW); // disable PWM +        case PWM: +            pinMode(pin, OUTPUT); +            portStatus[port] = portStatus[port] | (1 << (pin - offset)); +            break; +        //case ANALOG: // TODO figure this out +        default: +            Firmata.sendString(""); +        } +        // TODO: save status to EEPROM here, if changed +    } +} + +void analogWriteCallback(byte pin, int value) +{ +    setPinModeCallback(pin,PWM); +    analogWrite(pin, value); +} + +void digitalWriteCallback(byte port, int value) +{ +    switch(port) { +    case 0: // pins 2-7 (don't change Rx/Tx, pins 0 and 1) +        // 0xFF03 == B1111111100000011    0x03 == B00000011 +        PORTD = (value &~ 0xFF03) | (PORTD & 0x03); +        break; +    case 1: // pins 8-13 (14,15 are disabled for the crystal)  +        PORTB = (byte)value; +        break; +    case 2: // analog pins used as digital +        PORTC = (byte)value; +        break; +    } +} + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte pin, int value) +{ +    if(value == 0) { +        analogInputsToReport = analogInputsToReport &~ (1 << pin); +    } +    else { // everything but 0 enables reporting of that pin +        analogInputsToReport = analogInputsToReport | (1 << pin); +    } +    // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ +    reportPINs[port] = (byte)value; +    if(port == 2) // turn off analog reporting when used as digital +        analogInputsToReport = 0; +} + +/*============================================================================== + * SETUP() + *============================================================================*/ +void setup()  +{ +    byte i; + +    Firmata.setFirmwareVersion(2, 0); + +    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); +    Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); +    Firmata.attach(REPORT_ANALOG, reportAnalogCallback); +    Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); +    Firmata.attach(SET_PIN_MODE, setPinModeCallback); + +    portStatus[0] = B00000011;  // ignore Tx/RX pins +    portStatus[1] = B11000000;  // ignore 14/15 pins  +    portStatus[2] = B00000000; + +//    for(i=0; i<TOTAL_PINS; ++i) { // TODO make this work with analogs +    for(i=0; i<14; ++i) { +        setPinModeCallback(i,OUTPUT); +    } +    // set all outputs to 0 to make sure internal pull-up resistors are off +    PORTB = 0; // pins 8-15 +    PORTC = 0; // analog port +    PORTD = 0; // pins 0-7 + +    // TODO rethink the init, perhaps it should report analog on default +    for(i=0; i<TOTAL_PORTS; ++i) { +        reportPINs[i] = false; +    } +    // TODO: load state from EEPROM here + +    /* send digital inputs here, if enabled, to set the initial state on the +     * host computer, since once in the loop(), this firmware will only send +     * digital data on change. */ +    if(reportPINs[0]) outputPort(0, PIND &~ B00000011); // ignore Rx/Tx 0/1 +    if(reportPINs[1]) outputPort(1, PINB); +    if(reportPINs[2]) outputPort(2, PINC); + +    Firmata.begin(115200); +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop()  +{ +/* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print()  */ +    checkDigitalInputs();   +    currentMillis = millis(); +    if(currentMillis - previousMillis > 20) {   +        previousMillis += 20;     // run this every 20ms +        /* SERIALREAD - Serial.read() uses a 128 byte circular buffer, so handle +         * all serialReads at once, i.e. empty the buffer */ +        while(Firmata.available()) +            Firmata.processInput(); +        /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over +         * 60 bytes. use a timer to sending an event character every 4 ms to +         * trigger the buffer to dump. */ +	 +        /* ANALOGREAD - right after the event character, do all of the +         * analogReads().  These only need to be done every 4ms. */ +        for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { +            if( analogInputsToReport & (1 << analogPin) ) { +                Firmata.sendAnalog(analogPin, analogRead(analogPin)); +            } +        } +    } +} diff --git a/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino new file mode 100644 index 0000000..cdcfff0 --- /dev/null +++ b/libraries/Firmata/examples/ServoFirmata/ServoFirmata.ino @@ -0,0 +1,53 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* This firmware supports as many servos as possible using the Servo library  + * included in Arduino 0017 + * + * TODO add message to configure minPulse/maxPulse/degrees + * + * This example code is in the public domain. + */ +  +#include <Servo.h> +#include <Firmata.h> + +Servo servos[MAX_SERVOS]; + +void analogWriteCallback(byte pin, int value) +{ +    if (IS_PIN_SERVO(pin)) { +        servos[PIN_TO_SERVO(pin)].write(value); +    } +} + +void setup()  +{ +    byte pin; + +    Firmata.setFirmwareVersion(0, 2); +    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + +    for (pin=0; pin < TOTAL_PINS; pin++) { +        if (IS_PIN_SERVO(pin)) { +	    servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); +        } +    } +    +    Firmata.begin(57600); +} + +void loop()  +{ +    while(Firmata.available()) +        Firmata.processInput(); +} + diff --git a/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino new file mode 100644 index 0000000..44ea91e --- /dev/null +++ b/libraries/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.ino @@ -0,0 +1,46 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* Supports as many analog inputs and analog PWM outputs as possible. + * + * This example code is in the public domain. + */ +#include <Firmata.h> + +byte analogPin = 0; + +void analogWriteCallback(byte pin, int value) +{ +    if (IS_PIN_PWM(pin)) { +        pinMode(PIN_TO_DIGITAL(pin), OUTPUT); +        analogWrite(PIN_TO_PWM(pin), value); +    } +} + +void setup() +{ +    Firmata.setFirmwareVersion(0, 1); +    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); +    Firmata.begin(57600); +} + +void loop() +{ +    while(Firmata.available()) { +        Firmata.processInput(); +    } +    // do one analogRead per loop, so if PC is sending a lot of +    // analog write messages, we will only delay 1 analogRead +    Firmata.sendAnalog(analogPin, analogRead(analogPin));  +    analogPin = analogPin + 1; +    if (analogPin >= TOTAL_ANALOG_PINS) analogPin = 0; +} + diff --git a/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino new file mode 100644 index 0000000..a0d764f --- /dev/null +++ b/libraries/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.ino @@ -0,0 +1,72 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* Supports as many digital inputs and outputs as possible. + * + * This example code is in the public domain. + */ +#include <Firmata.h> + +byte previousPIN[TOTAL_PORTS];  // PIN means PORT for input +byte previousPORT[TOTAL_PORTS];  + +void outputPort(byte portNumber, byte portValue) +{ +    // only send the data when it changes, otherwise you get too many messages! +    if (previousPIN[portNumber] != portValue) { +        Firmata.sendDigitalPort(portNumber, portValue);  +        previousPIN[portNumber] = portValue; +    } +} + +void setPinModeCallback(byte pin, int mode) { +    if (IS_PIN_DIGITAL(pin)) { +        pinMode(PIN_TO_DIGITAL(pin), mode); +    } +} + +void digitalWriteCallback(byte port, int value) +{ +    byte i; +    byte currentPinValue, previousPinValue; + +    if (port < TOTAL_PORTS && value != previousPORT[port]) { +        for(i=0; i<8; i++) { +            currentPinValue = (byte) value & (1 << i); +            previousPinValue = previousPORT[port] & (1 << i); +            if(currentPinValue != previousPinValue) { +                digitalWrite(i + (port*8), currentPinValue); +            } +        } +        previousPORT[port] = value; +    } +} + +void setup() +{ +    Firmata.setFirmwareVersion(0, 1); +    Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); +    Firmata.attach(SET_PIN_MODE, setPinModeCallback); +    Firmata.begin(57600); +} + +void loop() +{ +    byte i; + +    for (i=0; i<TOTAL_PORTS; i++) { +        outputPort(i, readPort(i, 0xff)); +    } + +    while(Firmata.available()) { +        Firmata.processInput(); +    } +} diff --git a/libraries/Firmata/examples/StandardFirmata/LICENSE.txt b/libraries/Firmata/examples/StandardFirmata/LICENSE.txt new file mode 100644 index 0000000..77cec6d --- /dev/null +++ b/libraries/Firmata/examples/StandardFirmata/LICENSE.txt @@ -0,0 +1,458 @@ + +		  GNU LESSER GENERAL PUBLIC LICENSE +		       Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL.  It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + +			    Preamble + +  The licenses for most software are designed to take away your +freedom to share and change it.  By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + +  This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it.  You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + +  When we speak of free software, we are referring to freedom of use, +not price.  Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + +  To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights.  These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + +  For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you.  You must make sure that they, too, receive or can get the source +code.  If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it.  And you must show them these terms so they know their rights. + +  We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + +  To protect each distributor, we want to make it very clear that +there is no warranty for the free library.  Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + +  Finally, software patents pose a constant threat to the existence of +any free program.  We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder.  Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + +  Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License.  This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License.  We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + +  When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library.  The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom.  The Lesser General +Public License permits more lax criteria for linking other code with +the library. + +  We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License.  It also provides other free software developers Less +of an advantage over competing non-free programs.  These disadvantages +are the reason we use the ordinary General Public License for many +libraries.  However, the Lesser license provides advantages in certain +special circumstances. + +  For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard.  To achieve this, non-free programs must be +allowed to use the library.  A more frequent case is that a free +library does the same job as widely used non-free libraries.  In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + +  In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software.  For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + +  Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + +  The precise terms and conditions for copying, distribution and +modification follow.  Pay close attention to the difference between a +"work based on the library" and a "work that uses the library".  The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + +		  GNU LESSER GENERAL PUBLIC LICENSE +   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +  0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + +  A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + +  The "Library", below, refers to any such software library or work +which has been distributed under these terms.  A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language.  (Hereinafter, translation is +included without limitation in the term "modification".) + +  "Source code" for a work means the preferred form of the work for +making modifications to it.  For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + +  Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope.  The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it).  Whether that is true depends on what the Library does +and what the program that uses the Library does. +   +  1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + +  You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + +  2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +    a) The modified work must itself be a software library. + +    b) You must cause the files modified to carry prominent notices +    stating that you changed the files and the date of any change. + +    c) You must cause the whole of the work to be licensed at no +    charge to all third parties under the terms of this License. + +    d) If a facility in the modified Library refers to a function or a +    table of data to be supplied by an application program that uses +    the facility, other than as an argument passed when the facility +    is invoked, then you must make a good faith effort to ensure that, +    in the event an application does not supply such function or +    table, the facility still operates, and performs whatever part of +    its purpose remains meaningful. + +    (For example, a function in a library to compute square roots has +    a purpose that is entirely well-defined independent of the +    application.  Therefore, Subsection 2d requires that any +    application-supplied function or table used by this function must +    be optional: if the application does not supply it, the square +    root function must still compute square roots.) + +These requirements apply to the modified work as a whole.  If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works.  But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +  3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library.  To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License.  (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.)  Do not make any other change in +these notices. + +  Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + +  This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + +  4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + +  If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + +  5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library".  Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + +  However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library".  The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + +  When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library.  The +threshold for this to be true is not precisely defined by law. + +  If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work.  (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + +  Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + +  6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + +  You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License.  You must supply a copy of this License.  If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License.  Also, you must do one +of these things: + +    a) Accompany the work with the complete corresponding +    machine-readable source code for the Library including whatever +    changes were used in the work (which must be distributed under +    Sections 1 and 2 above); and, if the work is an executable linked +    with the Library, with the complete machine-readable "work that +    uses the Library", as object code and/or source code, so that the +    user can modify the Library and then relink to produce a modified +    executable containing the modified Library.  (It is understood +    that the user who changes the contents of definitions files in the +    Library will not necessarily be able to recompile the application +    to use the modified definitions.) + +    b) Use a suitable shared library mechanism for linking with the +    Library.  A suitable mechanism is one that (1) uses at run time a +    copy of the library already present on the user's computer system, +    rather than copying library functions into the executable, and (2) +    will operate properly with a modified version of the library, if +    the user installs one, as long as the modified version is +    interface-compatible with the version that the work was made with. + +    c) Accompany the work with a written offer, valid for at +    least three years, to give the same user the materials +    specified in Subsection 6a, above, for a charge no more +    than the cost of performing this distribution. + +    d) If distribution of the work is made by offering access to copy +    from a designated place, offer equivalent access to copy the above +    specified materials from the same place. + +    e) Verify that the user has already received a copy of these +    materials or that you have already sent this user a copy. + +  For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it.  However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + +  It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system.  Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + +  7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + +    a) Accompany the combined library with a copy of the same work +    based on the Library, uncombined with any other library +    facilities.  This must be distributed under the terms of the +    Sections above. + +    b) Give prominent notice with the combined library of the fact +    that part of it is a work based on the Library, and explaining +    where to find the accompanying uncombined form of the same work. + +  8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License.  Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License.  However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + +  9. You are not required to accept this License, since you have not +signed it.  However, nothing else grants you permission to modify or +distribute the Library or its derivative works.  These actions are +prohibited by law if you do not accept this License.  Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + +  10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions.  You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + +  11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License.  If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all.  For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices.  Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +  12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded.  In such case, this License incorporates the limitation as if +written in the body of this License. + +  13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number.  If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation.  If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + +  14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission.  For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this.  Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + +			    NO WARRANTY + +  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + diff --git a/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino new file mode 100644 index 0000000..1a987ee --- /dev/null +++ b/libraries/Firmata/examples/StandardFirmata/StandardFirmata.ino @@ -0,0 +1,636 @@ +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* +  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved. +  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved. +  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved. +  Copyright (C) 2009-2011 Jeff Hoefs.  All rights reserved. +   +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. +  +  See file LICENSE.txt for further informations on licensing terms. + +  formatted using the GNU C formatting and indenting +*/ + +/*  + * TODO: use Program Control to load stored profiles from EEPROM + */ + +#include <Servo.h> +#include <Wire.h> +#include <Firmata.h> + +// move the following defines to Firmata.h? +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS];         // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS];           // any value that has been written + +/* timer variables */ +unsigned long currentMillis;        // store the current value from millis() +unsigned long previousMillis;       // for comparison with currentMillis +int samplingInterval = 19;          // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { +  byte addr; +  byte reg; +  byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0;  // default delay time between i2c read request and Wire.requestFrom() + +Servo servos[MAX_SERVOS]; +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void readAndReportData(byte address, int theRegister, byte numBytes) { +  // allow I2C requests that don't require a register read +  // for example, some devices using an interrupt pin to signify new data available +  // do not always require the register read so upon interrupt you call Wire.requestFrom()   +  if (theRegister != REGISTER_NOT_SPECIFIED) { +    Wire.beginTransmission(address); +    #if ARDUINO >= 100 +    Wire.write((byte)theRegister); +    #else +    Wire.send((byte)theRegister); +    #endif +    Wire.endTransmission(); +    delayMicroseconds(i2cReadDelayTime);  // delay is necessary for some devices such as WiiNunchuck +  } else { +    theRegister = 0;  // fill the register with a dummy value +  } + +  Wire.requestFrom(address, numBytes);  // all bytes are returned in requestFrom + +  // check to be sure correct number of bytes were returned by slave +  if(numBytes == Wire.available()) { +    i2cRxData[0] = address; +    i2cRxData[1] = theRegister; +    for (int i = 0; i < numBytes; i++) { +      #if ARDUINO >= 100 +      i2cRxData[2 + i] = Wire.read(); +      #else +      i2cRxData[2 + i] = Wire.receive(); +      #endif +    } +  } +  else { +    if(numBytes > Wire.available()) { +      Firmata.sendString("I2C Read Error: Too many bytes received"); +    } else { +      Firmata.sendString("I2C Read Error: Too few bytes received");  +    } +  } + +  // send slave address, register and received bytes +  Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ +  // pins not configured as INPUT are cleared to zeros +  portValue = portValue & portConfigInputs[portNumber]; +  // only send if the value is different than previously sent +  if(forceSend || previousPINs[portNumber] != portValue) { +    Firmata.sendDigitalPort(portNumber, portValue); +    previousPINs[portNumber] = portValue; +  } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ +  /* Using non-looping code allows constants to be given to readPort(). +   * The compiler will apply substantial optimizations if the inputs +   * to readPort() are compile-time constants. */ +  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); +  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); +  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); +  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); +  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); +  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); +  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); +  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); +  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); +  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); +  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); +  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); +  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); +  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); +  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); +  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ +  if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { +    // disable i2c so pins can be used for other functions +    // the following if statements should reconfigure the pins properly +    disableI2CPins(); +  } +  if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { +    servos[PIN_TO_SERVO(pin)].detach(); +  } +  if (IS_PIN_ANALOG(pin)) { +    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting +  } +  if (IS_PIN_DIGITAL(pin)) { +    if (mode == INPUT) { +      portConfigInputs[pin/8] |= (1 << (pin & 7)); +    } else { +      portConfigInputs[pin/8] &= ~(1 << (pin & 7)); +    } +  } +  pinState[pin] = 0; +  switch(mode) { +  case ANALOG: +    if (IS_PIN_ANALOG(pin)) { +      if (IS_PIN_DIGITAL(pin)) { +        pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +      } +      pinConfig[pin] = ANALOG; +    } +    break; +  case INPUT: +    if (IS_PIN_DIGITAL(pin)) { +      pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver +      digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups +      pinConfig[pin] = INPUT; +    } +    break; +  case OUTPUT: +    if (IS_PIN_DIGITAL(pin)) { +      digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM +      pinMode(PIN_TO_DIGITAL(pin), OUTPUT); +      pinConfig[pin] = OUTPUT; +    } +    break; +  case PWM: +    if (IS_PIN_PWM(pin)) { +      pinMode(PIN_TO_PWM(pin), OUTPUT); +      analogWrite(PIN_TO_PWM(pin), 0); +      pinConfig[pin] = PWM; +    } +    break; +  case SERVO: +    if (IS_PIN_SERVO(pin)) { +      pinConfig[pin] = SERVO; +      if (!servos[PIN_TO_SERVO(pin)].attached()) { +          servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); +      } +    } +    break; +  case I2C: +    if (IS_PIN_I2C(pin)) { +      // mark the pin as i2c +      // the user must call I2C_CONFIG to enable I2C for a device +      pinConfig[pin] = I2C; +    } +    break; +  default: +    Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM +  } +  // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ +  if (pin < TOTAL_PINS) { +    switch(pinConfig[pin]) { +    case SERVO: +      if (IS_PIN_SERVO(pin)) +        servos[PIN_TO_SERVO(pin)].write(value); +        pinState[pin] = value; +      break; +    case PWM: +      if (IS_PIN_PWM(pin)) +        analogWrite(PIN_TO_PWM(pin), value); +        pinState[pin] = value; +      break; +    } +  } +} + +void digitalWriteCallback(byte port, int value) +{ +  byte pin, lastPin, mask=1, pinWriteMask=0; + +  if (port < TOTAL_PORTS) { +    // create a mask of the pins on this port that are writable. +    lastPin = port*8+8; +    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; +    for (pin=port*8; pin < lastPin; pin++) { +      // do not disturb non-digital pins (eg, Rx & Tx) +      if (IS_PIN_DIGITAL(pin)) { +        // only write to OUTPUT and INPUT (enables pullup) +        // do not touch pins in PWM, ANALOG, SERVO or other modes +        if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { +          pinWriteMask |= mask; +          pinState[pin] = ((byte)value & mask) ? 1 : 0; +        } +      } +      mask = mask << 1; +    } +    writePort(port, (byte)value, pinWriteMask); +  } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ +  if (analogPin < TOTAL_ANALOG_PINS) { +    if(value == 0) { +      analogInputsToReport = analogInputsToReport &~ (1 << analogPin); +    } else { +      analogInputsToReport = analogInputsToReport | (1 << analogPin); +    } +  } +  // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ +  if (port < TOTAL_PORTS) { +    reportPINs[port] = (byte)value; +  } +  // do not disable analog reporting on these 8 pins, to allow some +  // pins used for digital, others analog.  Instead, allow both types +  // of reporting to be enabled, but check if the pin is configured +  // as analog when sampling the analog inputs.  Likewise, while +  // scanning digital pins, portConfigInputs will mask off values from any +  // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ +  byte mode; +  byte slaveAddress; +  byte slaveRegister; +  byte data; +  unsigned int delayTime;  +   +  switch(command) { +  case I2C_REQUEST: +    mode = argv[1] & I2C_READ_WRITE_MODE_MASK; +    if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { +      Firmata.sendString("10-bit addressing mode is not yet supported"); +      return; +    } +    else { +      slaveAddress = argv[0]; +    } + +    switch(mode) { +    case I2C_WRITE: +      Wire.beginTransmission(slaveAddress); +      for (byte i = 2; i < argc; i += 2) { +        data = argv[i] + (argv[i + 1] << 7); +        #if ARDUINO >= 100 +        Wire.write(data); +        #else +        Wire.send(data); +        #endif +      } +      Wire.endTransmission(); +      delayMicroseconds(70); +      break; +    case I2C_READ: +      if (argc == 6) { +        // a slave register is specified +        slaveRegister = argv[2] + (argv[3] << 7); +        data = argv[4] + (argv[5] << 7);  // bytes to read +        readAndReportData(slaveAddress, (int)slaveRegister, data); +      } +      else { +        // a slave register is NOT specified +        data = argv[2] + (argv[3] << 7);  // bytes to read +        readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); +      } +      break; +    case I2C_READ_CONTINUOUSLY: +      if ((queryIndex + 1) >= MAX_QUERIES) { +        // too many queries, just ignore +        Firmata.sendString("too many queries"); +        break; +      } +      queryIndex++; +      query[queryIndex].addr = slaveAddress; +      query[queryIndex].reg = argv[2] + (argv[3] << 7); +      query[queryIndex].bytes = argv[4] + (argv[5] << 7); +      break; +    case I2C_STOP_READING: +	  byte queryIndexToSkip;       +      // if read continuous mode is enabled for only 1 i2c device, disable +      // read continuous reporting for that device +      if (queryIndex <= 0) { +        queryIndex = -1;         +      } else { +        // if read continuous mode is enabled for multiple devices, +        // determine which device to stop reading and remove it's data from +        // the array, shifiting other array data to fill the space +        for (byte i = 0; i < queryIndex + 1; i++) { +          if (query[i].addr = slaveAddress) { +            queryIndexToSkip = i; +            break; +          } +        } +         +        for (byte i = queryIndexToSkip; i<queryIndex + 1; i++) { +          if (i < MAX_QUERIES) { +            query[i].addr = query[i+1].addr; +            query[i].reg = query[i+1].addr; +            query[i].bytes = query[i+1].bytes;  +          } +        } +        queryIndex--; +      } +      break; +    default: +      break; +    } +    break; +  case I2C_CONFIG: +    delayTime = (argv[0] + (argv[1] << 7)); + +    if(delayTime > 0) { +      i2cReadDelayTime = delayTime; +    } + +    if (!isI2CEnabled) { +      enableI2CPins(); +    } +     +    break; +  case SERVO_CONFIG: +    if(argc > 4) { +      // these vars are here for clarity, they'll optimized away by the compiler +      byte pin = argv[0]; +      int minPulse = argv[1] + (argv[2] << 7); +      int maxPulse = argv[3] + (argv[4] << 7); + +      if (IS_PIN_SERVO(pin)) { +        if (servos[PIN_TO_SERVO(pin)].attached()) +          servos[PIN_TO_SERVO(pin)].detach(); +        servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); +        setPinModeCallback(pin, SERVO); +      } +    } +    break; +  case SAMPLING_INTERVAL: +    if (argc > 1) { +      samplingInterval = argv[0] + (argv[1] << 7); +      if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { +        samplingInterval = MINIMUM_SAMPLING_INTERVAL; +      }       +    } else { +      //Firmata.sendString("Not enough data"); +    } +    break; +  case EXTENDED_ANALOG: +    if (argc > 1) { +      int val = argv[1]; +      if (argc > 2) val |= (argv[2] << 7); +      if (argc > 3) val |= (argv[3] << 14); +      analogWriteCallback(argv[0], val); +    } +    break; +  case CAPABILITY_QUERY: +    Serial.write(START_SYSEX); +    Serial.write(CAPABILITY_RESPONSE); +    for (byte pin=0; pin < TOTAL_PINS; pin++) { +      if (IS_PIN_DIGITAL(pin)) { +        Serial.write((byte)INPUT); +        Serial.write(1); +        Serial.write((byte)OUTPUT); +        Serial.write(1); +      } +      if (IS_PIN_ANALOG(pin)) { +        Serial.write(ANALOG); +        Serial.write(10); +      } +      if (IS_PIN_PWM(pin)) { +        Serial.write(PWM); +        Serial.write(8); +      } +      if (IS_PIN_SERVO(pin)) { +        Serial.write(SERVO); +        Serial.write(14); +      } +      if (IS_PIN_I2C(pin)) { +        Serial.write(I2C); +        Serial.write(1);  // to do: determine appropriate value  +      } +      Serial.write(127); +    } +    Serial.write(END_SYSEX); +    break; +  case PIN_STATE_QUERY: +    if (argc > 0) { +      byte pin=argv[0]; +      Serial.write(START_SYSEX); +      Serial.write(PIN_STATE_RESPONSE); +      Serial.write(pin); +      if (pin < TOTAL_PINS) { +        Serial.write((byte)pinConfig[pin]); +	Serial.write((byte)pinState[pin] & 0x7F); +	if (pinState[pin] & 0xFF80) Serial.write((byte)(pinState[pin] >> 7) & 0x7F); +	if (pinState[pin] & 0xC000) Serial.write((byte)(pinState[pin] >> 14) & 0x7F); +      } +      Serial.write(END_SYSEX); +    } +    break; +  case ANALOG_MAPPING_QUERY: +    Serial.write(START_SYSEX); +    Serial.write(ANALOG_MAPPING_RESPONSE); +    for (byte pin=0; pin < TOTAL_PINS; pin++) { +      Serial.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); +    } +    Serial.write(END_SYSEX); +    break; +  } +} + +void enableI2CPins() +{ +  byte i; +  // is there a faster way to do this? would probaby require importing  +  // Arduino.h to get SCL and SDA pins +  for (i=0; i < TOTAL_PINS; i++) { +    if(IS_PIN_I2C(i)) { +      // mark pins as i2c so they are ignore in non i2c data requests +      setPinModeCallback(i, I2C); +    }  +  } +    +  isI2CEnabled = true;  +   +  // is there enough time before the first I2C request to call this here? +  Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { +    isI2CEnabled = false; +    // disable read continuous mode for all devices +    queryIndex = -1; +    // uncomment the following if or when the end() method is added to Wire library +    // Wire.end(); +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ +  // initialize a defalt state +  // TODO: option to load config from EEPROM instead of default +  if (isI2CEnabled) { +  	disableI2CPins(); +  } +  for (byte i=0; i < TOTAL_PORTS; i++) { +    reportPINs[i] = false;      // by default, reporting off +    portConfigInputs[i] = 0;	// until activated +    previousPINs[i] = 0; +  } +  // pins with analog capability default to analog input +  // otherwise, pins default to digital output +  for (byte i=0; i < TOTAL_PINS; i++) { +    if (IS_PIN_ANALOG(i)) { +      // turns off pullup, configures everything +      setPinModeCallback(i, ANALOG); +    } else { +      // sets the output to 0, configures portConfigInputs +      setPinModeCallback(i, OUTPUT); +    } +  } +  // by default, do not report any analog inputs +  analogInputsToReport = 0; + +  /* send digital inputs to set the initial state on the host computer, +   * since once in the loop(), this firmware will only send on change */ +  /* +  TODO: this can never execute, since no pins default to digital input +        but it will be needed when/if we support EEPROM stored config +  for (byte i=0; i < TOTAL_PORTS; i++) { +    outputPort(i, readPort(i, portConfigInputs[i]), true); +  } +  */ +} + +void setup()  +{ +  Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + +  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); +  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); +  Firmata.attach(REPORT_ANALOG, reportAnalogCallback); +  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); +  Firmata.attach(SET_PIN_MODE, setPinModeCallback); +  Firmata.attach(START_SYSEX, sysexCallback); +  Firmata.attach(SYSTEM_RESET, systemResetCallback); + +  Firmata.begin(57600); +  systemResetCallback();  // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop()  +{ +  byte pin, analogPin; + +  /* DIGITALREAD - as fast as possible, check for changes and output them to the +   * FTDI buffer using Serial.print()  */ +  checkDigitalInputs();   + +  /* SERIALREAD - processing incoming messagse as soon as possible, while still +   * checking digital inputs.  */ +  while(Firmata.available()) +    Firmata.processInput(); + +  /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over +   * 60 bytes. use a timer to sending an event character every 4 ms to +   * trigger the buffer to dump. */ + +  currentMillis = millis(); +  if (currentMillis - previousMillis > samplingInterval) { +    previousMillis += samplingInterval; +    /* ANALOGREAD - do all analogReads() at the configured sampling interval */ +    for(pin=0; pin<TOTAL_PINS; pin++) { +      if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { +        analogPin = PIN_TO_ANALOG(pin); +        if (analogInputsToReport & (1 << analogPin)) { +          Firmata.sendAnalog(analogPin, analogRead(analogPin)); +        } +      } +    } +    // report i2c data for all device with read continuous mode enabled +    if (queryIndex > -1) { +      for (byte i = 0; i < queryIndex + 1; i++) { +        readAndReportData(query[i].addr, query[i].reg, query[i].bytes); +      } +    } +  } +} diff --git a/libraries/Firmata/keywords.txt b/libraries/Firmata/keywords.txt new file mode 100644 index 0000000..52e0a9c --- /dev/null +++ b/libraries/Firmata/keywords.txt @@ -0,0 +1,62 @@ +####################################### +# Syntax Coloring Map For Firmata +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Firmata	KEYWORD1 +callbackFunction	KEYWORD1 +systemResetCallbackFunction	KEYWORD1 +stringCallbackFunction	KEYWORD1 +sysexCallbackFunction	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin	KEYWORD2 +begin	KEYWORD2 +printVersion	KEYWORD2 +blinkVersion	KEYWORD2 +printFirmwareVersion	KEYWORD2 +setFirmwareVersion	KEYWORD2 +setFirmwareNameAndVersion	KEYWORD2 +available	KEYWORD2 +processInput	KEYWORD2 +sendAnalog	KEYWORD2 +sendDigital	KEYWORD2 +sendDigitalPortPair	KEYWORD2 +sendDigitalPort	KEYWORD2 +sendString	KEYWORD2 +sendString	KEYWORD2 +sendSysex	KEYWORD2 +attach	KEYWORD2 +detach	KEYWORD2 +flush	KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + +MAX_DATA_BYTES	LITERAL1 + +DIGITAL_MESSAGE	LITERAL1 +ANALOG_MESSAGE	LITERAL1 +REPORT_ANALOG	LITERAL1 +REPORT_DIGITAL	LITERAL1 +REPORT_VERSION	LITERAL1 +SET_PIN_MODE	LITERAL1 +SYSTEM_RESET	LITERAL1 + +START_SYSEX	LITERAL1 +END_SYSEX	LITERAL1 + +PWM	LITERAL1 + +TOTAL_ANALOG_PINS	LITERAL1 +TOTAL_DIGITAL_PINS	LITERAL1 +TOTAL_PORTS			LITERAL1 +ANALOG_PORT			LITERAL1 diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp new file mode 100644 index 0000000..5e48073 --- /dev/null +++ b/libraries/SPI/SPI.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#include "pins_arduino.h" +#include "SPI.h" + +SPIClass SPI; + +void SPIClass::begin() { + +  // Set SS to high so a connected chip will be "deselected" by default +  digitalWrite(SS, HIGH); + +  // When the SS pin is set as OUTPUT, it can be used as +  // a general purpose output port (it doesn't influence +  // SPI operations). +  pinMode(SS, OUTPUT); + +  // Warning: if the SS pin ever becomes a LOW INPUT then SPI +  // automatically switches to Slave, so the data direction of +  // the SS pin MUST be kept as OUTPUT. +  SPCR |= _BV(MSTR); +  SPCR |= _BV(SPE); + +  // Set direction register for SCK and MOSI pin. +  // MISO pin automatically overrides to INPUT. +  // By doing this AFTER enabling SPI, we avoid accidentally +  // clocking in a single bit since the lines go directly +  // from "input" to SPI control.   +  // http://code.google.com/p/arduino/issues/detail?id=888 +  pinMode(SCK, OUTPUT); +  pinMode(MOSI, OUTPUT); +} + + +void SPIClass::end() { +  SPCR &= ~_BV(SPE); +} + +void SPIClass::setBitOrder(uint8_t bitOrder) +{ +  if(bitOrder == LSBFIRST) { +    SPCR |= _BV(DORD); +  } else { +    SPCR &= ~(_BV(DORD)); +  } +} + +void SPIClass::setDataMode(uint8_t mode) +{ +  SPCR = (SPCR & ~SPI_MODE_MASK) | mode; +} + +void SPIClass::setClockDivider(uint8_t rate) +{ +  SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK); +  SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK); +} + diff --git a/libraries/SPI/SPI.h b/libraries/SPI/SPI.h new file mode 100644 index 0000000..f647d5c --- /dev/null +++ b/libraries/SPI/SPI.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st> + * SPI Master library for arduino. + * + * This file is free software; you can redistribute it and/or modify + * it under the terms of either the GNU General Public License version 2 + * or the GNU Lesser General Public License version 2.1, both as + * published by the Free Software Foundation. + */ + +#ifndef _SPI_H_INCLUDED +#define _SPI_H_INCLUDED + +#include <stdio.h> +#include <Arduino.h> +#include <avr/pgmspace.h> + +#define SPI_CLOCK_DIV4 0x00 +#define SPI_CLOCK_DIV16 0x01 +#define SPI_CLOCK_DIV64 0x02 +#define SPI_CLOCK_DIV128 0x03 +#define SPI_CLOCK_DIV2 0x04 +#define SPI_CLOCK_DIV8 0x05 +#define SPI_CLOCK_DIV32 0x06 +//#define SPI_CLOCK_DIV64 0x07 + +#define SPI_MODE0 0x00 +#define SPI_MODE1 0x04 +#define SPI_MODE2 0x08 +#define SPI_MODE3 0x0C + +#define SPI_MODE_MASK 0x0C  // CPOL = bit 3, CPHA = bit 2 on SPCR +#define SPI_CLOCK_MASK 0x03  // SPR1 = bit 1, SPR0 = bit 0 on SPCR +#define SPI_2XCLOCK_MASK 0x01  // SPI2X = bit 0 on SPSR + +class SPIClass { +public: +  inline static byte transfer(byte _data); + +  // SPI Configuration methods + +  inline static void attachInterrupt(); +  inline static void detachInterrupt(); // Default + +  static void begin(); // Default +  static void end(); + +  static void setBitOrder(uint8_t); +  static void setDataMode(uint8_t); +  static void setClockDivider(uint8_t); +}; + +extern SPIClass SPI; + +byte SPIClass::transfer(byte _data) { +  SPDR = _data; +  while (!(SPSR & _BV(SPIF))) +    ; +  return SPDR; +} + +void SPIClass::attachInterrupt() { +  SPCR |= _BV(SPIE); +} + +void SPIClass::detachInterrupt() { +  SPCR &= ~_BV(SPIE); +} + +#endif diff --git a/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino b/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..9d77a42 --- /dev/null +++ b/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* + SCP1000 Barometric Pressure Sensor Display +  + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ +  + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip +  + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 +  + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include <SPI.h> + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F;      //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure +const int TEMPERATURE = 0x21;   //16 bit temperature reading +const byte READ = 0b11111100;     // SCP1000's read command +const byte WRITE = 0b00000010;   // SCP1000's write command + +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6; +const int chipSelectPin = 7; + +void setup() { +  Serial.begin(9600); + +  // start the SPI library: +  SPI.begin(); + +  // initalize the  data ready and chip select pins: +  pinMode(dataReadyPin, INPUT); +  pinMode(chipSelectPin, OUTPUT); + +  //Configure SCP1000 for low noise configuration: +  writeRegister(0x02, 0x2D); +  writeRegister(0x01, 0x03); +  writeRegister(0x03, 0x02); +  // give the sensor time to set up: +  delay(100); +} + +void loop() { +  //Select High Resolution Mode +  writeRegister(0x03, 0x0A); + +  // don't do anything until the data ready pin is high: +  if (digitalRead(dataReadyPin) == HIGH) { +    //Read the temperature data +    int tempData = readRegister(0x21, 2); + +    // convert the temperature to celsius and display it: +    float realTemp = (float)tempData / 20.0; +    Serial.print("Temp[C]="); +    Serial.print(realTemp); + + +    //Read the pressure data highest 3 bits: +    byte  pressure_data_high = readRegister(0x1F, 1); +    pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + +    //Read the pressure data lower 16 bits: +    unsigned int pressure_data_low = readRegister(0x20, 2); +    //combine the two parts into one 19-bit number: +    long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; + +    // display the temperature: +    Serial.println("\tPressure [Pa]=" + String(pressure)); +  } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { +  byte inByte = 0;           // incoming byte from the SPI +  unsigned int result = 0;   // result to return +  Serial.print(thisRegister, BIN); +  Serial.print("\t"); +  // SCP1000 expects the register name in the upper 6 bits +  // of the byte. So shift the bits left by two bits: +  thisRegister = thisRegister << 2; +  // now combine the address and the command into one byte +  byte dataToSend = thisRegister & READ; +  Serial.println(thisRegister, BIN); +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW); +  // send the device the register you want to read: +  SPI.transfer(dataToSend); +  // send a value of 0 to read the first byte returned: +  result = SPI.transfer(0x00); +  // decrement the number of bytes left to read: +  bytesToRead--; +  // if you still have another byte to read: +  if (bytesToRead > 0) { +    // shift the first byte left, then get the second byte: +    result = result << 8; +    inByte = SPI.transfer(0x00); +    // combine the byte you just got with the previous one: +    result = result | inByte; +    // decrement the number of bytes left to read: +    bytesToRead--; +  } +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH); +  // return the result: +  return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + +  // SCP1000 expects the register address in the upper 6 bits +  // of the byte. So shift the bits left by two bits: +  thisRegister = thisRegister << 2; +  // now combine the register address and the command into one byte: +  byte dataToSend = thisRegister | WRITE; + +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW); + +  SPI.transfer(dataToSend); //Send register location +  SPI.transfer(thisValue);  //Send value to record into register + +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH); +} + diff --git a/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino b/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino new file mode 100644 index 0000000..9c9c9b6 --- /dev/null +++ b/libraries/SPI/examples/BarometricPressureSensor/BarometricPressureSensor/BarometricPressureSensor.ino @@ -0,0 +1,143 @@ +/* +  SCP1000 Barometric Pressure Sensor Display +  + Shows the output of a Barometric Pressure Sensor on a + Uses the SPI library. For details on the sensor, see: + http://www.sparkfun.com/commerce/product_info.php?products_id=8161 + http://www.vti.fi/en/support/obsolete_products/pressure_sensors/ +  + This sketch adapted from Nathan Seidle's SCP1000 example for PIC: + http://www.sparkfun.com/datasheets/Sensors/SCP1000-Testing.zip +  + Circuit: + SCP1000 sensor attached to pins 6, 7, 10 - 13: + DRDY: pin 6 + CSB: pin 7 + MOSI: pin 11 + MISO: pin 12 + SCK: pin 13 +  + created 31 July 2010 + modified 14 August 2010 + by Tom Igoe + */ + +// the sensor communicates using SPI, so include the library: +#include <SPI.h> + +//Sensor's memory register addresses: +const int PRESSURE = 0x1F;      //3 most significant bits of pressure +const int PRESSURE_LSB = 0x20;  //16 least significant bits of pressure +const int TEMPERATURE = 0x21;   //16 bit temperature reading +cont byte READ = 0b00000000;     // SCP1000's read command +const byte WRITE = 0b00000010;   // SCP1000's write command +// pins used for the connection with the sensor +// the other you need are controlled by the SPI library): +const int dataReadyPin = 6;  +const int chipSelectPin = 7; + +void setup() { +  Serial.begin(9600); + +  // start the SPI library: +  SPI.begin(); + +  // initalize the  data ready and chip select pins: +  pinMode(dataReadyPin, INPUT); +  pinMode(chipSelectPin, OUTPUT); + +  //Configure SCP1000 for low noise configuration: +  writeRegister(0x02, 0x2D); +  writeRegister(0x01, 0x03); +  writeRegister(0x03, 0x02); +  // give the sensor time to set up: +  delay(100); +} + +void loop() { +  //Select High Resolution Mode +  writeRegister(0x03, 0x0A); + +  // don't do anything until the data ready pin is high: +  if (digitalRead(dataReadyPin) == HIGH) { +    //Read the temperature data +    int tempData = readRegister(0x21, 2); + +    // convert the temperature to celsius and display it: +    float realTemp = (float)tempData / 20.0; +    Serial.print("Temp[C]="); +    Serial.print(realTemp); + + +    //Read the pressure data highest 3 bits: +    byte  pressure_data_high = readRegister(0x1F, 1);    +    pressure_data_high &= 0b00000111; //you only needs bits 2 to 0 + +    //Read the pressure data lower 16 bits: +    unsigned int pressure_data_low = readRegister(0x20, 2);     +    //combine the two parts into one 19-bit number: +    long pressure = ((pressure_data_high << 16) | pressure_data_low)/4; + +    // display the temperature: +    Serial.println("\tPressure [Pa]=" + String(pressure)); +  } +} + +//Read from or write to register from the SCP1000: +unsigned int readRegister(byte thisRegister, int bytesToRead ) { +  byte inByte = 0;           // incoming byte from the SPI +  unsigned int result = 0;   // result to return  + +  // SCP1000 expects the register name in the upper 6 bits +  // of the byte. So shift the bits left by two bits: +  thisRegister = thisRegister << 2; +  // now combine the address and the command into one byte +  dataToSend = thisRegister & READ; + +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW);  +  // send the device the register you want to read: +  SPI.transfer(dataToSend);  +  // send a value of 0 to read the first byte returned: +  result = SPI.transfer(0x00);  +  // decrement the number of bytes left to read: +  bytesToRead--; +  // if you still have another byte to read: +  if (bytesToRead > 0) { +    // shift the first byte left, then get the second byte:  +    result = result << 8; +    inByte = SPI.transfer(0x00);  +    // combine the byte you just got with the previous one: +    result = result | inByte; +    // decrement the number of bytes left to read: +    bytesToRead--; +  } +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH);  +  // return the result: +  return(result); +} + + +//Sends a write command to SCP1000 + +void writeRegister(byte thisRegister, byte thisValue) { + +  // SCP1000 expects the register address in the upper 6 bits +  // of the byte. So shift the bits left by two bits: +  thisRegister = thisRegister << 2; +  // now combine the register address and the command into one byte: +  dataToSend = thisRegister | WRITE; + +  // take the chip select low to select the device: +  digitalWrite(chipSelectPin, LOW);  + +  SPI.transfer(dataToSend); //Send register location +  SPI.transfer(thisValue);  //Send value to record into register + +  // take the chip select high to de-select: +  digitalWrite(chipSelectPin, HIGH);  +} + + + diff --git a/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino b/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino new file mode 100644 index 0000000..ef97dae --- /dev/null +++ b/libraries/SPI/examples/DigitalPotControl/DigitalPotControl.ino @@ -0,0 +1,71 @@ +/* +  Digital Pot Control +   +  This example controls an Analog Devices AD5206 digital potentiometer. +  The AD5206 has 6 potentiometer channels. Each channel's pins are labeled +  A - connect this to voltage +  W - this is the pot's wiper, which changes when you set it +  B - connect this to ground. +  + The AD5206 is SPI-compatible,and to command it, you send two bytes,  + one with the channel number (0 - 5) and one with the resistance value for the + channel (0 - 255).   +  + The circuit: +  * All A pins  of AD5206 connected to +5V +  * All B pins of AD5206 connected to ground +  * An LED and a 220-ohm resisor in series connected from each W pin to ground +  * CS - to digital pin 10  (SS pin) +  * SDI - to digital pin 11 (MOSI pin) +  * CLK - to digital pin 13 (SCK pin) +  + created 10 Aug 2010  + by Tom Igoe +  + Thanks to Heather Dewey-Hagborg for the original tutorial, 2005 +  +*/ + + +// inslude the SPI library: +#include <SPI.h> + + +// set pin 10 as the slave select for the digital pot: +const int slaveSelectPin = 10; + +void setup() { +  // set the slaveSelectPin as an output: +  pinMode (slaveSelectPin, OUTPUT); +  // initialize SPI: +  SPI.begin();  +} + +void loop() { +  // go through the six channels of the digital pot: +  for (int channel = 0; channel < 6; channel++) {  +    // change the resistance on this channel from min to max: +    for (int level = 0; level < 255; level++) { +      digitalPotWrite(channel, level); +      delay(10); +    } +    // wait a second at the top: +    delay(100); +    // change the resistance on this channel from max to min: +    for (int level = 0; level < 255; level++) { +      digitalPotWrite(channel, 255 - level); +      delay(10); +    } +  } + +} + +int digitalPotWrite(int address, int value) { +  // take the SS pin low to select the chip: +  digitalWrite(slaveSelectPin,LOW); +  //  send in the address and value via SPI: +  SPI.transfer(address); +  SPI.transfer(value); +  // take the SS pin high to de-select the chip: +  digitalWrite(slaveSelectPin,HIGH);  +}
\ No newline at end of file diff --git a/libraries/SPI/keywords.txt b/libraries/SPI/keywords.txt new file mode 100644 index 0000000..fa76165 --- /dev/null +++ b/libraries/SPI/keywords.txt @@ -0,0 +1,36 @@ +####################################### +# Syntax Coloring Map SPI +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +SPI	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin	KEYWORD2 +end	KEYWORD2 +transfer	KEYWORD2 +setBitOrder	KEYWORD2 +setDataMode	KEYWORD2 +setClockDivider	KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### +SPI_CLOCK_DIV4	LITERAL1 +SPI_CLOCK_DIV16	LITERAL1 +SPI_CLOCK_DIV64	LITERAL1 +SPI_CLOCK_DIV128	LITERAL1 +SPI_CLOCK_DIV2	LITERAL1 +SPI_CLOCK_DIV8	LITERAL1 +SPI_CLOCK_DIV32	LITERAL1 +SPI_CLOCK_DIV64	LITERAL1 +SPI_MODE0	LITERAL1 +SPI_MODE1	LITERAL1 +SPI_MODE2	LITERAL1 +SPI_MODE3	LITERAL1
\ No newline at end of file diff --git a/libraries/Servo/Servo.cpp b/libraries/Servo/Servo.cpp new file mode 100644 index 0000000..a716433 --- /dev/null +++ b/libraries/Servo/Servo.cpp @@ -0,0 +1,337 @@ +/*
 + Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
 + Copyright (c) 2009 Michael Margolis.  All right reserved.
 + 
 + This library is free software; you can redistribute it and/or
 + modify it under the terms of the GNU Lesser General Public
 + License as published by the Free Software Foundation; either
 + version 2.1 of the License, or (at your option) any later version.
 + 
 + This library is distributed in the hope that it will be useful,
 + but WITHOUT ANY WARRANTY; without even the implied warranty of
 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 + Lesser General Public License for more details.
 + 
 + You should have received a copy of the GNU Lesser General Public
 + License along with this library; if not, write to the Free Software
 + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 + */
 +
 +/* 
 + 
 + A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method.
 + The servos are pulsed in the background using the value most recently written using the write() method
 + 
 + Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached.
 + Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four.
 + 
 + The methods are:
 + 
 + Servo - Class for manipulating servo motors connected to Arduino pins.
 + 
 + attach(pin )  - Attaches a servo motor to an i/o pin.
 + attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds
 + default min is 544, max is 2400  
 + 
 + write()     - Sets the servo angle in degrees.  (invalid angle that is valid as pulse in microseconds is treated as microseconds)
 + writeMicroseconds() - Sets the servo pulse width in microseconds 
 + read()      - Gets the last written servo pulse width as an angle between 0 and 180. 
 + readMicroseconds()   - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
 + attached()  - Returns true if there is a servo attached. 
 + detach()    - Stops an attached servos from pulsing its i/o pin. 
 + 
 +*/
 +
 +#include <avr/interrupt.h>
 +#include <Arduino.h> 
 +
 +#include "Servo.h"
 +
 +#define usToTicks(_us)    (( clockCyclesPerMicrosecond()* _us) / 8)     // converts microseconds to tick (assumes prescale of 8)  // 12 Aug 2009
 +#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
 +
 +
 +#define TRIM_DURATION       2                               // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
 +
 +//#define NBR_TIMERS        (MAX_SERVOS / SERVOS_PER_TIMER)
 +
 +static servo_t servos[MAX_SERVOS];                          // static array of servo structures
 +static volatile int8_t Channel[_Nbr_16timers ];             // counter for the servo being pulsed for each timer (or -1 if refresh interval)
 +
 +uint8_t ServoCount = 0;                                     // the total number of attached servos
 +
 +
 +// convenience macros
 +#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
 +#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER)       // returns the index of the servo on this timer
 +#define SERVO_INDEX(_timer,_channel)  ((_timer*SERVOS_PER_TIMER) + _channel)     // macro to access servo index by timer and channel
 +#define SERVO(_timer,_channel)  (servos[SERVO_INDEX(_timer,_channel)])            // macro to access servo class by timer and channel
 +
 +#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4)  // minimum value in uS for this servo
 +#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4)  // maximum value in uS for this servo 
 +
 +/************ static functions common to all instances ***********************/
 +
 +static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
 +{
 +  if( Channel[timer] < 0 )
 +    *TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer 
 +  else{
 +    if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )  
 +      digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated   
 +  }
 +
 +  Channel[timer]++;    // increment to the next channel
 +  if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
 +    *OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
 +    if(SERVO(timer,Channel[timer]).Pin.isActive == true)     // check if activated
 +      digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high   
 +  }  
 +  else { 
 +    // finished all channels so wait for the refresh period to expire before starting over 
 +    if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) )  // allow a few ticks to ensure the next OCR1A not missed
 +      *OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);  
 +    else 
 +      *OCRnA = *TCNTn + 4;  // at least REFRESH_INTERVAL has elapsed
 +    Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
 +  }
 +}
 +
 +#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
 +// Interrupt handlers for Arduino 
 +#if defined(_useTimer1)
 +SIGNAL (TIMER1_COMPA_vect) 
 +{ 
 +  handle_interrupts(_timer1, &TCNT1, &OCR1A); 
 +}
 +#endif
 +
 +#if defined(_useTimer3)
 +SIGNAL (TIMER3_COMPA_vect) 
 +{ 
 +  handle_interrupts(_timer3, &TCNT3, &OCR3A); 
 +}
 +#endif
 +
 +#if defined(_useTimer4)
 +SIGNAL (TIMER4_COMPA_vect) 
 +{
 +  handle_interrupts(_timer4, &TCNT4, &OCR4A); 
 +}
 +#endif
 +
 +#if defined(_useTimer5)
 +SIGNAL (TIMER5_COMPA_vect) 
 +{
 +  handle_interrupts(_timer5, &TCNT5, &OCR5A); 
 +}
 +#endif
 +
 +#elif defined WIRING
 +// Interrupt handlers for Wiring 
 +#if defined(_useTimer1)
 +void Timer1Service() 
 +{ 
 +  handle_interrupts(_timer1, &TCNT1, &OCR1A); 
 +}
 +#endif
 +#if defined(_useTimer3)
 +void Timer3Service() 
 +{ 
 +  handle_interrupts(_timer3, &TCNT3, &OCR3A); 
 +}
 +#endif
 +#endif
 +
 +
 +static void initISR(timer16_Sequence_t timer)
 +{  
 +#if defined (_useTimer1)
 +  if(timer == _timer1) {
 +    TCCR1A = 0;             // normal counting mode 
 +    TCCR1B = _BV(CS11);     // set prescaler of 8 
 +    TCNT1 = 0;              // clear the timer count 
 +#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
 +    TIFR |= _BV(OCF1A);      // clear any pending interrupts; 
 +    TIMSK |=  _BV(OCIE1A) ;  // enable the output compare interrupt  
 +#else
 +    // here if not ATmega8 or ATmega128
 +    TIFR1 |= _BV(OCF1A);     // clear any pending interrupts; 
 +    TIMSK1 |=  _BV(OCIE1A) ; // enable the output compare interrupt 
 +#endif    
 +#if defined(WIRING)       
 +    timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service); 
 +#endif	
 +  } 
 +#endif  
 +
 +#if defined (_useTimer3)
 +  if(timer == _timer3) {
 +    TCCR3A = 0;             // normal counting mode 
 +    TCCR3B = _BV(CS31);     // set prescaler of 8  
 +    TCNT3 = 0;              // clear the timer count 
 +#if defined(__AVR_ATmega128__)
 +    TIFR |= _BV(OCF3A);     // clear any pending interrupts;   
 +	ETIMSK |= _BV(OCIE3A);  // enable the output compare interrupt     
 +#else  
 +    TIFR3 = _BV(OCF3A);     // clear any pending interrupts; 
 +    TIMSK3 =  _BV(OCIE3A) ; // enable the output compare interrupt      
 +#endif
 +#if defined(WIRING)    
 +    timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service);  // for Wiring platform only	
 +#endif  
 +  }
 +#endif
 +
 +#if defined (_useTimer4)
 +  if(timer == _timer4) {
 +    TCCR4A = 0;             // normal counting mode 
 +    TCCR4B = _BV(CS41);     // set prescaler of 8  
 +    TCNT4 = 0;              // clear the timer count 
 +    TIFR4 = _BV(OCF4A);     // clear any pending interrupts; 
 +    TIMSK4 =  _BV(OCIE4A) ; // enable the output compare interrupt
 +  }    
 +#endif
 +
 +#if defined (_useTimer5)
 +  if(timer == _timer5) {
 +    TCCR5A = 0;             // normal counting mode 
 +    TCCR5B = _BV(CS51);     // set prescaler of 8  
 +    TCNT5 = 0;              // clear the timer count 
 +    TIFR5 = _BV(OCF5A);     // clear any pending interrupts; 
 +    TIMSK5 =  _BV(OCIE5A) ; // enable the output compare interrupt      
 +  }
 +#endif
 +} 
 +
 +static void finISR(timer16_Sequence_t timer)
 +{
 +    //disable use of the given timer
 +#if defined WIRING   // Wiring
 +  if(timer == _timer1) {
 +    #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
 +    TIMSK1 &=  ~_BV(OCIE1A) ;  // disable timer 1 output compare interrupt
 +    #else 
 +    TIMSK &=  ~_BV(OCIE1A) ;  // disable timer 1 output compare interrupt   
 +    #endif
 +    timerDetach(TIMER1OUTCOMPAREA_INT); 
 +  }
 +  else if(timer == _timer3) {     
 +    #if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
 +    TIMSK3 &= ~_BV(OCIE3A);    // disable the timer3 output compare A interrupt
 +    #else
 +    ETIMSK &= ~_BV(OCIE3A);    // disable the timer3 output compare A interrupt
 +    #endif
 +    timerDetach(TIMER3OUTCOMPAREA_INT);
 +  }
 +#else
 +    //For arduino - in future: call here to a currently undefined function to reset the timer
 +#endif
 +}
 +
 +static boolean isTimerActive(timer16_Sequence_t timer)
 +{
 +  // returns true if any servo is active on this timer
 +  for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
 +    if(SERVO(timer,channel).Pin.isActive == true)
 +      return true;
 +  }
 +  return false;
 +}
 +
 +
 +/****************** end of static functions ******************************/
 +
 +Servo::Servo()
 +{
 +  if( ServoCount < MAX_SERVOS) {
 +    this->servoIndex = ServoCount++;                    // assign a servo index to this instance
 +	servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH);   // store default values  - 12 Aug 2009
 +  }
 +  else
 +    this->servoIndex = INVALID_SERVO ;  // too many servos 
 +}
 +
 +uint8_t Servo::attach(int pin)
 +{
 +  return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
 +}
 +
 +uint8_t Servo::attach(int pin, int min, int max)
 +{
 +  if(this->servoIndex < MAX_SERVOS ) {
 +    pinMode( pin, OUTPUT) ;                                   // set servo pin to output
 +    servos[this->servoIndex].Pin.nbr = pin;  
 +    // todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128 
 +    this->min  = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
 +    this->max  = (MAX_PULSE_WIDTH - max)/4; 
 +    // initialize the timer if it has not already been initialized 
 +    timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
 +    if(isTimerActive(timer) == false)
 +      initISR(timer);    
 +    servos[this->servoIndex].Pin.isActive = true;  // this must be set after the check for isTimerActive
 +  } 
 +  return this->servoIndex ;
 +}
 +
 +void Servo::detach()  
 +{
 +  servos[this->servoIndex].Pin.isActive = false;  
 +  timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
 +  if(isTimerActive(timer) == false) {
 +    finISR(timer);
 +  }
 +}
 +
 +void Servo::write(int value)
 +{  
 +  if(value < MIN_PULSE_WIDTH)
 +  {  // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
 +    if(value < 0) value = 0;
 +    if(value > 180) value = 180;
 +    value = map(value, 0, 180, SERVO_MIN(),  SERVO_MAX());      
 +  }
 +  this->writeMicroseconds(value);
 +}
 +
 +void Servo::writeMicroseconds(int value)
 +{
 +  // calculate and store the values for the given channel
 +  byte channel = this->servoIndex;
 +  if( (channel < MAX_SERVOS) )   // ensure channel is valid
 +  {  
 +    if( value < SERVO_MIN() )          // ensure pulse width is valid
 +      value = SERVO_MIN();
 +    else if( value > SERVO_MAX() )
 +      value = SERVO_MAX();   
 +    
 +  	value = value - TRIM_DURATION;
 +    value = usToTicks(value);  // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
 +
 +    uint8_t oldSREG = SREG;
 +    cli();
 +    servos[channel].ticks = value;  
 +    SREG = oldSREG;   
 +  } 
 +}
 +
 +int Servo::read() // return the value as degrees
 +{
 +  return  map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);     
 +}
 +
 +int Servo::readMicroseconds()
 +{
 +  unsigned int pulsewidth;
 +  if( this->servoIndex != INVALID_SERVO )
 +    pulsewidth = ticksToUs(servos[this->servoIndex].ticks)  + TRIM_DURATION ;   // 12 aug 2009
 +  else 
 +    pulsewidth  = 0;
 +
 +  return pulsewidth;   
 +}
 +
 +bool Servo::attached()
 +{
 +  return servos[this->servoIndex].Pin.isActive ;
 +}
 diff --git a/libraries/Servo/Servo.h b/libraries/Servo/Servo.h new file mode 100644 index 0000000..8168494 --- /dev/null +++ b/libraries/Servo/Servo.h @@ -0,0 +1,126 @@ +/* +  Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2 +  Copyright (c) 2009 Michael Margolis.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +/*  +   +  A servo is activated by creating an instance of the Servo class passing the desired pin to the attach() method. +  The servos are pulsed in the background using the value most recently written using the write() method + +  Note that analogWrite of PWM on pins associated with the timer are disabled when the first servo is attached. +  Timers are seized as needed in groups of 12 servos - 24 servos use two timers, 48 servos will use four. +  The sequence used to sieze timers is defined in timers.h + +  The methods are: + +   Servo - Class for manipulating servo motors connected to Arduino pins. + +   attach(pin )  - Attaches a servo motor to an i/o pin. +   attach(pin, min, max  ) - Attaches to a pin setting min and max values in microseconds +   default min is 544, max is 2400   +  +   write()     - Sets the servo angle in degrees.  (invalid angle that is valid as pulse in microseconds is treated as microseconds) +   writeMicroseconds() - Sets the servo pulse width in microseconds  +   read()      - Gets the last written servo pulse width as an angle between 0 and 180.  +   readMicroseconds()   - Gets the last written servo pulse width in microseconds. (was read_us() in first release) +   attached()  - Returns true if there is a servo attached.  +   detach()    - Stops an attached servos from pulsing its i/o pin.  + */ + +#ifndef Servo_h +#define Servo_h + +#include <inttypes.h> + +/*  + * Defines for 16 bit timers used with  Servo library  + * + * If _useTimerX is defined then TimerX is a 16 bit timer on the curent board + * timer16_Sequence_t enumerates the sequence that the timers should be allocated + * _Nbr_16timers indicates how many 16 bit timers are available. + * + */ + +// Say which 16 bit timers can be used and in what order +#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define _useTimer5 +#define _useTimer1  +#define _useTimer3 +#define _useTimer4  +typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t ; + +#elif defined(__AVR_ATmega32U4__)   +#define _useTimer1  +typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ; + +#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) +#define _useTimer3 +#define _useTimer1 +typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ; + +#elif defined(__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) +#define _useTimer3 +#define _useTimer1 +typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t ; + +#else  // everything else +#define _useTimer1 +typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t ;                   +#endif + +#define Servo_VERSION           2      // software version of this library + +#define MIN_PULSE_WIDTH       544     // the shortest pulse sent to a servo   +#define MAX_PULSE_WIDTH      2400     // the longest pulse sent to a servo  +#define DEFAULT_PULSE_WIDTH  1500     // default pulse width when servo is attached +#define REFRESH_INTERVAL    20000     // minumim time to refresh servos in microseconds  + +#define SERVOS_PER_TIMER       12     // the maximum number of servos controlled by one timer  +#define MAX_SERVOS   (_Nbr_16timers  * SERVOS_PER_TIMER) + +#define INVALID_SERVO         255     // flag indicating an invalid servo index + +typedef struct  { +  uint8_t nbr        :6 ;             // a pin number from 0 to 63 +  uint8_t isActive   :1 ;             // true if this channel is enabled, pin not pulsed if false  +} ServoPin_t   ;   + +typedef struct { +  ServoPin_t Pin; +  unsigned int ticks; +} servo_t; + +class Servo +{ +public: +  Servo(); +  uint8_t attach(int pin);           // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure +  uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.  +  void detach(); +  void write(int value);             // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds  +  void writeMicroseconds(int value); // Write pulse width in microseconds  +  int read();                        // returns current pulse width as an angle between 0 and 180 degrees +  int readMicroseconds();            // returns current pulse width in microseconds for this servo (was read_us() in first release) +  bool attached();                   // return true if this servo is attached, otherwise false  +private: +   uint8_t servoIndex;               // index into the channel data for this servo +   int8_t min;                       // minimum is this value times 4 added to MIN_PULSE_WIDTH     +   int8_t max;                       // maximum is this value times 4 added to MAX_PULSE_WIDTH    +}; + +#endif diff --git a/libraries/Servo/examples/Knob/Knob.ino b/libraries/Servo/examples/Knob/Knob.ino new file mode 100644 index 0000000..886e107 --- /dev/null +++ b/libraries/Servo/examples/Knob/Knob.ino @@ -0,0 +1,22 @@ +// Controlling a servo position using a potentiometer (variable resistor)  +// by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>  + +#include <Servo.h>  +  +Servo myservo;  // create servo object to control a servo  +  +int potpin = 0;  // analog pin used to connect the potentiometer +int val;    // variable to read the value from the analog pin  +  +void setup()  +{  +  myservo.attach(9);  // attaches the servo on pin 9 to the servo object  +}  +  +void loop()  +{  +  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)  +  val = map(val, 0, 1023, 0, 179);     // scale it to use it with the servo (value between 0 and 180)  +  myservo.write(val);                  // sets the servo position according to the scaled value  +  delay(15);                           // waits for the servo to get there  +}  diff --git a/libraries/Servo/examples/Sweep/Sweep.ino b/libraries/Servo/examples/Sweep/Sweep.ino new file mode 100644 index 0000000..fb326e7 --- /dev/null +++ b/libraries/Servo/examples/Sweep/Sweep.ino @@ -0,0 +1,31 @@ +// Sweep +// by BARRAGAN <http://barraganstudio.com>  +// This example code is in the public domain. + + +#include <Servo.h>  +  +Servo myservo;  // create servo object to control a servo  +                // a maximum of eight servo objects can be created  +  +int pos = 0;    // variable to store the servo position  +  +void setup()  +{  +  myservo.attach(9);  // attaches the servo on pin 9 to the servo object  +}  +  +  +void loop()  +{  +  for(pos = 0; pos < 180; pos += 1)  // goes from 0 degrees to 180 degrees  +  {                                  // in steps of 1 degree  +    myservo.write(pos);              // tell servo to go to position in variable 'pos'  +    delay(15);                       // waits 15ms for the servo to reach the position  +  }  +  for(pos = 180; pos>=1; pos-=1)     // goes from 180 degrees to 0 degrees  +  {                                 +    myservo.write(pos);              // tell servo to go to position in variable 'pos'  +    delay(15);                       // waits 15ms for the servo to reach the position  +  }  +}  diff --git a/libraries/Servo/keywords.txt b/libraries/Servo/keywords.txt new file mode 100644 index 0000000..ca5ba79 --- /dev/null +++ b/libraries/Servo/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map Servo +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Servo	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +attach	KEYWORD2 +detach	KEYWORD2 +write	KEYWORD2 +read	KEYWORD2 +attached	KEYWORD2 +writeMicroseconds	KEYWORD2 +readMicroseconds	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/SoftwareSerial/SoftwareSerial.cpp b/libraries/SoftwareSerial/SoftwareSerial.cpp new file mode 100644 index 0000000..64496fe --- /dev/null +++ b/libraries/SoftwareSerial/SoftwareSerial.cpp @@ -0,0 +1,518 @@ +/*
 +SoftwareSerial.cpp (formerly NewSoftSerial.cpp) - 
 +Multi-instance software serial library for Arduino/Wiring
 +-- Interrupt-driven receive and other improvements by ladyada
 +   (http://ladyada.net)
 +-- Tuning, circular buffer, derivation from class Print/Stream,
 +   multi-instance support, porting to 8MHz processors,
 +   various optimizations, PROGMEM delay tables, inverse logic and 
 +   direct port writing by Mikal Hart (http://www.arduiniana.org)
 +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
 +-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
 +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
 +
 +This library is free software; you can redistribute it and/or
 +modify it under the terms of the GNU Lesser General Public
 +License as published by the Free Software Foundation; either
 +version 2.1 of the License, or (at your option) any later version.
 +
 +This library is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +Lesser General Public License for more details.
 +
 +You should have received a copy of the GNU Lesser General Public
 +License along with this library; if not, write to the Free Software
 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 +
 +The latest version of this library can always be found at
 +http://arduiniana.org.
 +*/
 +
 +// When set, _DEBUG co-opts pins 11 and 13 for debugging with an
 +// oscilloscope or logic analyzer.  Beware: it also slightly modifies
 +// the bit times, so don't rely on it too much at high baud rates
 +#define _DEBUG 0
 +#define _DEBUG_PIN1 11
 +#define _DEBUG_PIN2 13
 +// 
 +// Includes
 +// 
 +#include <avr/interrupt.h>
 +#include <avr/pgmspace.h>
 +#include <Arduino.h>
 +#include <SoftwareSerial.h>
 +//
 +// Lookup table
 +//
 +typedef struct _DELAY_TABLE
 +{
 +  long baud;
 +  unsigned short rx_delay_centering;
 +  unsigned short rx_delay_intrabit;
 +  unsigned short rx_delay_stopbit;
 +  unsigned short tx_delay;
 +} DELAY_TABLE;
 +
 +#if F_CPU == 16000000
 +
 +static const DELAY_TABLE PROGMEM table[] = 
 +{
 +  //  baud    rxcenter   rxintra    rxstop    tx
 +  { 115200,   1,         17,        17,       12,    },
 +  { 57600,    10,        37,        37,       33,    },
 +  { 38400,    25,        57,        57,       54,    },
 +  { 31250,    31,        70,        70,       68,    },
 +  { 28800,    34,        77,        77,       74,    },
 +  { 19200,    54,        117,       117,      114,   },
 +  { 14400,    74,        156,       156,      153,   },
 +  { 9600,     114,       236,       236,      233,   },
 +  { 4800,     233,       474,       474,      471,   },
 +  { 2400,     471,       950,       950,      947,   },
 +  { 1200,     947,       1902,      1902,     1899,  },
 +  { 600,      1902,      3804,      3804,     3800,  },
 +  { 300,      3804,      7617,      7617,     7614,  },
 +};
 +
 +const int XMIT_START_ADJUSTMENT = 5;
 +
 +#elif F_CPU == 8000000
 +
 +static const DELAY_TABLE table[] PROGMEM = 
 +{
 +  //  baud    rxcenter    rxintra    rxstop  tx
 +  { 115200,   1,          5,         5,      3,      },
 +  { 57600,    1,          15,        15,     13,     },
 +  { 38400,    2,          25,        26,     23,     },
 +  { 31250,    7,          32,        33,     29,     },
 +  { 28800,    11,         35,        35,     32,     },
 +  { 19200,    20,         55,        55,     52,     },
 +  { 14400,    30,         75,        75,     72,     },
 +  { 9600,     50,         114,       114,    112,    },
 +  { 4800,     110,        233,       233,    230,    },
 +  { 2400,     229,        472,       472,    469,    },
 +  { 1200,     467,        948,       948,    945,    },
 +  { 600,      948,        1895,      1895,   1890,   },
 +  { 300,      1895,       3805,      3805,   3802,   },
 +};
 +
 +const int XMIT_START_ADJUSTMENT = 4;
 +
 +#elif F_CPU == 20000000
 +
 +// 20MHz support courtesy of the good people at macegr.com.
 +// Thanks, Garrett!
 +
 +static const DELAY_TABLE PROGMEM table[] =
 +{
 +  //  baud    rxcenter    rxintra    rxstop  tx
 +  { 115200,   3,          21,        21,     18,     },
 +  { 57600,    20,         43,        43,     41,     },
 +  { 38400,    37,         73,        73,     70,     },
 +  { 31250,    45,         89,        89,     88,     },
 +  { 28800,    46,         98,        98,     95,     },
 +  { 19200,    71,         148,       148,    145,    },
 +  { 14400,    96,         197,       197,    194,    },
 +  { 9600,     146,        297,       297,    294,    },
 +  { 4800,     296,        595,       595,    592,    },
 +  { 2400,     592,        1189,      1189,   1186,   },
 +  { 1200,     1187,       2379,      2379,   2376,   },
 +  { 600,      2379,       4759,      4759,   4755,   },
 +  { 300,      4759,       9523,      9523,   9520,   },
 +};
 +
 +const int XMIT_START_ADJUSTMENT = 6;
 +
 +#else
 +
 +#error This version of SoftwareSerial supports only 20, 16 and 8MHz processors
 +
 +#endif
 +
 +//
 +// Statics
 +//
 +SoftwareSerial *SoftwareSerial::active_object = 0;
 +char SoftwareSerial::_receive_buffer[_SS_MAX_RX_BUFF]; 
 +volatile uint8_t SoftwareSerial::_receive_buffer_tail = 0;
 +volatile uint8_t SoftwareSerial::_receive_buffer_head = 0;
 +
 +//
 +// Debugging
 +//
 +// This function generates a brief pulse
 +// for debugging or measuring on an oscilloscope.
 +inline void DebugPulse(uint8_t pin, uint8_t count)
 +{
 +#if _DEBUG
 +  volatile uint8_t *pport = portOutputRegister(digitalPinToPort(pin));
 +
 +  uint8_t val = *pport;
 +  while (count--)
 +  {
 +    *pport = val | digitalPinToBitMask(pin);
 +    *pport = val;
 +  }
 +#endif
 +}
 +
 +//
 +// Private methods
 +//
 +
 +/* static */ 
 +inline void SoftwareSerial::tunedDelay(uint16_t delay) { 
 +  uint8_t tmp=0;
 +
 +  asm volatile("sbiw    %0, 0x01 \n\t"
 +    "ldi %1, 0xFF \n\t"
 +    "cpi %A0, 0xFF \n\t"
 +    "cpc %B0, %1 \n\t"
 +    "brne .-10 \n\t"
 +    : "+r" (delay), "+a" (tmp)
 +    : "0" (delay)
 +    );
 +}
 +
 +// This function sets the current object as the "listening"
 +// one and returns true if it replaces another 
 +bool SoftwareSerial::listen()
 +{
 +  if (active_object != this)
 +  {
 +    _buffer_overflow = false;
 +    uint8_t oldSREG = SREG;
 +    cli();
 +    _receive_buffer_head = _receive_buffer_tail = 0;
 +    active_object = this;
 +    SREG = oldSREG;
 +    return true;
 +  }
 +
 +  return false;
 +}
 +
 +//
 +// The receive routine called by the interrupt handler
 +//
 +void SoftwareSerial::recv()
 +{
 +
 +#if GCC_VERSION < 40302
 +// Work-around for avr-gcc 4.3.0 OSX version bug
 +// Preserve the registers that the compiler misses
 +// (courtesy of Arduino forum user *etracer*)
 +  asm volatile(
 +    "push r18 \n\t"
 +    "push r19 \n\t"
 +    "push r20 \n\t"
 +    "push r21 \n\t"
 +    "push r22 \n\t"
 +    "push r23 \n\t"
 +    "push r26 \n\t"
 +    "push r27 \n\t"
 +    ::);
 +#endif  
 +
 +  uint8_t d = 0;
 +
 +  // If RX line is high, then we don't see any start bit
 +  // so interrupt is probably not for us
 +  if (_inverse_logic ? rx_pin_read() : !rx_pin_read())
 +  {
 +    // Wait approximately 1/2 of a bit width to "center" the sample
 +    tunedDelay(_rx_delay_centering);
 +    DebugPulse(_DEBUG_PIN2, 1);
 +
 +    // Read each of the 8 bits
 +    for (uint8_t i=0x1; i; i <<= 1)
 +    {
 +      tunedDelay(_rx_delay_intrabit);
 +      DebugPulse(_DEBUG_PIN2, 1);
 +      uint8_t noti = ~i;
 +      if (rx_pin_read())
 +        d |= i;
 +      else // else clause added to ensure function timing is ~balanced
 +        d &= noti;
 +    }
 +
 +    // skip the stop bit
 +    tunedDelay(_rx_delay_stopbit);
 +    DebugPulse(_DEBUG_PIN2, 1);
 +
 +    if (_inverse_logic)
 +      d = ~d;
 +
 +    // if buffer full, set the overflow flag and return
 +    if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head) 
 +    {
 +      // save new data in buffer: tail points to where byte goes
 +      _receive_buffer[_receive_buffer_tail] = d; // save new byte
 +      _receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
 +    } 
 +    else 
 +    {
 +#if _DEBUG // for scope: pulse pin as overflow indictator
 +      DebugPulse(_DEBUG_PIN1, 1);
 +#endif
 +      _buffer_overflow = true;
 +    }
 +  }
 +
 +#if GCC_VERSION < 40302
 +// Work-around for avr-gcc 4.3.0 OSX version bug
 +// Restore the registers that the compiler misses
 +  asm volatile(
 +    "pop r27 \n\t"
 +    "pop r26 \n\t"
 +    "pop r23 \n\t"
 +    "pop r22 \n\t"
 +    "pop r21 \n\t"
 +    "pop r20 \n\t"
 +    "pop r19 \n\t"
 +    "pop r18 \n\t"
 +    ::);
 +#endif
 +}
 +
 +void SoftwareSerial::tx_pin_write(uint8_t pin_state)
 +{
 +  if (pin_state == LOW)
 +    *_transmitPortRegister &= ~_transmitBitMask;
 +  else
 +    *_transmitPortRegister |= _transmitBitMask;
 +}
 +
 +uint8_t SoftwareSerial::rx_pin_read()
 +{
 +  return *_receivePortRegister & _receiveBitMask;
 +}
 +
 +//
 +// Interrupt handling
 +//
 +
 +/* static */
 +inline void SoftwareSerial::handle_interrupt()
 +{
 +  if (active_object)
 +  {
 +    active_object->recv();
 +  }
 +}
 +
 +#if defined(PCINT0_vect)
 +ISR(PCINT0_vect)
 +{
 +  SoftwareSerial::handle_interrupt();
 +}
 +#endif
 +
 +#if defined(PCINT1_vect)
 +ISR(PCINT1_vect)
 +{
 +  SoftwareSerial::handle_interrupt();
 +}
 +#endif
 +
 +#if defined(PCINT2_vect)
 +ISR(PCINT2_vect)
 +{
 +  SoftwareSerial::handle_interrupt();
 +}
 +#endif
 +
 +#if defined(PCINT3_vect)
 +ISR(PCINT3_vect)
 +{
 +  SoftwareSerial::handle_interrupt();
 +}
 +#endif
 +
 +//
 +// Constructor
 +//
 +SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */) : 
 +  _rx_delay_centering(0),
 +  _rx_delay_intrabit(0),
 +  _rx_delay_stopbit(0),
 +  _tx_delay(0),
 +  _buffer_overflow(false),
 +  _inverse_logic(inverse_logic)
 +{
 +  setTX(transmitPin);
 +  setRX(receivePin);
 +}
 +
 +//
 +// Destructor
 +//
 +SoftwareSerial::~SoftwareSerial()
 +{
 +  end();
 +}
 +
 +void SoftwareSerial::setTX(uint8_t tx)
 +{
 +  pinMode(tx, OUTPUT);
 +  digitalWrite(tx, HIGH);
 +  _transmitBitMask = digitalPinToBitMask(tx);
 +  uint8_t port = digitalPinToPort(tx);
 +  _transmitPortRegister = portOutputRegister(port);
 +}
 +
 +void SoftwareSerial::setRX(uint8_t rx)
 +{
 +  pinMode(rx, INPUT);
 +  if (!_inverse_logic)
 +    digitalWrite(rx, HIGH);  // pullup for normal logic!
 +  _receivePin = rx;
 +  _receiveBitMask = digitalPinToBitMask(rx);
 +  uint8_t port = digitalPinToPort(rx);
 +  _receivePortRegister = portInputRegister(port);
 +}
 +
 +//
 +// Public methods
 +//
 +
 +void SoftwareSerial::begin(long speed)
 +{
 +  _rx_delay_centering = _rx_delay_intrabit = _rx_delay_stopbit = _tx_delay = 0;
 +
 +  for (unsigned i=0; i<sizeof(table)/sizeof(table[0]); ++i)
 +  {
 +    long baud = pgm_read_dword(&table[i].baud);
 +    if (baud == speed)
 +    {
 +      _rx_delay_centering = pgm_read_word(&table[i].rx_delay_centering);
 +      _rx_delay_intrabit = pgm_read_word(&table[i].rx_delay_intrabit);
 +      _rx_delay_stopbit = pgm_read_word(&table[i].rx_delay_stopbit);
 +      _tx_delay = pgm_read_word(&table[i].tx_delay);
 +      break;
 +    }
 +  }
 +
 +  // Set up RX interrupts, but only if we have a valid RX baud rate
 +  if (_rx_delay_stopbit)
 +  {
 +    if (digitalPinToPCICR(_receivePin))
 +    {
 +      *digitalPinToPCICR(_receivePin) |= _BV(digitalPinToPCICRbit(_receivePin));
 +      *digitalPinToPCMSK(_receivePin) |= _BV(digitalPinToPCMSKbit(_receivePin));
 +    }
 +    tunedDelay(_tx_delay); // if we were low this establishes the end
 +  }
 +
 +#if _DEBUG
 +  pinMode(_DEBUG_PIN1, OUTPUT);
 +  pinMode(_DEBUG_PIN2, OUTPUT);
 +#endif
 +
 +  listen();
 +}
 +
 +void SoftwareSerial::end()
 +{
 +  if (digitalPinToPCMSK(_receivePin))
 +    *digitalPinToPCMSK(_receivePin) &= ~_BV(digitalPinToPCMSKbit(_receivePin));
 +}
 +
 +
 +// Read data from buffer
 +int SoftwareSerial::read()
 +{
 +  if (!isListening())
 +    return -1;
 +
 +  // Empty buffer?
 +  if (_receive_buffer_head == _receive_buffer_tail)
 +    return -1;
 +
 +  // Read from "head"
 +  uint8_t d = _receive_buffer[_receive_buffer_head]; // grab next byte
 +  _receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
 +  return d;
 +}
 +
 +int SoftwareSerial::available()
 +{
 +  if (!isListening())
 +    return 0;
 +
 +  return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
 +}
 +
 +size_t SoftwareSerial::write(uint8_t b)
 +{
 +  if (_tx_delay == 0) {
 +    setWriteError();
 +    return 0;
 +  }
 +
 +  uint8_t oldSREG = SREG;
 +  cli();  // turn off interrupts for a clean txmit
 +
 +  // Write the start bit
 +  tx_pin_write(_inverse_logic ? HIGH : LOW);
 +  tunedDelay(_tx_delay + XMIT_START_ADJUSTMENT);
 +
 +  // Write each of the 8 bits
 +  if (_inverse_logic)
 +  {
 +    for (byte mask = 0x01; mask; mask <<= 1)
 +    {
 +      if (b & mask) // choose bit
 +        tx_pin_write(LOW); // send 1
 +      else
 +        tx_pin_write(HIGH); // send 0
 +    
 +      tunedDelay(_tx_delay);
 +    }
 +
 +    tx_pin_write(LOW); // restore pin to natural state
 +  }
 +  else
 +  {
 +    for (byte mask = 0x01; mask; mask <<= 1)
 +    {
 +      if (b & mask) // choose bit
 +        tx_pin_write(HIGH); // send 1
 +      else
 +        tx_pin_write(LOW); // send 0
 +    
 +      tunedDelay(_tx_delay);
 +    }
 +
 +    tx_pin_write(HIGH); // restore pin to natural state
 +  }
 +
 +  SREG = oldSREG; // turn interrupts back on
 +  tunedDelay(_tx_delay);
 +  
 +  return 1;
 +}
 +
 +void SoftwareSerial::flush()
 +{
 +  if (!isListening())
 +    return;
 +
 +  uint8_t oldSREG = SREG;
 +  cli();
 +  _receive_buffer_head = _receive_buffer_tail = 0;
 +  SREG = oldSREG;
 +}
 +
 +int SoftwareSerial::peek()
 +{
 +  if (!isListening())
 +    return -1;
 +
 +  // Empty buffer?
 +  if (_receive_buffer_head == _receive_buffer_tail)
 +    return -1;
 +
 +  // Read from "head"
 +  return _receive_buffer[_receive_buffer_head];
 +}
 diff --git a/libraries/SoftwareSerial/SoftwareSerial.h b/libraries/SoftwareSerial/SoftwareSerial.h new file mode 100644 index 0000000..a6a60b5 --- /dev/null +++ b/libraries/SoftwareSerial/SoftwareSerial.h @@ -0,0 +1,112 @@ +/*
 +SoftwareSerial.h (formerly NewSoftSerial.h) - 
 +Multi-instance software serial library for Arduino/Wiring
 +-- Interrupt-driven receive and other improvements by ladyada
 +   (http://ladyada.net)
 +-- Tuning, circular buffer, derivation from class Print/Stream,
 +   multi-instance support, porting to 8MHz processors,
 +   various optimizations, PROGMEM delay tables, inverse logic and 
 +   direct port writing by Mikal Hart (http://www.arduiniana.org)
 +-- Pin change interrupt macros by Paul Stoffregen (http://www.pjrc.com)
 +-- 20MHz processor support by Garrett Mace (http://www.macetech.com)
 +-- ATmega1280/2560 support by Brett Hagman (http://www.roguerobotics.com/)
 +
 +This library is free software; you can redistribute it and/or
 +modify it under the terms of the GNU Lesser General Public
 +License as published by the Free Software Foundation; either
 +version 2.1 of the License, or (at your option) any later version.
 +
 +This library is distributed in the hope that it will be useful,
 +but WITHOUT ANY WARRANTY; without even the implied warranty of
 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 +Lesser General Public License for more details.
 +
 +You should have received a copy of the GNU Lesser General Public
 +License along with this library; if not, write to the Free Software
 +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 +
 +The latest version of this library can always be found at
 +http://arduiniana.org.
 +*/
 +
 +#ifndef SoftwareSerial_h
 +#define SoftwareSerial_h
 +
 +#include <inttypes.h>
 +#include <Stream.h>
 +
 +/******************************************************************************
 +* Definitions
 +******************************************************************************/
 +
 +#define _SS_MAX_RX_BUFF 64 // RX buffer size
 +#ifndef GCC_VERSION
 +#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
 +#endif
 +
 +class SoftwareSerial : public Stream
 +{
 +private:
 +  // per object data
 +  uint8_t _receivePin;
 +  uint8_t _receiveBitMask;
 +  volatile uint8_t *_receivePortRegister;
 +  uint8_t _transmitBitMask;
 +  volatile uint8_t *_transmitPortRegister;
 +
 +  uint16_t _rx_delay_centering;
 +  uint16_t _rx_delay_intrabit;
 +  uint16_t _rx_delay_stopbit;
 +  uint16_t _tx_delay;
 +
 +  uint16_t _buffer_overflow:1;
 +  uint16_t _inverse_logic:1;
 +
 +  // static data
 +  static char _receive_buffer[_SS_MAX_RX_BUFF]; 
 +  static volatile uint8_t _receive_buffer_tail;
 +  static volatile uint8_t _receive_buffer_head;
 +  static SoftwareSerial *active_object;
 +
 +  // private methods
 +  void recv();
 +  uint8_t rx_pin_read();
 +  void tx_pin_write(uint8_t pin_state);
 +  void setTX(uint8_t transmitPin);
 +  void setRX(uint8_t receivePin);
 +
 +  // private static method for timing
 +  static inline void tunedDelay(uint16_t delay);
 +
 +public:
 +  // public methods
 +  SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic = false);
 +  ~SoftwareSerial();
 +  void begin(long speed);
 +  bool listen();
 +  void end();
 +  bool isListening() { return this == active_object; }
 +  bool overflow() { bool ret = _buffer_overflow; _buffer_overflow = false; return ret; }
 +  int peek();
 +
 +  virtual size_t write(uint8_t byte);
 +  virtual int read();
 +  virtual int available();
 +  virtual void flush();
 +  
 +  using Print::write;
 +
 +  // public only for easy access by interrupt handlers
 +  static inline void handle_interrupt();
 +};
 +
 +// Arduino 0012 workaround
 +#undef int
 +#undef char
 +#undef long
 +#undef byte
 +#undef float
 +#undef abs
 +#undef round
 +
 +#endif
 diff --git a/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino new file mode 100644 index 0000000..6101bb1 --- /dev/null +++ b/libraries/SoftwareSerial/examples/SoftwareSerialExample/SoftwareSerialExample.ino @@ -0,0 +1,55 @@ +/* +  Software serial multple serial test +  + Receives from the hardware serial, sends to software serial. + Receives from software serial, sends to hardware serial. +  + The circuit:  + * RX is digital pin 10 (connect to TX of other device) + * TX is digital pin 11 (connect to RX of other device) +  + Note: + Not all pins on the Mega and Mega 2560 support change interrupts,  + so only the following can be used for RX:  + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 +  + Not all pins on the Leonardo support change interrupts,  + so only the following can be used for RX:  + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). +  + created back in the mists of time + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's example +  + This example code is in the public domain. +  + */ +#include <SoftwareSerial.h> + +SoftwareSerial mySerial(10, 11); // RX, TX + +void setup()   +{ +  // Open serial communications and wait for port to open: +  Serial.begin(57600); +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  Serial.println("Goodnight moon!"); + +  // set the data rate for the SoftwareSerial port +  mySerial.begin(4800); +  mySerial.println("Hello, world?"); +} + +void loop() // run over and over +{ +  if (mySerial.available()) +    Serial.write(mySerial.read()); +  if (Serial.available()) +    mySerial.write(Serial.read()); +} + diff --git a/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino new file mode 100644 index 0000000..d607ee6 --- /dev/null +++ b/libraries/SoftwareSerial/examples/TwoPortReceive/TwoPortReceive.ino @@ -0,0 +1,93 @@ +/* +  Software serial multple serial test +  + Receives from the two software serial ports,  + sends to the hardware serial port.  +  + In order to listen on a software port, you call port.listen().  + When using two software serial ports, you have to switch ports + by listen()ing on each one in turn. Pick a logical time to switch + ports, like the end of an expected transmission, or when the  + buffer is empty. This example switches ports when there is nothing + more to read from a port +  + The circuit:  + Two devices which communicate serially are needed. + * First serial device's TX attached to digital pin 2, RX to pin 3 + * Second serial device's TX attached to digital pin 4, RX to pin 5 +  + Note: + Not all pins on the Mega and Mega 2560 support change interrupts,  + so only the following can be used for RX:  + 10, 11, 12, 13, 50, 51, 52, 53, 62, 63, 64, 65, 66, 67, 68, 69 +  + Not all pins on the Leonardo support change interrupts,  + so only the following can be used for RX:  + 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI). +  + created 18 Apr. 2011 + modified 25 May 2012 + by Tom Igoe + based on Mikal Hart's twoPortRXExample +  + This example code is in the public domain. +  + */ + +#include <SoftwareSerial.h> +// software serial #1: TX = digital pin 10, RX = digital pin 11 +SoftwareSerial portOne(10,11); + +// software serial #2: TX = digital pin 8, RX = digital pin 9 +// on the Mega, use other pins instead, since 8 and 9 don't work on the Mega +SoftwareSerial portTwo(8,9); + +void setup() +{ + // Open serial communications and wait for port to open: +  Serial.begin(9600); +   while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + + +  // Start each software serial port +  portOne.begin(9600); +  portTwo.begin(9600); +} + +void loop() +{ +  // By default, the last intialized port is listening. +  // when you want to listen on a port, explicitly select it: +  portOne.listen(); +  Serial.println("Data from port one:"); +  // while there is data coming in, read it +  // and send to the hardware serial port: +  while (portOne.available() > 0) { +    char inByte = portOne.read(); +    Serial.write(inByte); +  } + +  // blank line to separate data from the two ports: +  Serial.println(); + +  // Now listen on the second port +  portTwo.listen(); +  // while there is data coming in, read it +  // and send to the hardware serial port: +  Serial.println("Data from port two:"); +  while (portTwo.available() > 0) { +    char inByte = portTwo.read(); +    Serial.write(inByte); +  } + +  // blank line to separate data from the two ports: +  Serial.println(); +} + + + + + + diff --git a/libraries/SoftwareSerial/keywords.txt b/libraries/SoftwareSerial/keywords.txt new file mode 100644 index 0000000..90d4c15 --- /dev/null +++ b/libraries/SoftwareSerial/keywords.txt @@ -0,0 +1,27 @@ +####################################### +# Syntax Coloring Map for NewSoftSerial +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +NewSoftSerial	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin	KEYWORD2 +end	KEYWORD2 +read	KEYWORD2 +available	KEYWORD2 +isListening	KEYWORD2 +overflow	KEYWORD2 +flush	KEYWORD2 +listen	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Stepper/Stepper.cpp b/libraries/Stepper/Stepper.cpp new file mode 100644 index 0000000..5d6b5e5 --- /dev/null +++ b/libraries/Stepper/Stepper.cpp @@ -0,0 +1,220 @@ +/* +  Stepper.cpp - - Stepper library for Wiring/Arduino - Version 0.4 +   +  Original library     (0.1) by Tom Igoe. +  Two-wire modifications   (0.2) by Sebastian Gassner +  Combination version   (0.3) by Tom Igoe and David Mellis +  Bug fix for four-wire   (0.4) by Tom Igoe, bug fix from Noah Shibley   + +  Drives a unipolar or bipolar stepper motor using  2 wires or 4 wires + +  When wiring multiple stepper motors to a microcontroller, +  you quickly run out of output pins, with each motor requiring 4 connections.  + +  By making use of the fact that at any time two of the four motor +  coils are the inverse  of the other two, the number of +  control connections can be reduced from 4 to 2.  + +  A slightly modified circuit around a Darlington transistor array or an L293 H-bridge +  connects to only 2 microcontroler pins, inverts the signals received, +  and delivers the 4 (2 plus 2 inverted ones) output signals required +  for driving a stepper motor. + +  The sequence of control signals for 4 control wires is as follows: + +  Step C0 C1 C2 C3 +     1  1  0  1  0 +     2  0  1  1  0 +     3  0  1  0  1 +     4  1  0  0  1 + +  The sequence of controls signals for 2 control wires is as follows +  (columns C1 and C2 from above): + +  Step C0 C1 +     1  0  1 +     2  1  1 +     3  1  0 +     4  0  0 + +  The circuits can be found at  +  +http://www.arduino.cc/en/Tutorial/Stepper +  +  + */ + + +#include "Arduino.h" +#include "Stepper.h" + +/* + * two-wire constructor. + * Sets which wires should control the motor. + */ +Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2) +{ +  this->step_number = 0;      // which step the motor is on +  this->speed = 0;        // the motor speed, in revolutions per minute +  this->direction = 0;      // motor direction +  this->last_step_time = 0;    // time stamp in ms of the last step taken +  this->number_of_steps = number_of_steps;    // total number of steps for this motor +   +  // Arduino pins for the motor control connection: +  this->motor_pin_1 = motor_pin_1; +  this->motor_pin_2 = motor_pin_2; + +  // setup the pins on the microcontroller: +  pinMode(this->motor_pin_1, OUTPUT); +  pinMode(this->motor_pin_2, OUTPUT); +   +  // When there are only 2 pins, set the other two to 0: +  this->motor_pin_3 = 0; +  this->motor_pin_4 = 0; +   +  // pin_count is used by the stepMotor() method: +  this->pin_count = 2; +} + + +/* + *   constructor for four-pin version + *   Sets which wires should control the motor. + */ + +Stepper::Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4) +{ +  this->step_number = 0;      // which step the motor is on +  this->speed = 0;        // the motor speed, in revolutions per minute +  this->direction = 0;      // motor direction +  this->last_step_time = 0;    // time stamp in ms of the last step taken +  this->number_of_steps = number_of_steps;    // total number of steps for this motor +   +  // Arduino pins for the motor control connection: +  this->motor_pin_1 = motor_pin_1; +  this->motor_pin_2 = motor_pin_2; +  this->motor_pin_3 = motor_pin_3; +  this->motor_pin_4 = motor_pin_4; + +  // setup the pins on the microcontroller: +  pinMode(this->motor_pin_1, OUTPUT); +  pinMode(this->motor_pin_2, OUTPUT); +  pinMode(this->motor_pin_3, OUTPUT); +  pinMode(this->motor_pin_4, OUTPUT); + +  // pin_count is used by the stepMotor() method:   +  this->pin_count = 4;   +} + +/* +  Sets the speed in revs per minute + +*/ +void Stepper::setSpeed(long whatSpeed) +{ +  this->step_delay = 60L * 1000L / this->number_of_steps / whatSpeed; +} + +/* +  Moves the motor steps_to_move steps.  If the number is negative,  +   the motor moves in the reverse direction. + */ +void Stepper::step(int steps_to_move) +{   +  int steps_left = abs(steps_to_move);  // how many steps to take +   +  // determine direction based on whether steps_to_mode is + or -: +  if (steps_to_move > 0) {this->direction = 1;} +  if (steps_to_move < 0) {this->direction = 0;} +     +     +  // decrement the number of steps, moving one step each time: +  while(steps_left > 0) { +  // move only if the appropriate delay has passed: +  if (millis() - this->last_step_time >= this->step_delay) { +      // get the timeStamp of when you stepped: +      this->last_step_time = millis(); +      // increment or decrement the step number, +      // depending on direction: +      if (this->direction == 1) { +        this->step_number++; +        if (this->step_number == this->number_of_steps) { +          this->step_number = 0; +        } +      }  +      else {  +        if (this->step_number == 0) { +          this->step_number = this->number_of_steps; +        } +        this->step_number--; +      } +      // decrement the steps left: +      steps_left--; +      // step the motor to step number 0, 1, 2, or 3: +      stepMotor(this->step_number % 4); +    } +  } +} + +/* + * Moves the motor forward or backwards. + */ +void Stepper::stepMotor(int thisStep) +{ +  if (this->pin_count == 2) { +    switch (thisStep) { +      case 0: /* 01 */ +      digitalWrite(motor_pin_1, LOW); +      digitalWrite(motor_pin_2, HIGH); +      break; +      case 1: /* 11 */ +      digitalWrite(motor_pin_1, HIGH); +      digitalWrite(motor_pin_2, HIGH); +      break; +      case 2: /* 10 */ +      digitalWrite(motor_pin_1, HIGH); +      digitalWrite(motor_pin_2, LOW); +      break; +      case 3: /* 00 */ +      digitalWrite(motor_pin_1, LOW); +      digitalWrite(motor_pin_2, LOW); +      break; +    }  +  } +  if (this->pin_count == 4) { +    switch (thisStep) { +      case 0:    // 1010 +      digitalWrite(motor_pin_1, HIGH); +      digitalWrite(motor_pin_2, LOW); +      digitalWrite(motor_pin_3, HIGH); +      digitalWrite(motor_pin_4, LOW); +      break; +      case 1:    // 0110 +      digitalWrite(motor_pin_1, LOW); +      digitalWrite(motor_pin_2, HIGH); +      digitalWrite(motor_pin_3, HIGH); +      digitalWrite(motor_pin_4, LOW); +      break; +      case 2:    //0101 +      digitalWrite(motor_pin_1, LOW); +      digitalWrite(motor_pin_2, HIGH); +      digitalWrite(motor_pin_3, LOW); +      digitalWrite(motor_pin_4, HIGH); +      break; +      case 3:    //1001 +      digitalWrite(motor_pin_1, HIGH); +      digitalWrite(motor_pin_2, LOW); +      digitalWrite(motor_pin_3, LOW); +      digitalWrite(motor_pin_4, HIGH); +      break; +    }  +  } +} + +/* +  version() returns the version of the library: +*/ +int Stepper::version(void) +{ +  return 4; +} diff --git a/libraries/Stepper/Stepper.h b/libraries/Stepper/Stepper.h new file mode 100644 index 0000000..4094aee --- /dev/null +++ b/libraries/Stepper/Stepper.h @@ -0,0 +1,83 @@ +/* +  Stepper.h - - Stepper library for Wiring/Arduino - Version 0.4 +   +  Original library     (0.1) by Tom Igoe. +  Two-wire modifications   (0.2) by Sebastian Gassner +  Combination version   (0.3) by Tom Igoe and David Mellis +  Bug fix for four-wire   (0.4) by Tom Igoe, bug fix from Noah Shibley + +  Drives a unipolar or bipolar stepper motor using  2 wires or 4 wires + +  When wiring multiple stepper motors to a microcontroller, +  you quickly run out of output pins, with each motor requiring 4 connections.  + +  By making use of the fact that at any time two of the four motor +  coils are the inverse  of the other two, the number of +  control connections can be reduced from 4 to 2.  + +  A slightly modified circuit around a Darlington transistor array or an L293 H-bridge +  connects to only 2 microcontroler pins, inverts the signals received, +  and delivers the 4 (2 plus 2 inverted ones) output signals required +  for driving a stepper motor. + +  The sequence of control signals for 4 control wires is as follows: + +  Step C0 C1 C2 C3 +     1  1  0  1  0 +     2  0  1  1  0 +     3  0  1  0  1 +     4  1  0  0  1 + +  The sequence of controls signals for 2 control wires is as follows +  (columns C1 and C2 from above): + +  Step C0 C1 +     1  0  1 +     2  1  1 +     3  1  0 +     4  0  0 + +  The circuits can be found at  +  http://www.arduino.cc/en/Tutorial/Stepper +*/ + +// ensure this library description is only included once +#ifndef Stepper_h +#define Stepper_h + +// library interface description +class Stepper { +  public: +    // constructors: +    Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2); +    Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2, int motor_pin_3, int motor_pin_4); + +    // speed setter method: +    void setSpeed(long whatSpeed); + +    // mover method: +    void step(int number_of_steps); + +    int version(void); + +  private: +    void stepMotor(int this_step); +     +    int direction;        // Direction of rotation +    int speed;          // Speed in RPMs +    unsigned long step_delay;    // delay between steps, in ms, based on speed +    int number_of_steps;      // total number of steps this motor can take +    int pin_count;        // whether you're driving the motor with 2 or 4 pins +    int step_number;        // which step the motor is on +     +    // motor pin numbers: +    int motor_pin_1; +    int motor_pin_2; +    int motor_pin_3; +    int motor_pin_4; +     +    long last_step_time;      // time stamp in ms of when the last step was taken +}; + +#endif + diff --git a/libraries/Stepper/examples/MotorKnob/MotorKnob.ino b/libraries/Stepper/examples/MotorKnob/MotorKnob.ino new file mode 100644 index 0000000..d428186 --- /dev/null +++ b/libraries/Stepper/examples/MotorKnob/MotorKnob.ino @@ -0,0 +1,41 @@ +/* + * MotorKnob + * + * A stepper motor follows the turns of a potentiometer + * (or other sensor) on analog input 0. + * + * http://www.arduino.cc/en/Reference/Stepper + * This example code is in the public domain. + */ + +#include <Stepper.h> + +// change this to the number of steps on your motor +#define STEPS 100 + +// create an instance of the stepper class, specifying +// the number of steps of the motor and the pins it's +// attached to +Stepper stepper(STEPS, 8, 9, 10, 11); + +// the previous reading from the analog input +int previous = 0; + +void setup() +{ +  // set the speed of the motor to 30 RPMs +  stepper.setSpeed(30); +} + +void loop() +{ +  // get the sensor value +  int val = analogRead(0); + +  // move a number of steps equal to the change in the +  // sensor reading +  stepper.step(val - previous); + +  // remember the previous value of the sensor +  previous = val; +}
\ No newline at end of file diff --git a/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino b/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino new file mode 100644 index 0000000..2dbb57d --- /dev/null +++ b/libraries/Stepper/examples/stepper_oneRevolution/stepper_oneRevolution.ino @@ -0,0 +1,44 @@ + +/*  + Stepper Motor Control - one revolution +  + This program drives a unipolar or bipolar stepper motor.  + The motor is attached to digital pins 8 - 11 of the Arduino. +  + The motor should revolve one revolution in one direction, then + one revolution in the other direction.   +  +   + Created 11 Mar. 2007 + Modified 30 Nov. 2009 + by Tom Igoe +  + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution +                                     // for your motor + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11);             + +void setup() { +  // set the speed at 60 rpm: +  myStepper.setSpeed(60); +  // initialize the serial port: +  Serial.begin(9600); +} + +void loop() { +  // step one revolution  in one direction: +   Serial.println("clockwise"); +  myStepper.step(stepsPerRevolution); +  delay(500); +   +   // step one revolution in the other direction: +  Serial.println("counterclockwise"); +  myStepper.step(-stepsPerRevolution); +  delay(500);  +} + diff --git a/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino b/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino new file mode 100644 index 0000000..36d3299 --- /dev/null +++ b/libraries/Stepper/examples/stepper_oneStepAtATime/stepper_oneStepAtATime.ino @@ -0,0 +1,44 @@ + +/*  + Stepper Motor Control - one step at a time +  + This program drives a unipolar or bipolar stepper motor.  + The motor is attached to digital pins 8 - 11 of the Arduino. +  + The motor will step one step at a time, very slowly.  You can use this to + test that you've got the four wires of your stepper wired to the correct + pins. If wired correctly, all steps should be in the same direction. +  + Use this also to count the number of steps per revolution of your motor, + if you don't know it.  Then plug that number into the oneRevolution + example to see if you got it right. +  + Created 30 Nov. 2009 + by Tom Igoe +  + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution +                                     // for your motor + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11);             + +int stepCount = 0;         // number of steps the motor has taken + +void setup() { +  // initialize the serial port: +  Serial.begin(9600); +} + +void loop() { +  // step one step: +  myStepper.step(1); +  Serial.print("steps:" ); +  Serial.println(stepCount); +  stepCount++; +  delay(500); +} + diff --git a/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino b/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino new file mode 100644 index 0000000..1a67a55 --- /dev/null +++ b/libraries/Stepper/examples/stepper_speedControl/stepper_speedControl.ino @@ -0,0 +1,48 @@ + +/*  + Stepper Motor Control - speed control +  + This program drives a unipolar or bipolar stepper motor.  + The motor is attached to digital pins 8 - 11 of the Arduino. + A potentiometer is connected to analog input 0. +  + The motor will rotate in a clockwise direction. The higher the potentiometer value, + the faster the motor speed. Because setSpeed() sets the delay between steps,  + you may notice the motor is less responsive to changes in the sensor value at + low speeds. +  + Created 30 Nov. 2009 + Modified 28 Oct 2010 + by Tom Igoe +  + */ + +#include <Stepper.h> + +const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution +// for your motor + + +// initialize the stepper library on pins 8 through 11: +Stepper myStepper(stepsPerRevolution, 8,9,10,11);             + +int stepCount = 0;  // number of steps the motor has taken + +void setup() { +  // nothing to do inside the setup +} + +void loop() { +  // read the sensor value: +  int sensorReading = analogRead(A0); +  // map it to a range from 0 to 100: +  int motorSpeed = map(sensorReading, 0, 1023, 0, 100); +  // set the motor speed: +  if (motorSpeed > 0) { +    myStepper.setSpeed(motorSpeed); +    // step 1/100 of a revolution: +    myStepper.step(stepsPerRevolution/100); +  }  +} + + diff --git a/libraries/Stepper/keywords.txt b/libraries/Stepper/keywords.txt new file mode 100644 index 0000000..19a0fad --- /dev/null +++ b/libraries/Stepper/keywords.txt @@ -0,0 +1,28 @@ +####################################### +# Syntax Coloring Map For Test +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Stepper	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +step	KEYWORD2 +setSpeed	KEYWORD2 +version	KEYWORD2 + +###################################### +# Instances (KEYWORD2) +####################################### +direction	KEYWORD2 +speed	KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/libraries/WiFi/WiFi.cpp b/libraries/WiFi/WiFi.cpp new file mode 100644 index 0000000..c0cb001 --- /dev/null +++ b/libraries/WiFi/WiFi.cpp @@ -0,0 +1,199 @@ +#include "wifi_drv.h" +#include "WiFi.h" + +extern "C" { +  #include "utility/wl_definitions.h" +  #include "utility/wl_types.h" +  #include "debug.h" +} + +// XXX: don't make assumptions about the value of MAX_SOCK_NUM. +int16_t 	WiFiClass::_state[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; +uint16_t 	WiFiClass::_server_port[MAX_SOCK_NUM] = { 0, 0, 0, 0 }; + +WiFiClass::WiFiClass() +{ +	// Driver initialization +	init(); +} + +void WiFiClass::init() +{ +    WiFiDrv::wifiDriverInit(); +} + +uint8_t WiFiClass::getSocket() +{ +    for (uint8_t i = 0; i < MAX_SOCK_NUM; ++i) +    { +        if (WiFiClass::_server_port[i] == 0) +        { +             return i; +        } +    } +    return NO_SOCKET_AVAIL; +} + +char* WiFiClass::firmwareVersion() +{ +	return WiFiDrv::getFwVersion(); +} + +int WiFiClass::begin(char* ssid) +{ +	uint8_t status = WL_IDLE_STATUS; +	uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + +   if (WiFiDrv::wifiSetNetwork(ssid, strlen(ssid)) != WL_FAILURE) +   { +	   do +	   { +		   delay(WL_DELAY_START_CONNECTION); +		   status = WiFiDrv::getConnectionStatus(); +	   } +	   while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); +   }else +   { +	   status = WL_CONNECT_FAILED; +   } +   return status; +} + +int WiFiClass::begin(char* ssid, uint8_t key_idx, const char *key) +{ +	uint8_t status = WL_IDLE_STATUS; +	uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + +	// set encryption key +   if (WiFiDrv::wifiSetKey(ssid, strlen(ssid), key_idx, key, strlen(key)) != WL_FAILURE) +   { +	   do +	   { +		   delay(WL_DELAY_START_CONNECTION); +		   status = WiFiDrv::getConnectionStatus(); +	   } +	   while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); +   }else{ +	   status = WL_CONNECT_FAILED; +   } +   return status; +} + +int WiFiClass::begin(char* ssid, const char *passphrase) +{ +	uint8_t status = WL_IDLE_STATUS; +	uint8_t attempts = WL_MAX_ATTEMPT_CONNECTION; + +    // set passphrase +    if (WiFiDrv::wifiSetPassphrase(ssid, strlen(ssid), passphrase, strlen(passphrase))!= WL_FAILURE) +    { + 	   do + 	   { + 		   delay(WL_DELAY_START_CONNECTION); + 		   status = WiFiDrv::getConnectionStatus(); + 	   } +	   while ((( status == WL_IDLE_STATUS)||(status == WL_SCAN_COMPLETED))&&(--attempts>0)); +    }else{ +    	status = WL_CONNECT_FAILED; +    } +    return status; +} + +int WiFiClass::disconnect() +{ +    return WiFiDrv::disconnect(); +} + +uint8_t* WiFiClass::macAddress(uint8_t* mac) +{ +	uint8_t* _mac = WiFiDrv::getMacAddress(); +	memcpy(mac, _mac, WL_MAC_ADDR_LENGTH); +    return mac; +} +    +IPAddress WiFiClass::localIP() +{ +	IPAddress ret; +	WiFiDrv::getIpAddress(ret); +	return ret; +} + +IPAddress WiFiClass::subnetMask() +{ +	IPAddress ret; +	WiFiDrv::getSubnetMask(ret); +	return ret; +} + +IPAddress WiFiClass::gatewayIP() +{ +	IPAddress ret; +	WiFiDrv::getGatewayIP(ret); +	return ret; +} + +char* WiFiClass::SSID() +{ +    return WiFiDrv::getCurrentSSID(); +} + +uint8_t* WiFiClass::BSSID(uint8_t* bssid) +{ +	uint8_t* _bssid = WiFiDrv::getCurrentBSSID(); +	memcpy(bssid, _bssid, WL_MAC_ADDR_LENGTH); +    return bssid; +} + +int32_t WiFiClass::RSSI() +{ +    return WiFiDrv::getCurrentRSSI(); +} + +uint8_t WiFiClass::encryptionType() +{ +    return WiFiDrv::getCurrentEncryptionType(); +} + + +int8_t WiFiClass::scanNetworks() +{ +	uint8_t attempts = 10; +	uint8_t numOfNetworks = 0; + +	if (WiFiDrv::startScanNetworks() == WL_FAILURE) +		return WL_FAILURE; + 	do + 	{ + 		delay(2000); + 		numOfNetworks = WiFiDrv::getScanNetworks(); + 	} +	while (( numOfNetworks == 0)&&(--attempts>0)); +	return numOfNetworks; +} + +char* WiFiClass::SSID(uint8_t networkItem) +{ +	return WiFiDrv::getSSIDNetoworks(networkItem); +} + +int32_t WiFiClass::RSSI(uint8_t networkItem) +{ +	return WiFiDrv::getRSSINetoworks(networkItem); +} + +uint8_t WiFiClass::encryptionType(uint8_t networkItem) +{ +    return WiFiDrv::getEncTypeNetowrks(networkItem); +} + +uint8_t WiFiClass::status() +{ +    return WiFiDrv::getConnectionStatus(); +} + +int WiFiClass::hostByName(const char* aHostname, IPAddress& aResult) +{ +	return WiFiDrv::getHostByName(aHostname, aResult); +} + +WiFiClass WiFi; diff --git a/libraries/WiFi/WiFi.h b/libraries/WiFi/WiFi.h new file mode 100644 index 0000000..9a86701 --- /dev/null +++ b/libraries/WiFi/WiFi.h @@ -0,0 +1,183 @@ +#ifndef WiFi_h +#define WiFi_h + +#include <inttypes.h> + +extern "C" { +	#include "utility/wl_definitions.h" +	#include "utility/wl_types.h" +} + +#include "IPAddress.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +class WiFiClass +{ +private: + +    static void init(); +public: +    static int16_t 	_state[MAX_SOCK_NUM]; +    static uint16_t _server_port[MAX_SOCK_NUM]; + +    WiFiClass(); + +    /* +     * Get the first socket available +     */ +    static uint8_t getSocket(); + +    /* +     * Get firmware version +     */ +    static char* firmwareVersion(); + + +    /* Start Wifi connection for OPEN networks +     * +     * param ssid: Pointer to the SSID string. +     */ +    int begin(char* ssid); + +    /* Start Wifi connection with WEP encryption. +     * Configure a key into the device. The key type (WEP-40, WEP-104) +     * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104). +     * +     * param ssid: Pointer to the SSID string. +     * param key_idx: The key index to set. Valid values are 0-3. +     * param key: Key input buffer. +     */ +    int begin(char* ssid, uint8_t key_idx, const char* key); + +    /* Start Wifi connection with passphrase +     * the most secure supported mode will be automatically selected +     * +     * param ssid: Pointer to the SSID string. +     * param passphrase: Passphrase. Valid characters in a passphrase +     *        must be between ASCII 32-126 (decimal). +     */ +    int begin(char* ssid, const char *passphrase); + +    /* +     * Disconnect from the network +     * +     * return: one value of wl_status_t enum +     */ +    int disconnect(void); + +    /* +     * Get the interface MAC address. +     * +     * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH +     */ +    uint8_t* macAddress(uint8_t* mac); + +    /* +     * Get the interface IP address. +     * +     * return: Ip address value +     */ +    IPAddress localIP(); + +    /* +     * Get the interface subnet mask address. +     * +     * return: subnet mask address value +     */ +    IPAddress subnetMask(); + +    /* +     * Get the gateway ip address. +     * +     * return: gateway ip address value +     */ +   IPAddress gatewayIP(); + +    /* +     * Return the current SSID associated with the network +     * +     * return: ssid string +     */ +    char* SSID(); + +    /* +      * Return the current BSSID associated with the network. +      * It is the MAC address of the Access Point +      * +      * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH +      */ +    uint8_t* BSSID(uint8_t* bssid); + +    /* +      * Return the current RSSI /Received Signal Strength in dBm) +      * associated with the network +      * +      * return: signed value +      */ +    int32_t RSSI(); + +    /* +      * Return the Encryption Type associated with the network +      * +      * return: one value of wl_enc_type enum +      */ +    uint8_t	encryptionType(); + +    /* +     * Start scan WiFi networks available +     * +     * return: Number of discovered networks +     */ +    int8_t scanNetworks(); + +    /* +     * Return the SSID discovered during the network scan. +     * +     * param networkItem: specify from which network item want to get the information +	 * +     * return: ssid string of the specified item on the networks scanned list +     */ +    char*	SSID(uint8_t networkItem); + +    /* +     * Return the encryption type of the networks discovered during the scanNetworks +     * +     * param networkItem: specify from which network item want to get the information +	 * +     * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list +     */ +    uint8_t	encryptionType(uint8_t networkItem); + +    /* +     * Return the RSSI of the networks discovered during the scanNetworks +     * +     * param networkItem: specify from which network item want to get the information +	 * +     * return: signed value of RSSI of the specified item on the networks scanned list +     */ +    int32_t RSSI(uint8_t networkItem); + +    /* +     * Return Connection status. +     * +     * return: one of the value defined in wl_status_t +     */ +    uint8_t status(); + +    /* +     * Resolve the given hostname to an IP address. +     * param aHostname: Name to be resolved +     * param aResult: IPAddress structure to store the returned IP address +     * result: 1 if aIPAddrString was successfully converted to an IP address, +     *          else error code +     */ +    int hostByName(const char* aHostname, IPAddress& aResult); + +    friend class WiFiClient; +    friend class WiFiServer; +}; + +extern WiFiClass WiFi; + +#endif diff --git a/libraries/WiFi/WiFiClient.cpp b/libraries/WiFi/WiFiClient.cpp new file mode 100644 index 0000000..83c0d10 --- /dev/null +++ b/libraries/WiFi/WiFiClient.cpp @@ -0,0 +1,179 @@ +extern "C" { +  #include "utility/wl_definitions.h" +  #include "utility/wl_types.h" +  #include "socket.h" +  #include "string.h" +  #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" +#include "server_drv.h" + + +uint16_t WiFiClient::_srcport = 1024; + +WiFiClient::WiFiClient() : _sock(MAX_SOCK_NUM) { +} + +WiFiClient::WiFiClient(uint8_t sock) : _sock(sock) { +} + +int WiFiClient::connect(const char* host, uint16_t port) { +	IPAddress remote_addr; +	if (WiFi.hostByName(host, remote_addr)) +	{ +		return connect(remote_addr, port); +	} +	return 0; +} + +int WiFiClient::connect(IPAddress ip, uint16_t port) { +    _sock = getFirstSocket(); +    if (_sock != NO_SOCKET_AVAIL) +    { +    	ServerDrv::startClient(uint32_t(ip), port, _sock); +    	WiFiClass::_state[_sock] = _sock; + +    	unsigned long start = millis(); + +    	// wait 4 second for the connection to close +    	while (!connected() && millis() - start < 10000) +    		delay(1); + +    	if (!connected()) +       	{ +    		return 0; +    	} +    }else{ +    	Serial.println("No Socket available"); +    	return 0; +    } +    return 1; +} + +size_t WiFiClient::write(uint8_t b) { +	  return write(&b, 1); +} + +size_t WiFiClient::write(const uint8_t *buf, size_t size) { +  if (_sock >= MAX_SOCK_NUM) +  { +	  setWriteError(); +	  return 0; +  } +  if (size==0) +  { +	  setWriteError(); +      return 0; +  } + + +  if (!ServerDrv::sendData(_sock, buf, size)) +  { +	  setWriteError(); +      return 0; +  } +  if (!ServerDrv::checkDataSent(_sock)) +  { +	  setWriteError(); +      return 0; +  } + +  return size; +} + +int WiFiClient::available() { +  if (_sock != 255) +  { +      return ServerDrv::availData(_sock); +  } +    +  return 0; +} + +int WiFiClient::read() { +  uint8_t b; +  if (!available()) +    return -1; + +  ServerDrv::getData(_sock, &b); +  return b; +} + + +int WiFiClient::read(uint8_t* buf, size_t size) { +  if (!ServerDrv::getDataBuf(_sock, buf, &size)) +      return -1; +  return 0; +} + +int WiFiClient::peek() { +	  uint8_t b; +	  if (!available()) +	    return -1; + +	  ServerDrv::getData(_sock, &b, 1); +	  return b; +} + +void WiFiClient::flush() { +  while (available()) +    read(); +} + +void WiFiClient::stop() { + +  if (_sock == 255) +    return; + +  ServerDrv::stopClient(_sock); + +  unsigned long start = millis(); +   + +  // wait a second for the connection to close +  while (status() != CLOSED && millis() - start < 1000) +    delay(1); +  _sock = 255; +} + +uint8_t WiFiClient::connected() { + +  if (_sock == 255) { +    return 0; +  } else { +    uint8_t s = status(); + +    return !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 || +    		s == FIN_WAIT_2 || s == TIME_WAIT || +    		s == SYN_SENT || s== SYN_RCVD || +             (s == CLOSE_WAIT && !available())); +  } +} + +uint8_t WiFiClient::status() { +    if (_sock == 255) { +    return CLOSED; +  } else { +    return ServerDrv::getClientState(_sock); +  } +} + +WiFiClient::operator bool() { +  return _sock != 255; +} + +// Private Methods +uint8_t WiFiClient::getFirstSocket() +{ +    for (int i = 0; i < MAX_SOCK_NUM; i++) { +      if (WiFiClass::_state[i] == 0) +      { +          return i; +      } +    } +    return SOCK_NOT_AVAIL; +} + diff --git a/libraries/WiFi/WiFiClient.h b/libraries/WiFi/WiFiClient.h new file mode 100644 index 0000000..5a7f0f3 --- /dev/null +++ b/libraries/WiFi/WiFiClient.h @@ -0,0 +1,40 @@ +#ifndef wificlient_h +#define wificlient_h +#include "Arduino.h"	 +#include "Print.h" +#include "Client.h" +#include "IPAddress.h" + +class WiFiClient : public Client { + +public: +  WiFiClient(); +  WiFiClient(uint8_t sock); + +  uint8_t status(); +  virtual int connect(IPAddress ip, uint16_t port); +  virtual int connect(const char *host, uint16_t port); +  virtual size_t write(uint8_t); +  virtual size_t write(const uint8_t *buf, size_t size); +  virtual int available(); +  virtual int read(); +  virtual int read(uint8_t *buf, size_t size); +  virtual int peek(); +  virtual void flush(); +  virtual void stop(); +  virtual uint8_t connected(); +  virtual operator bool(); + +  friend class WiFiServer; + +  using Print::write; + +private: +  static uint16_t _srcport; +  uint8_t _sock;   //not used +  uint16_t  _socket; + +  uint8_t getFirstSocket(); +}; + +#endif diff --git a/libraries/WiFi/WiFiServer.cpp b/libraries/WiFi/WiFiServer.cpp new file mode 100644 index 0000000..77dbac0 --- /dev/null +++ b/libraries/WiFi/WiFiServer.cpp @@ -0,0 +1,88 @@ +#include <string.h> +#include "server_drv.h" + +extern "C" { +  #include "utility/debug.h" +} + +#include "WiFi.h" +#include "WiFiClient.h" +#include "WiFiServer.h" + +WiFiServer::WiFiServer(uint16_t port) +{ +    _port = port; +} + +void WiFiServer::begin() +{ +    uint8_t _sock = WiFiClass::getSocket(); +    if (_sock != NO_SOCKET_AVAIL) +    { +        ServerDrv::startServer(_port, _sock); +        WiFiClass::_server_port[_sock] = _port; +    } +} + +WiFiClient WiFiServer::available(byte* status) +{ +	static int cycle_server_down = 0; +	const int TH_SERVER_DOWN = 50; + +    for (int sock = 0; sock < MAX_SOCK_NUM; sock++) +    { +        if (WiFiClass::_server_port[sock] == _port) +        { +        	WiFiClient client(sock); +            uint8_t _status = client.status(); +            uint8_t _ser_status = this->status(); + +            if (status != NULL) +            	*status = _status; + +            //server not in listen state, restart it +            if ((_ser_status == 0)&&(cycle_server_down++ > TH_SERVER_DOWN)) +            { +            	ServerDrv::startServer(_port, sock); +            	cycle_server_down = 0; +            } + +            if (_status == ESTABLISHED) +            {                 +                return client;  //TODO  +            } +        } +    } + +    return WiFiClient(255); +} + +uint8_t WiFiServer::status() { +    return ServerDrv::getServerState(0); +} + + +size_t WiFiServer::write(uint8_t b) +{ +    return write(&b, 1); +} + +size_t WiFiServer::write(const uint8_t *buffer, size_t size) +{ +	size_t n = 0; + +    for (int sock = 0; sock < MAX_SOCK_NUM; sock++) +    { +        if (WiFiClass::_server_port[sock] != 0) +        { +        	WiFiClient client(sock); + +            if (WiFiClass::_server_port[sock] == _port && +                client.status() == ESTABLISHED) +            {                 +                n+=client.write(buffer, size); +            } +        } +    } +    return n; +} diff --git a/libraries/WiFi/WiFiServer.h b/libraries/WiFi/WiFiServer.h new file mode 100644 index 0000000..68b574c --- /dev/null +++ b/libraries/WiFi/WiFiServer.h @@ -0,0 +1,27 @@ +#ifndef wifiserver_h +#define wifiserver_h + +extern "C" { +  #include "utility/wl_definitions.h" +} + +#include "Server.h" + +class WiFiClient; + +class WiFiServer : public Server { +private: +  uint16_t _port; +  void*     pcb; +public: +  WiFiServer(uint16_t); +  WiFiClient available(uint8_t* status = NULL); +  void begin(); +  virtual size_t write(uint8_t); +  virtual size_t write(const uint8_t *buf, size_t size); +  uint8_t status(); + +  using Print::write; +}; + +#endif diff --git a/libraries/WiFi/examples/ConnectNoEncryption/ConnectNoEncryption.ino b/libraries/WiFi/examples/ConnectNoEncryption/ConnectNoEncryption.ino new file mode 100644 index 0000000..f42a7f3 --- /dev/null +++ b/libraries/WiFi/examples/ConnectNoEncryption/ConnectNoEncryption.ino @@ -0,0 +1,121 @@ +/* +  + This example connects to an unencrypted Wifi network.  + Then it prints the  MAC address of the Wifi shield, + the IP address obtained, and other network details. + + Circuit: + * WiFi shield attached +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + #include <WiFi.h> + +char ssid[] = "yourNetwork";     // the name of your network +int status = WL_IDLE_STATUS;     // the Wifi radio's status + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   + // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to open SSID: "); +    Serial.println(ssid); +    status = WiFi.begin(ssid); + +    // wait 10 seconds for connection: +    delay(10000); +  } +    +  // you're connected now, so print out the data: +  Serial.print("You're connected to the network"); +  printCurrentNet(); +  printWifiData(); +} + +void loop() { +  // check the network connection once every 10 seconds: +  delay(10000); +  printCurrentNet(); +} + +void printWifiData() { +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +    Serial.print("IP Address: "); +  Serial.println(ip); +  Serial.println(ip); +   +  // print your MAC address: +  byte mac[6];   +  WiFi.macAddress(mac); +  Serial.print("MAC address: "); +  Serial.print(mac[5],HEX); +  Serial.print(":"); +  Serial.print(mac[4],HEX); +  Serial.print(":"); +  Serial.print(mac[3],HEX); +  Serial.print(":"); +  Serial.print(mac[2],HEX); +  Serial.print(":"); +  Serial.print(mac[1],HEX); +  Serial.print(":"); +  Serial.println(mac[0],HEX); +   +  // print your subnet mask: +  IPAddress subnet = WiFi.subnetMask(); +  Serial.print("NetMask: "); +  Serial.println(subnet); + +  // print your gateway address: +  IPAddress gateway = WiFi.gatewayIP(); +  Serial.print("Gateway: "); +  Serial.println(gateway); +} + +void printCurrentNet() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print the MAC address of the router you're attached to: +  byte bssid[6]; +  WiFi.BSSID(bssid);     +  Serial.print("BSSID: "); +  Serial.print(bssid[5],HEX); +  Serial.print(":"); +  Serial.print(bssid[4],HEX); +  Serial.print(":"); +  Serial.print(bssid[3],HEX); +  Serial.print(":"); +  Serial.print(bssid[2],HEX); +  Serial.print(":"); +  Serial.print(bssid[1],HEX); +  Serial.print(":"); +  Serial.println(bssid[0],HEX); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.println(rssi); + +  // print the encryption type: +  byte encryption = WiFi.encryptionType(); +  Serial.print("Encryption Type:"); +  Serial.println(encryption,HEX); +} + diff --git a/libraries/WiFi/examples/ConnectWithWEP/ConnectWithWEP.ino b/libraries/WiFi/examples/ConnectWithWEP/ConnectWithWEP.ino new file mode 100644 index 0000000..19736b5 --- /dev/null +++ b/libraries/WiFi/examples/ConnectWithWEP/ConnectWithWEP.ino @@ -0,0 +1,126 @@ +/* +  + This example connects to a WEP-encrypted Wifi network.  + Then it prints the  MAC address of the Wifi shield, + the IP address obtained, and other network details. +  + If you use 40-bit WEP, you need a key that is 10 characters long,  + and the characters must be hexadecimal (0-9 or A-F).  + e.g.  for 40-bit, ABBADEAF01 will work, but ABBADEAF won't work  + (too short) and ABBAISDEAF won't work (I and S are not  + hexadecimal characters).  +  + For 128-bit, you need a string that is 26 characters long.  + D0D0DEADF00DABBADEAFBEADED will work because it's 26 characters,  + all in the 0-9, A-F range. +  + Circuit: + * WiFi shield attached +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include <WiFi.h> + +char ssid[] = "yourNetwork";                     // your network SSID (name)  +char key[] = "D0D0DEADF00DABBADEAFBEADED";       // your network key +int keyIndex = 0;                                // your network key Index number +int status = WL_IDLE_STATUS;                     // the Wifi radio's status + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  + +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to WEP network, SSID: "); +    Serial.println(ssid); +    status = WiFi.begin(ssid, keyIndex, key); + +    // wait 10 seconds for connection: +    delay(10000); +  } + +  // once you are connected : +  Serial.print("You're connected to the network"); +  printCurrentNet(); +  printWifiData(); +} + +void loop() { +  // check the network connection once every 10 seconds: +  delay(10000); +  printCurrentNet(); +} + +void printWifiData() { +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); +  Serial.println(ip); + +  // print your MAC address: +  byte mac[6];   +  WiFi.macAddress(mac); +  Serial.print("MAC address: "); +  Serial.print(mac[5],HEX); +  Serial.print(":"); +  Serial.print(mac[4],HEX); +  Serial.print(":"); +  Serial.print(mac[3],HEX); +  Serial.print(":"); +  Serial.print(mac[2],HEX); +  Serial.print(":"); +  Serial.print(mac[1],HEX); +  Serial.print(":"); +  Serial.println(mac[0],HEX); +} + +void printCurrentNet() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print the MAC address of the router you're attached to: +  byte bssid[6]; +  WiFi.BSSID(bssid);     +  Serial.print("BSSID: "); +  Serial.print(bssid[5],HEX); +  Serial.print(":"); +  Serial.print(bssid[4],HEX); +  Serial.print(":"); +  Serial.print(bssid[3],HEX); +  Serial.print(":"); +  Serial.print(bssid[2],HEX); +  Serial.print(":"); +  Serial.print(bssid[1],HEX); +  Serial.print(":"); +  Serial.println(bssid[0],HEX); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.println(rssi); + +  // print the encryption type: +  byte encryption = WiFi.encryptionType(); +  Serial.print("Encryption Type:"); +  Serial.println(encryption,HEX); +  Serial.println(); +} + + + diff --git a/libraries/WiFi/examples/ConnectWithWPA/ConnectWithWPA.ino b/libraries/WiFi/examples/ConnectWithWPA/ConnectWithWPA.ino new file mode 100644 index 0000000..fcc33ec --- /dev/null +++ b/libraries/WiFi/examples/ConnectWithWPA/ConnectWithWPA.ino @@ -0,0 +1,116 @@ +/* +  + This example connects to an unencrypted Wifi network.  + Then it prints the  MAC address of the Wifi shield, + the IP address obtained, and other network details. + + Circuit: + * WiFi shield attached +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + #include <WiFi.h> + +char ssid[] = "yourNetwork";     //  your network SSID (name)  +char pass[] = "secretPassword";  // your network password +int status = WL_IDLE_STATUS;     // the Wifi radio's status + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   + // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to WPA SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  } +    +  // you're connected now, so print out the data: +  Serial.print("You're connected to the network"); +  printCurrentNet(); +  printWifiData(); + +} + +void loop() { +  // check the network connection once every 10 seconds: +  delay(10000); +  printCurrentNet(); +} + +void printWifiData() { +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +    Serial.print("IP Address: "); +  Serial.println(ip); +  Serial.println(ip); +   +  // print your MAC address: +  byte mac[6];   +  WiFi.macAddress(mac); +  Serial.print("MAC address: "); +  Serial.print(mac[5],HEX); +  Serial.print(":"); +  Serial.print(mac[4],HEX); +  Serial.print(":"); +  Serial.print(mac[3],HEX); +  Serial.print(":"); +  Serial.print(mac[2],HEX); +  Serial.print(":"); +  Serial.print(mac[1],HEX); +  Serial.print(":"); +  Serial.println(mac[0],HEX); +  +} + +void printCurrentNet() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print the MAC address of the router you're attached to: +  byte bssid[6]; +  WiFi.BSSID(bssid);     +  Serial.print("BSSID: "); +  Serial.print(bssid[5],HEX); +  Serial.print(":"); +  Serial.print(bssid[4],HEX); +  Serial.print(":"); +  Serial.print(bssid[3],HEX); +  Serial.print(":"); +  Serial.print(bssid[2],HEX); +  Serial.print(":"); +  Serial.print(bssid[1],HEX); +  Serial.print(":"); +  Serial.println(bssid[0],HEX); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.println(rssi); + +  // print the encryption type: +  byte encryption = WiFi.encryptionType(); +  Serial.print("Encryption Type:"); +  Serial.println(encryption,HEX); +  Serial.println(); +} + diff --git a/libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino b/libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino new file mode 100644 index 0000000..93b3000 --- /dev/null +++ b/libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino @@ -0,0 +1,119 @@ +/* +  + This example  prints the Wifi shield's MAC address, and + scans for available Wifi networks using the Wifi shield. + Every ten seconds, it scans again. It doesn't actually  + connect to any network, so no encryption scheme is specified. +  + Circuit: + * WiFi shield attached +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 21 Junn 2012 + by Tom Igoe and Jaymes Dec + */ + + +#include <SPI.h> +#include <WiFi.h> + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } + +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  + +  // Print WiFi MAC address: +  printMacAddress(); + +  // scan for existing networks: +  Serial.println("Scanning available networks..."); +  listNetworks(); +} + +void loop() { +  delay(10000); +  // scan for existing networks: +  Serial.println("Scanning available networks..."); +  listNetworks(); +} + +void printMacAddress() { +  // the MAC address of your Wifi shield +  byte mac[6];                      + +  // print your MAC address: +  WiFi.macAddress(mac); +  Serial.print("MAC: "); +  Serial.print(mac[5],HEX); +  Serial.print(":"); +  Serial.print(mac[4],HEX); +  Serial.print(":"); +  Serial.print(mac[3],HEX); +  Serial.print(":"); +  Serial.print(mac[2],HEX); +  Serial.print(":"); +  Serial.print(mac[1],HEX); +  Serial.print(":"); +  Serial.println(mac[0],HEX); +} + +void listNetworks() { +  // scan for nearby networks: +  Serial.println("** Scan Networks **"); +  int numSsid = WiFi.scanNetworks(); +  if (numSsid == -1) +  {  +    Serial.println("Couldn't get a wifi connection"); +    while(true); +  }  + +  // print the list of networks seen: +  Serial.print("number of available networks:"); +  Serial.println(numSsid); + +  // print the network number and name for each network found: +  for (int thisNet = 0; thisNet<numSsid; thisNet++) { +    Serial.print(thisNet); +    Serial.print(") "); +    Serial.print(WiFi.SSID(thisNet)); +    Serial.print("\tSignal: "); +    Serial.print(WiFi.RSSI(thisNet)); +    Serial.print(" dBm"); +    Serial.print("\tEncryption: "); +    printEncryptionType(WiFi.encryptionType(thisNet)); +  } +} + +void printEncryptionType(int thisType) { +  // read the encryption type and print out the name: +  switch (thisType) { +  case ENC_TYPE_WEP: +    Serial.println("WEP"); +    break; +  case ENC_TYPE_TKIP: +    Serial.println("WPA"); +    break; +  case ENC_TYPE_CCMP: +    Serial.println("WPA2"); +    break; +  case ENC_TYPE_NONE: +    Serial.println("None"); +    break; +  case ENC_TYPE_AUTO: +    Serial.println("Auto"); +    break; +  }  +} + + + diff --git a/libraries/WiFi/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino b/libraries/WiFi/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino new file mode 100644 index 0000000..cdb4e62 --- /dev/null +++ b/libraries/WiFi/examples/SimpleWebServerWiFi/SimpleWebServerWiFi.ino @@ -0,0 +1,129 @@ +/* +  WiFi Web Server LED Blink +  + A simple web server that lets you blink an LED via the web. + This sketch will print the IP address of your WiFi Shield (once connected) + to the Serial monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 9. +  + If the IP address of your shield is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + Circuit: + * WiFi shield attached + * LED attached to pin 9 +  + created 25 Nov 2012 + by Tom Igoe + */ +#include <SPI.h> +#include <WiFi.h> + +char ssid[] = "yourNetwork";      //  your network SSID (name)  +char pass[] = "secretPassword";   // your network password +int keyIndex = 0;                 // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +WiFiServer server(80); + +void setup() { +  Serial.begin(9600);      // initialize serial communication +  pinMode(9, OUTPUT);      // set the LED pin mode + +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    while(true);        // don't continue +  }  + +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to Network named: "); +    Serial.println(ssid);                   // print the network name (SSID); + +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); +    // wait 10 seconds for connection: +    delay(10000); +  }  +  server.begin();                           // start the web server on port 80 +  printWifiStatus();                        // you're connected now, so print out the status +} + + +void loop() { +  WiFiClient client = server.available();   // listen for incoming clients + +  if (client) {                             // if you get a client, +    Serial.println("new client");           // print a message out the serial port +    String currentLine = "";                // make a String to hold incoming data from the client +    while (client.connected()) {            // loop while the client's connected +      if (client.available()) {             // if there's bytes to read from the client, +        char c = client.read();             // read a byte, then +        Serial.write(c);                    // print it out the serial monitor +        if (c == '\n') {                    // if the byte is a newline character + +          // if the current line is blank, you got two newline characters in a row. +          // that's the end of the client HTTP request, so send a response: +          if (currentLine.length() == 0) {   +            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) +            // and a content-type so the client knows what's coming, then a blank line:     +            client.println("HTTP/1.1 200 OK"); +            client.println("Content-type:text/html"); +            client.println(); + +            // the content of the HTTP response follows the header: +            client.print("Click <a href=\"/H\">here</a> turn the LED on pin 9 on<br>"); +            client.print("Click <a href=\"/L\">here</a> turn the LED on pin 9 off<br>"); + +            // The HTTP response ends with another blank line: +            client.println(); +            // break out of the while loop: +            break;          +          }  +          else {      // if you got a newline, then clear currentLine: +            currentLine = ""; +          } +        }      +        else if (c != '\r') {    // if you got anything else but a carriage return character, +          currentLine += c;      // add it to the end of the currentLine +        } + +        // Check to see if the client request was "GET /H" or "GET /L": +        if (currentLine.endsWith("GET /H")) { +          digitalWrite(9, HIGH);               // GET /H turns the LED on +        } +        if (currentLine.endsWith("GET /L")) { +          digitalWrite(9, LOW);                // GET /L turns the LED off +        } +      } +    } +    // close the connection: +    client.stop(); +    Serial.println("client disonnected"); +  } +} + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +  // print where to go in a browser: +  Serial.print("To see this page in action, open a browser to http://"); +  Serial.println(ip); +} diff --git a/libraries/WiFi/examples/WifiChatServer/WifiChatServer.ino b/libraries/WiFi/examples/WifiChatServer/WifiChatServer.ino new file mode 100644 index 0000000..e4b1d1a --- /dev/null +++ b/libraries/WiFi/examples/WifiChatServer/WifiChatServer.ino @@ -0,0 +1,111 @@ +/* + Chat  Server +  + A simple server that distributes any incoming messages to all + connected clients.  To use telnet to  your device's IP address and type. + You can see the client's input in the serial monitor as well. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  +  + Circuit: + * WiFi shield attached +  + created 18 Dec 2009 + by David A. Mellis + modified 31 May 2012 + by Tom Igoe +  + */ + +#include <SPI.h> +#include <WiFi.h> + +char ssid[] = "yourNetwork"; //  your network SSID (name)  +char pass[] = "secretPassword";    // your network password (use for WPA, or use as key for WEP) + +int keyIndex = 0;            // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(23); + +boolean alreadyConnected = false; // whether or not the client was connected previously + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  }  +  // start the server: +  server.begin(); +  // you're connected now, so print out the status: +  printWifiStatus(); + } + + +void loop() { +  // wait for a new client: +  WiFiClient client = server.available(); + + +  // when the client sends the first byte, say hello: +  if (client) { +    if (!alreadyConnected) { +      // clead out the input buffer: +      client.flush();     +      Serial.println("We have a new client"); +      client.println("Hello, client!");  +      alreadyConnected = true; +    }  + +    if (client.available() > 0) { +      // read the bytes incoming from the client: +      char thisChar = client.read(); +      // echo the bytes back to the client: +      server.write(thisChar); +      // echo the bytes to the server as well: +      Serial.write(thisChar); +    } +  } +} + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + diff --git a/libraries/WiFi/examples/WifiPachubeClient/WifiPachubeClient.ino b/libraries/WiFi/examples/WifiPachubeClient/WifiPachubeClient.ino new file mode 100644 index 0000000..f8ffc07 --- /dev/null +++ b/libraries/WiFi/examples/WifiPachubeClient/WifiPachubeClient.ino @@ -0,0 +1,190 @@ +/* +  Wifi Pachube sensor client +  + This sketch connects an analog sensor to Pachube (http://www.pachube.com) + using an Arduino Wifi shield. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + This example has been updated to use version 2.0 of the Pachube API.  + To make it work, create a feed with a datastream, and give it the ID + sensor1. Or change the code below to match your feed. +  + Circuit: + * Analog sensor attached to analog in 0 + * Wifi shield attached to pins 10, 11, 12, 13 +  + created 13 Mar 2012 + modified 31 May 2012 + by Tom Igoe + modified 8 Sept 2012 + by Scott Fitzgerald +  + This code is in the public domain. +  + */ +#include <SPI.h> +#include <WiFi.h> + +#define APIKEY         "YOUR API KEY GOES HERE" // replace your pachube api key here +#define FEEDID         00000                    // replace your feed ID +#define USERAGENT      "My Arduino Project"     // user agent is the project name + +char ssid[] = "yourNetwork";      //  your network SSID (name)  +char pass[] = "secretPassword";   // your network password + +int status = WL_IDLE_STATUS; + +// initialize the library instance: +WiFiClient client; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +IPAddress server(216,52,233,121);      // numeric IP for api.pachube.com +//char server[] = "api.pachube.com";   // name address for pachube API + +unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds +boolean lastConnected = false;                 // state of the connection last time through the main loop +const unsigned long postingInterval = 10*1000; //delay between updates to pachube.com + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  }  +  // you're connected now, so print out the status: +  printWifiStatus(); +} + + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  while (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data: +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(sensorReading); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(int thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.pachube.com"); +    client.print("X-ApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); + +    // calculate the length of the sensor reading in bytes: +    // 8 bytes for "sensor1," + number of digits of the data: +    int thisLength = 8 + getLength(thisData); +    client.println(thisLength); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.print("sensor1,"); +    client.println(thisData); +   +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +   // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + + +// This method calculates the number of digits in the +// sensor reading.  Since each digit of the ASCII decimal +// representation is a byte, the number of digits equals +// the number of bytes: + +int getLength(int someValue) { +  // there's at least one byte: +  int digits = 1; +  // continually divide the value by ten,  +  // adding one to the digit count for each +  // time you divide, until you're at 0: +  int dividend = someValue /10; +  while (dividend > 0) { +    dividend = dividend /10; +    digits++; +  } +  // return the number of digits: +  return digits; +} + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + + diff --git a/libraries/WiFi/examples/WifiPachubeClientString/WifiPachubeClientString.ino b/libraries/WiFi/examples/WifiPachubeClientString/WifiPachubeClientString.ino new file mode 100644 index 0000000..243fe83 --- /dev/null +++ b/libraries/WiFi/examples/WifiPachubeClientString/WifiPachubeClientString.ino @@ -0,0 +1,177 @@ +/* +  Wifi Pachube sensor client with Strings +  + This sketch connects an analog sensor to Pachube (http://www.pachube.com) + using a Arduino Wifi shield. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + This example has been updated to use version 2.0 of the pachube.com API.  + To make it work, create a feed with a datastream, and give it the ID + sensor1. Or change the code below to match your feed. +  + This example uses the String library, which is part of the Arduino core from + version 0019.   +  + Circuit: + * Analog sensor attached to analog in 0 + * Wifi shield attached to pins 10, 11, 12, 13 +  + created 16 Mar 2012 + modified 31 May 2012 + by Tom Igoe + modified 8 Sept 2012 + by Scott Fitzgerald +  + This code is in the public domain. +  + */ + +#include <SPI.h> +#include <WiFi.h> + +#define APIKEY         "YOUR API KEY GOES HERE" // replace your pachube api key here +#define FEEDID         00000                    // replace your feed ID +#define USERAGENT      "My Arduino Project"     // user agent is the project name + +char ssid[] = "yourNetwork";      //  your network SSID (name)  +char pass[] = "secretPassword";   // your network password + +int status = WL_IDLE_STATUS; + +// initialize the library instance: +WiFiClient client; + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(216,52,233,121);      // numeric IP for api.pachube.com +char server[] = "api.pachube.com";   // name address for pachube API + +unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds +boolean lastConnected = false;                 // state of the connection last time through the main loop +const unsigned long postingInterval = 10*1000;  //delay between updates to pachube.com + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  }  +  // you're connected now, so print out the status: +  printWifiStatus(); +} + +void loop() { +  // read the analog sensor: +  int sensorReading = analogRead(A0);    +  // convert the data to a String to send it: + +  String dataString = "sensor1,"; +  dataString += sensorReading; + +  // you can append multiple readings to this String if your +  // pachube feed is set up to handle multiple values: +  int otherSensorReading = analogRead(A1); +  dataString += "\nsensor2,"; +  dataString += otherSensorReading; + +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  while (client.available()) { +    char c = client.read(); +    Serial.print(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data:  +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    sendData(dataString); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void sendData(String thisData) { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.print("PUT /v2/feeds/"); +    client.print(FEEDID); +    client.println(".csv HTTP/1.1"); +    client.println("Host: api.pachube.com"); +    client.print("X-ApiKey: "); +    client.println(APIKEY); +    client.print("User-Agent: "); +    client.println(USERAGENT); +    client.print("Content-Length: "); +    client.println(thisData.length()); + +    // last pieces of the HTTP PUT request: +    client.println("Content-Type: text/csv"); +    client.println("Connection: close"); +    client.println(); + +    // here's the actual content of the PUT request: +    client.println(thisData); +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } +  // note the time that the connection was made or attempted: +  lastConnectionTime = millis(); +} + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + diff --git a/libraries/WiFi/examples/WifiTwitterClient/WifiTwitterClient.ino b/libraries/WiFi/examples/WifiTwitterClient/WifiTwitterClient.ino new file mode 100644 index 0000000..3dc2c8d --- /dev/null +++ b/libraries/WiFi/examples/WifiTwitterClient/WifiTwitterClient.ino @@ -0,0 +1,163 @@ +/* +  Wifi Twitter Client with Strings +  + This sketch connects to Twitter using using an Arduino WiFi shield.  + It parses the XML returned, and looks for <text>this is a tweet</text> +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + This example uses the String library, which is part of the Arduino core from + version 0019.   +  + Circuit: + * WiFi shield attached to pins 10, 11, 12, 13 +  + created 23 apr 2012 + modified 31 May 2012 + by Tom Igoe +  + This code is in the public domain. +  + */ +#include <SPI.h> +#include <WiFi.h> + +char ssid[] = "yourNetwork"; //  your network SSID (name)  +char pass[] = "password";    // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0;            // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; // status of the wifi connection + +// initialize the library instance: +WiFiClient client; + +const unsigned long requestInterval = 30*1000;    // delay between requests; 30 seconds + +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +//IPAddress server(199,59,149,200);    // numeric IP for api.twitter.com +char server[] = "api.twitter.com";     // name address for twitter API + +boolean requested;                     // whether you've made a request since connecting +unsigned long lastAttemptTime = 0;     // last time you connected to the server, in milliseconds + +String currentLine = "";               // string to hold the text from server +String tweet = "";                     // string to hold the tweet +boolean readingTweet = false;          // if you're currently reading the tweet + +void setup() { +  // reserve space for the strings: +  currentLine.reserve(256); +  tweet.reserve(150); +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass);   +  +    // wait 10 seconds for connection: +    delay(10000); +  }  +  // you're connected now, so print out the status: +  printWifiStatus(); +  connectToServer(); +} + +void loop() +{ +  if (client.connected()) { +    if (client.available()) { +      // read incoming bytes: +      char inChar = client.read(); + +      // add incoming byte to end of line: +      currentLine += inChar;  + +      // if you get a newline, clear the line: +      if (inChar == '\n') { +        currentLine = ""; +      }  +      // if the current line ends with <text>, it will +      // be followed by the tweet: +      if ( currentLine.endsWith("<text>")) { +        // tweet is beginning. Clear the tweet string: +        readingTweet = true;  +        tweet = ""; +        // break out of the loop so this character isn't added to the tweet: +        return; +      } +      // if you're currently reading the bytes of a tweet, +      // add them to the tweet String: +      if (readingTweet) { +        if (inChar != '<') { +          tweet += inChar; +        }  +        else { +          // if you got a "<" character, +          // you've reached the end of the tweet: +          readingTweet = false; +          Serial.println(tweet);    +          // close the connection to the server: +          client.stop();  +        } +      } +    }    +  } +  else if (millis() - lastAttemptTime > requestInterval) { +    // if you're not connected, and two minutes have passed since +    // your last connection, then attempt to connect again: +    connectToServer(); +  } +} + +void connectToServer() { +  // attempt to connect, and wait a millisecond: +  Serial.println("connecting to server..."); +  if (client.connect(server, 80)) { +    Serial.println("making HTTP request..."); +    // make HTTP GET request to twitter: +    client.println("GET /1/statuses/user_timeline.xml?screen_name=arduino HTTP/1.1"); +    client.println("Host:api.twitter.com"); +    client.println("Connection:close"); +    client.println(); +  } +  // note the time of this connect attempt: +  lastAttemptTime = millis(); +}    + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + + + diff --git a/libraries/WiFi/examples/WifiWebClient/WifiWebClient.ino b/libraries/WiFi/examples/WifiWebClient/WifiWebClient.ino new file mode 100644 index 0000000..17f44a3 --- /dev/null +++ b/libraries/WiFi/examples/WifiWebClient/WifiWebClient.ino @@ -0,0 +1,121 @@ + +/* +  Web client +  + This sketch connects to a website (http://www.google.com) + using a WiFi shield. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + Circuit: + * WiFi shield attached +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ + + +#include <SPI.h> +#include <WiFi.h> + +char ssid[] = "yourNetwork"; //  your network SSID (name)  +char pass[] = "secretPassword";    // your network password (use for WPA, or use as key for WEP) +int keyIndex = 0;            // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; +// if you don't want to use DNS (and reduce your sketch size) +// use the numeric IP instead of the name for the server: +IPAddress server(173,194,73,105);  // numeric IP for Google (no DNS) +//char server[] = "www.google.com";    // name address for Google (using DNS) + +// Initialize the Ethernet client library +// with the IP address and port of the server  +// that you want to connect to (port 80 is default for HTTP): +WiFiClient client; + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); +   +    // wait 10 seconds for connection: +    delay(10000); +  }  +  Serial.println("Connected to wifi"); +  printWifiStatus(); +   +  Serial.println("\nStarting connection to server..."); +  // if you get a connection, report back via serial: +  if (client.connect(server, 80)) { +    Serial.println("connected to server"); +    // Make a HTTP request: +    client.println("GET /search?q=arduino HTTP/1.1"); +    client.println("Host:www.google.com"); +    client.println("Connection: close"); +    client.println(); +  } +} + +void loop() { +  // if there are incoming bytes available  +  // from the server, read them and print them: +  while (client.available()) { +    char c = client.read(); +    Serial.write(c); +  } + +  // if the server's disconnected, stop the client: +  if (!client.connected()) { +    Serial.println(); +    Serial.println("disconnecting from server."); +    client.stop(); + +    // do nothing forevermore: +    while(true); +  } +} + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + + + + diff --git a/libraries/WiFi/examples/WifiWebClientRepeating/WifiWebClientRepeating.ino b/libraries/WiFi/examples/WifiWebClientRepeating/WifiWebClientRepeating.ino new file mode 100644 index 0000000..96eb628 --- /dev/null +++ b/libraries/WiFi/examples/WifiWebClientRepeating/WifiWebClientRepeating.ino @@ -0,0 +1,138 @@ +/* +  Repeating Wifi Web client +  + This sketch connects to a a web server and makes a request + using an Arduino Wifi shield. +  + Circuit: + * Wifi shield attached to pins 10, 11, 12, 13 +  + created 23 April 2012 + modifide 31 May 2012 + by Tom Igoe +  + http://arduino.cc/en/Tutorial/WifiWebClientRepeating + This code is in the public domain. + */ + +#include <SPI.h> +#include <WiFi.h> + +char ssid[] = "yourNetwork";      //  your network SSID (name)  +char pass[] = "secretPassword";   // your network password +int keyIndex = 0;            // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +// Initialize the Wifi client library +WiFiClient client; + +// server address: +char server[] = "www.arduino.cc"; +//IPAddress server(64,131,82,241); + +unsigned long lastConnectionTime = 0;           // last time you connected to the server, in milliseconds +boolean lastConnected = false;                  // state of the connection last time through the main loop +const unsigned long postingInterval = 10*1000;  // delay between updates, in milliseconds + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  }  +  // you're connected now, so print out the status: +  printWifiStatus(); +} + +void loop() { +  // if there's incoming data from the net connection. +  // send it out the serial port.  This is for debugging +  // purposes only: +  while (client.available()) { +    char c = client.read(); +    Serial.write(c); +  } + +  // if there's no net connection, but there was one last time +  // through the loop, then stop the client: +  if (!client.connected() && lastConnected) { +    Serial.println(); +    Serial.println("disconnecting."); +    client.stop(); +  } + +  // if you're not connected, and ten seconds have passed since +  // your last connection, then connect again and send data: +  if(!client.connected() && (millis() - lastConnectionTime > postingInterval)) { +    httpRequest(); +  } +  // store the state of the connection for next time through +  // the loop: +  lastConnected = client.connected(); +} + +// this method makes a HTTP connection to the server: +void httpRequest() { +  // if there's a successful connection: +  if (client.connect(server, 80)) { +    Serial.println("connecting..."); +    // send the HTTP PUT request: +    client.println("GET /latest.txt HTTP/1.1"); +    client.println("Host: www.arduino.cc"); +    client.println("User-Agent: arduino-ethernet"); +    client.println("Connection: close"); +    client.println(); + +    // note the time that the connection was made: +    lastConnectionTime = millis(); +  }  +  else { +    // if you couldn't make a connection: +    Serial.println("connection failed"); +    Serial.println("disconnecting."); +    client.stop(); +  } +} + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + + + + + + diff --git a/libraries/WiFi/examples/WifiWebServer/WifiWebServer.ino b/libraries/WiFi/examples/WifiWebServer/WifiWebServer.ino new file mode 100644 index 0000000..ac5f056 --- /dev/null +++ b/libraries/WiFi/examples/WifiWebServer/WifiWebServer.ino @@ -0,0 +1,132 @@ +/* +  Web  Server +  + A simple web server that shows the value of the analog input pins. + using a WiFi shield. +  + This example is written for a network using WPA encryption. For  + WEP or WPA, change the Wifi.begin() call accordingly. +  + Circuit: + * WiFi shield attached + * Analog inputs attached to pins A0 through A5 (optional) +  + created 13 July 2010 + by dlf (Metodo2 srl) + modified 31 May 2012 + by Tom Igoe + */ +#include <SPI.h> +#include <WiFi.h> + + +char ssid[] = "yourNetwork";      //  your network SSID (name)  +char pass[] = "secretPassword";   // your network password +int keyIndex = 0;                 // your network key Index number (needed only for WEP) + +int status = WL_IDLE_STATUS; + +WiFiServer server(80); + +void setup() { +  //Initialize serial and wait for port to open: +  Serial.begin(9600);  +  while (!Serial) { +    ; // wait for serial port to connect. Needed for Leonardo only +  } +   +  // check for the presence of the shield: +  if (WiFi.status() == WL_NO_SHIELD) { +    Serial.println("WiFi shield not present");  +    // don't continue: +    while(true); +  }  +   +  // attempt to connect to Wifi network: +  while ( status != WL_CONNECTED) {  +    Serial.print("Attempting to connect to SSID: "); +    Serial.println(ssid); +    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:     +    status = WiFi.begin(ssid, pass); + +    // wait 10 seconds for connection: +    delay(10000); +  }  +  server.begin(); +  // you're connected now, so print out the status: +  printWifiStatus(); +} + + +void loop() { +  // listen for incoming clients +  WiFiClient client = server.available(); +  if (client) { +    Serial.println("new client"); +    // an http request ends with a blank line +    boolean currentLineIsBlank = true; +    while (client.connected()) { +      if (client.available()) { +        char c = client.read(); +        Serial.write(c); +        // if you've gotten to the end of the line (received a newline +        // character) and the line is blank, the http request has ended, +        // so you can send a reply +        if (c == '\n' && currentLineIsBlank) { +          // send a standard http response header +          client.println("HTTP/1.1 200 OK"); +          client.println("Content-Type: text/html"); +          client.println("Connnection: close"); +          client.println(); +          client.println("<!DOCTYPE HTML>"); +          client.println("<html>"); +          // add a meta refresh tag, so the browser pulls again every 5 seconds: +          client.println("<meta http-equiv=\"refresh\" content=\"5\">"); +          // output the value of each analog input pin +          for (int analogChannel = 0; analogChannel < 6; analogChannel++) { +            int sensorReading = analogRead(analogChannel); +            client.print("analog input "); +            client.print(analogChannel); +            client.print(" is "); +            client.print(sensorReading); +            client.println("<br />");        +          } +          client.println("</html>"); +           break; +        } +        if (c == '\n') { +          // you're starting a new line +          currentLineIsBlank = true; +        }  +        else if (c != '\r') { +          // you've gotten a character on the current line +          currentLineIsBlank = false; +        } +      } +    } +    // give the web browser time to receive the data +    delay(1); +      // close the connection: +      client.stop(); +      Serial.println("client disonnected"); +  } +} + + +void printWifiStatus() { +  // print the SSID of the network you're attached to: +  Serial.print("SSID: "); +  Serial.println(WiFi.SSID()); + +  // print your WiFi shield's IP address: +  IPAddress ip = WiFi.localIP(); +  Serial.print("IP Address: "); +  Serial.println(ip); + +  // print the received signal strength: +  long rssi = WiFi.RSSI(); +  Serial.print("signal strength (RSSI):"); +  Serial.print(rssi); +  Serial.println(" dBm"); +} + diff --git a/libraries/WiFi/keywords.txt b/libraries/WiFi/keywords.txt new file mode 100644 index 0000000..47704cd --- /dev/null +++ b/libraries/WiFi/keywords.txt @@ -0,0 +1,43 @@ +####################################### +# Syntax Coloring Map For WiFi +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +WiFi	KEYWORD1 +Client	KEYWORD1 +Server	KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +status	KEYWORD2 +connect	KEYWORD2 +write	KEYWORD2 +available	KEYWORD2 +read	KEYWORD2 +flush	KEYWORD2 +stop	KEYWORD2 +connected	KEYWORD2 +begin	KEYWORD2 +disconnect	KEYWORD2 +macAddress	KEYWORD2 +localIP	KEYWORD2 +subnetMask	KEYWORD2 +gatewayIP	KEYWORD2 +SSID	KEYWORD2 +BSSID		KEYWORD2 +RSSI	KEYWORD2 +encryptionType	KEYWORD2 +getResult	KEYWORD2 +getSocket	KEYWORD2 +WiFiClient	KEYWORD2 +WiFiServer	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/WiFi/utility/debug.h b/libraries/WiFi/utility/debug.h new file mode 100644 index 0000000..9f71055 --- /dev/null +++ b/libraries/WiFi/utility/debug.h @@ -0,0 +1,77 @@ +//*********************************************/ +//  +//  File:   debug.h +//  +//  Author: dlf (Metodo2 srl) +//  +//********************************************/ + + +#ifndef Debug_H +#define Debug_H + +#include <stdio.h> +#include <string.h> + +#define PRINT_FILE_LINE() do { 						\ +		Serial.print("[");Serial.print(__FILE__);		\ +		Serial.print("::");Serial.print(__LINE__);Serial.print("]");\ +}while (0); + +#ifdef _DEBUG_ + +#define INFO(format, args...) do { \ +	char buf[250];	\ +	sprintf(buf, format, args); \ +	Serial.println(buf); \ +} while(0); + +#define INFO1(x) do { PRINT_FILE_LINE() Serial.print("-I-");\ +		Serial.println(x);    			\ +}while (0); + + +#define INFO2(x,y) do { PRINT_FILE_LINE() Serial.print("-I-");\ +		Serial.print(x,16);Serial.print(",");Serial.println(y,16); \ +}while (0); + + +#else +#define INFO1(x) do {} while(0); +#define INFO2(x,y) do {} while(0); +#define INFO(format, args...) do {} while(0); +#endif + +#if 0 +#define WARN(args) do { PRINT_FILE_LINE()			\ +		Serial.print("-W-"); Serial.println(args);	\ +}while (0); +#else +#define WARN(args) do {} while (0); +#endif + +#if _DEBUG_SPI_ +#define DBG_PIN2 5 +#define DBG_PIN 4 + +#define START()         digitalWrite(DBG_PIN2, HIGH); +#define END()           digitalWrite(DBG_PIN2, LOW); +#define SET_TRIGGER()   digitalWrite(DBG_PIN, HIGH); +#define RST_TRIGGER()   digitalWrite(DBG_PIN, LOW); + +#define INIT_TRIGGER()  pinMode(DBG_PIN, OUTPUT); \ +                        pinMode(DBG_PIN2, OUTPUT); \ +                        RST_TRIGGER() +#define TOGGLE_TRIGGER() SET_TRIGGER() \ +                           delayMicroseconds(2);    \ +                               RST_TRIGGER() +#else +#define START() +#define END() +#define SET_TRIGGER() +#define RST_TRIGGER() +#define INIT_TRIGGER() +#define TOGGLE_TRIGGER() +#endif + +#endif diff --git a/libraries/WiFi/utility/server_drv.cpp b/libraries/WiFi/utility/server_drv.cpp new file mode 100644 index 0000000..ce03604 --- /dev/null +++ b/libraries/WiFi/utility/server_drv.cpp @@ -0,0 +1,260 @@ +//#define _DEBUG_
 +
 +#include "server_drv.h"
 +
 +#include "Arduino.h"
 +#include "spi_drv.h"
 +
 +extern "C" {
 +#include "wl_types.h"
 +#include "debug.h"
 +}
 +
 +
 +// Start server TCP on port specified
 +void ServerDrv::startServer(uint16_t port, uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(START_SERVER_TCP_CMD, PARAM_NUMS_2);
 +    SpiDrv::sendParam(port);
 +    SpiDrv::sendParam(&sock, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(START_SERVER_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +}
 +
 +// Start server TCP on port specified
 +void ServerDrv::startClient(uint32_t ipAddress, uint16_t port, uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_3);
 +    SpiDrv::sendParam((uint8_t*)&ipAddress, sizeof(ipAddress));
 +    SpiDrv::sendParam(port);
 +    SpiDrv::sendParam(&sock, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(START_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +}
 +
 +// Start server TCP on port specified
 +void ServerDrv::stopClient(uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam(&sock, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(STOP_CLIENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +}
 +
 +
 +uint8_t ServerDrv::getServerState(uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(GET_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +   return _data;
 +}
 +
 +uint8_t ServerDrv::getClientState(uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(GET_CLIENT_STATE_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +   return _data;
 +}
 +
 +uint8_t ServerDrv::availData(uint8_t sock)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(AVAIL_DATA_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +
 +    if (_dataLen!=0)
 +    {
 +        return (_data == 1);
 +    }
 +    return false;
 +}
 +
 +bool ServerDrv::getData(uint8_t sock, uint8_t *data, uint8_t peek)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_DATA_TCP_CMD, PARAM_NUMS_2);
 +    SpiDrv::sendParam(&sock, sizeof(sock));
 +    SpiDrv::sendParam(peek, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseData8(GET_DATA_TCP_CMD, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    if (_dataLen!=0)
 +    {
 +        *data = _data;
 +        return true;
 +    }
 +    return false;
 +}
 +
 +bool ServerDrv::getDataBuf(uint8_t sock, uint8_t *_data, uint16_t *_dataLen)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_DATABUF_TCP_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendBuffer(&sock, sizeof(sock), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    if (!SpiDrv::waitResponseData16(GET_DATABUF_TCP_CMD, _data, _dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    if (*_dataLen!=0)
 +    {
 +        return true;
 +    }
 +    return false;
 +}
 +
 +
 +bool ServerDrv::sendData(uint8_t sock, const uint8_t *data, uint16_t len)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(SEND_DATA_TCP_CMD, PARAM_NUMS_2);
 +    SpiDrv::sendBuffer(&sock, sizeof(sock));
 +    SpiDrv::sendBuffer((uint8_t *)data, len, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseData8(SEND_DATA_TCP_CMD, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    if (_dataLen!=0)
 +    {
 +        return (_data == 1);
 +    }
 +    return false;
 +}
 +
 +
 +uint8_t ServerDrv::checkDataSent(uint8_t sock)
 +{
 +	const uint16_t TIMEOUT_DATA_SENT = 25;
 +    uint16_t timeout = 0;
 +	uint8_t _data = 0;
 +	uint8_t _dataLen = 0;
 +
 +	do {
 +		WAIT_FOR_SLAVE_SELECT();
 +		// Send Command
 +		SpiDrv::sendCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1);
 +		SpiDrv::sendParam(&sock, sizeof(sock), LAST_PARAM);
 +
 +		//Wait the reply elaboration
 +		SpiDrv::waitForSlaveReady();
 +
 +		// Wait for reply
 +		if (!SpiDrv::waitResponseCmd(DATA_SENT_TCP_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +		{
 +			WARN("error waitResponse isDataSent");
 +		}
 +		SpiDrv::spiSlaveDeselect();
 +
 +		if (_data) timeout = 0;
 +		else{
 +			++timeout;
 +			delay(100);
 +		}
 +
 +	}while((_data==0)&&(timeout<TIMEOUT_DATA_SENT));
 +    return (timeout==TIMEOUT_DATA_SENT)?0:1;
 +}
 +
 +ServerDrv serverDrv;
 diff --git a/libraries/WiFi/utility/server_drv.h b/libraries/WiFi/utility/server_drv.h new file mode 100644 index 0000000..69ba593 --- /dev/null +++ b/libraries/WiFi/utility/server_drv.h @@ -0,0 +1,34 @@ +#ifndef Server_Drv_h
 +#define Server_Drv_h
 +
 +#include <inttypes.h>
 +#include "wifi_spi.h"
 +
 +class ServerDrv
 +{
 +public:
 +    // Start server TCP on port specified
 +    static void startServer(uint16_t port, uint8_t sock);
 +
 +    static void startClient(uint32_t ipAddress, uint16_t port, uint8_t sock);
 +
 +    static void stopClient(uint8_t sock);
 +                                                                                  
 +    static uint8_t getServerState(uint8_t sock);
 +
 +    static uint8_t getClientState(uint8_t sock);
 +
 +    static bool getData(uint8_t sock, uint8_t *data, uint8_t peek = 0);
 +
 +    static bool getDataBuf(uint8_t sock, uint8_t *data, uint16_t *len);
 +
 +    static bool sendData(uint8_t sock, const uint8_t *data, uint16_t len);
 +
 +    static uint8_t availData(uint8_t sock);
 +
 +    static uint8_t checkDataSent(uint8_t sock);
 +};
 +
 +extern ServerDrv serverDrv;
 +
 +#endif
 diff --git a/libraries/WiFi/utility/socket.c b/libraries/WiFi/utility/socket.c new file mode 100644 index 0000000..665073b --- /dev/null +++ b/libraries/WiFi/utility/socket.c @@ -0,0 +1,20 @@ +/*
 +*
 +@file		socket.c
 +@brief	define function of socket API 
 +*
 +*/
 +#include <inttypes.h>
 +#include "socket.h"
 +
 +SOCKET socket(uint8 protocol) {return 0;} // Opens a socket(TCP or UDP or IP_RAW mode)
 +void close(SOCKET s) {} // Close socket
 +uint8 connect(SOCKET s, uint8 * addr, uint16 port) {return 0;} // Establish TCP connection (Active connection)
 +void disconnect(SOCKET s) {} // disconnect the connection
 +uint8 listen(SOCKET s) { return 0;}	// Establish TCP connection (Passive connection)
 +uint16 send(SOCKET s, const uint8 * buf, uint16 len) { return 0;} // Send data (TCP)
 +uint16 recv(SOCKET s, uint8 * buf, uint16 len) {return 0;}	// Receive data (TCP)
 +uint16 sendto(SOCKET s, const uint8 * buf, uint16 len, uint8 * addr, uint16 port) {return 0;} // Send data (UDP/IP RAW)
 +uint16 recvfrom(SOCKET s, uint8 * buf, uint16 len, uint8 * addr, uint16  *port) {return 0;} // Receive data (UDP/IP RAW)
 +
 +uint16 igmpsend(SOCKET s, const uint8 * buf, uint16 len) {return 0;}
 diff --git a/libraries/WiFi/utility/socket.h b/libraries/WiFi/utility/socket.h new file mode 100644 index 0000000..9b06d00 --- /dev/null +++ b/libraries/WiFi/utility/socket.h @@ -0,0 +1,87 @@ +/*
 +*
 +@file		socket.h
 +@brief	define function of socket API 
 +*
 +*/
 +
 +#ifndef	_SOCKET_H_
 +#define	_SOCKET_H_
 +
 +#define TCP_SOCKET  1
 +#define UDP_SOCKET  2
 +#define RAW_SOCKET  3
 +
 +#define SOCK_NOT_AVAIL  255
 +
 +#include "wl_definitions.h"
 +/**
 + * The 8-bit signed data type.
 + */
 +typedef char int8;
 +/**
 + * The volatile 8-bit signed data type.
 + */
 +typedef volatile char vint8;
 +/**
 + * The 8-bit unsigned data type.
 + */
 +typedef unsigned char uint8;
 +/**
 + * The volatile 8-bit unsigned data type.
 + */
 +typedef volatile unsigned char vuint8;
 +
 +/**
 + * The 16-bit signed data type.
 + */
 +typedef int int16;
 +/**
 + * The volatile 16-bit signed data type.
 + */
 +typedef volatile int vint16;
 +/**
 + * The 16-bit unsigned data type.
 + */
 +typedef unsigned int uint16;
 +/**
 + * The volatile 16-bit unsigned data type.
 + */
 +typedef volatile unsigned int vuint16;
 +/**
 + * The 32-bit signed data type.
 + */
 +typedef long int32;
 +/**
 + * The volatile 32-bit signed data type.
 + */
 +typedef volatile long vint32;
 +/**
 + * The 32-bit unsigned data type.
 + */
 +typedef unsigned long uint32;
 +/**
 + * The volatile 32-bit unsigned data type.
 + */
 +typedef volatile unsigned long vuint32;
 +
 +/* bsd */
 +typedef uint8			u_char;		/**< 8-bit value */
 +typedef uint16_t 			SOCKET;
 +typedef uint16			u_short;	/**< 16-bit value */
 +typedef uint16			u_int;		/**< 16-bit value */
 +typedef uint32			u_long;		/**< 32-bit value */
 +
 +extern SOCKET socket(uint8 protocol); // Opens a socket(TCP or UDP or IP_RAW mode)
 +extern void close(SOCKET s); // Close socket
 +extern uint8 connect(SOCKET s, uint8 * addr, uint16 port); // Establish TCP connection (Active connection)
 +extern void disconnect(SOCKET s); // disconnect the connection
 +extern uint8 listen(SOCKET s);	// Establish TCP connection (Passive connection)
 +extern uint16 send(SOCKET s, const uint8 * buf, uint16 len); // Send data (TCP)
 +extern uint16 recv(SOCKET s, uint8 * buf, uint16 len);	// Receive data (TCP)
 +extern uint16 sendto(SOCKET s, const uint8 * buf, uint16 len, uint8 * addr, uint16 port); // Send data (UDP/IP RAW)
 +extern uint16 recvfrom(SOCKET s, uint8 * buf, uint16 len, uint8 * addr, uint16  *port); // Receive data (UDP/IP RAW)
 +
 +extern uint16 igmpsend(SOCKET s, const uint8 * buf, uint16 len);
 +#endif
 +/* _SOCKET_H_ */
 diff --git a/libraries/WiFi/utility/spi_drv.cpp b/libraries/WiFi/utility/spi_drv.cpp new file mode 100644 index 0000000..12a320b --- /dev/null +++ b/libraries/WiFi/utility/spi_drv.cpp @@ -0,0 +1,506 @@ + +#include "Arduino.h" +#include "spi_drv.h"                    +#include "pins_arduino.h" +//#define _DEBUG_ +extern "C" { +#include "debug.h" +} + +#define DATAOUT 	11 // MOSI +#define DATAIN  	12 // MISO +#define SPICLOCK  	13 // sck +#define SLAVESELECT 10 // ss +#define SLAVEREADY 	7  // handshake pin +#define WIFILED 	9  // led on wifi shield + +#define DELAY_100NS do { asm volatile("nop"); }while(0); +#define DELAY_SPI(X) { int ii=0; do {  asm volatile("nop"); }while(++ii<X);} +#define DELAY_TRANSFER() DELAY_SPI(10) + +void SpiDrv::begin() +{ +	  // Set direction register for SCK and MOSI pin. +	  // MISO pin automatically overrides to INPUT. +	  // When the SS pin is set as OUTPUT, it can be used as +	  // a general purpose output port (it doesn't influence +	  // SPI operations). + +	  pinMode(SCK, OUTPUT); +	  pinMode(MOSI, OUTPUT); +	  pinMode(SS, OUTPUT); +	  pinMode(SLAVESELECT, OUTPUT); +	  pinMode(SLAVEREADY, INPUT); +	  pinMode(WIFILED, OUTPUT); + +	  digitalWrite(SCK, LOW); +	  digitalWrite(MOSI, LOW); +	  digitalWrite(SS, HIGH); +	  digitalWrite(SLAVESELECT, HIGH); +	  digitalWrite(WIFILED, LOW); + +#ifdef _DEBUG_ +	  INIT_TRIGGER() +#endif + +	  // Warning: if the SS pin ever becomes a LOW INPUT then SPI +	  // automatically switches to Slave, so the data direction of +	  // the SS pin MUST be kept as OUTPUT. +	  SPCR |= _BV(MSTR); +	  SPCR |= _BV(SPE); +	  //SPSR |= _BV(SPI2X); +} + +void SpiDrv::end() { +  SPCR &= ~_BV(SPE); +} + +void SpiDrv::spiSlaveSelect() +{ +    digitalWrite(SLAVESELECT,LOW); +} + + +void SpiDrv::spiSlaveDeselect() +{ +    digitalWrite(SLAVESELECT,HIGH); +} + +void delaySpi() +{ +	int i = 0; +	const int DELAY = 1000; +	for (;i<DELAY;++i) +	{ +		int a =a+1; +	} +} + +char SpiDrv::spiTransfer(volatile char data) +{ +    SPDR = data;                    // Start the transmission +    while (!(SPSR & (1<<SPIF)))     // Wait the end of the transmission +    { +    }; +    char result = SPDR; +    DELAY_TRANSFER(); + +    return result;                    // return the received byte +} + +int SpiDrv::waitSpiChar(unsigned char waitChar) +{ +    int timeout = TIMEOUT_CHAR; +    unsigned char _readChar = 0; +    do{ +        _readChar = readChar(); //get data byte +        if (_readChar == ERR_CMD) +        { +        	WARN("Err cmd received\n"); +        	return -1; +        } +    }while((timeout-- > 0) && (_readChar != waitChar)); +    return  (_readChar == waitChar); +} + +int SpiDrv::readAndCheckChar(char checkChar, char* readChar) +{ +    getParam((uint8_t*)readChar); + +    return  (*readChar == checkChar); +} + +char SpiDrv::readChar() +{ +	uint8_t readChar = 0; +	getParam(&readChar); +	return readChar; +} + +#define WAIT_START_CMD(x) waitSpiChar(START_CMD) + +#define IF_CHECK_START_CMD(x)                      \ +    if (!WAIT_START_CMD(_data))                 \ +    {                                           \ +        TOGGLE_TRIGGER()                        \ +        WARN("Error waiting START_CMD");        \ +        return 0;                               \ +    }else                                       \ + +#define CHECK_DATA(check, x)                   \ +        if (!readAndCheckChar(check, &x))   \ +        {                                               \ +        	TOGGLE_TRIGGER()                        \ +            WARN("Reply error");                        \ +            INFO2(check, (uint8_t)x);							\ +            return 0;                                   \ +        }else                                           \ + +#define waitSlaveReady() (digitalRead(SLAVEREADY) == LOW) +#define waitSlaveSign() (digitalRead(SLAVEREADY) == HIGH) +#define waitSlaveSignalH() while(digitalRead(SLAVEREADY) != HIGH){} +#define waitSlaveSignalL() while(digitalRead(SLAVEREADY) != LOW){} + +void SpiDrv::waitForSlaveSign() +{ +	while (!waitSlaveSign()); +} + +void SpiDrv::waitForSlaveReady() +{ +	while (!waitSlaveReady()); +} + +void SpiDrv::getParam(uint8_t* param) +{ +    // Get Params data +    *param = spiTransfer(DUMMY_DATA); +    DELAY_TRANSFER(); +} + +int SpiDrv::waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len) +{ +    char _data = 0; +    int ii = 0; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        CHECK_DATA(numParam, _data); +        { +            readParamLen8(param_len); +            for (ii=0; ii<(*param_len); ++ii) +            { +                // Get Params data +                //param[ii] = spiTransfer(DUMMY_DATA); +                getParam(¶m[ii]); +            }  +        }          + +        readAndCheckChar(END_CMD, &_data); +    }      +     +    return 1; +} +/* +int SpiDrv::waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len) +{ +    char _data = 0; +    int i =0, ii = 0; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        CHECK_DATA(numParam, _data); +        { +            readParamLen16(param_len); +            for (ii=0; ii<(*param_len); ++ii) +            { +                // Get Params data +                param[ii] = spiTransfer(DUMMY_DATA); +            }  +        }          + +        readAndCheckChar(END_CMD, &_data); +    }      +     +    return 1; +} +*/ + +int SpiDrv::waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len) +{ +    char _data = 0; +    uint16_t ii = 0; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        uint8_t numParam = readChar(); +        if (numParam != 0) +        {         +            readParamLen16(param_len); +            for (ii=0; ii<(*param_len); ++ii) +            { +                // Get Params data +                param[ii] = spiTransfer(DUMMY_DATA); +            }  +        }          + +        readAndCheckChar(END_CMD, &_data); +    }      +     +    return 1; +} + +int SpiDrv::waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len) +{ +    char _data = 0; +    int ii = 0; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        uint8_t numParam = readChar(); +        if (numParam != 0) +        {         +            readParamLen8(param_len); +            for (ii=0; ii<(*param_len); ++ii) +            { +                // Get Params data +                param[ii] = spiTransfer(DUMMY_DATA); +            }  +        }          + +        readAndCheckChar(END_CMD, &_data); +    }      +     +    return 1; +} + +int SpiDrv::waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params) +{ +    char _data = 0; +    int i =0, ii = 0; + + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        uint8_t _numParam = readChar(); +        if (_numParam != 0) +        {         +            for (i=0; i<_numParam; ++i) +            { +                params[i].paramLen = readParamLen8(); +                for (ii=0; ii<params[i].paramLen; ++ii) +                { +                    // Get Params data +                    params[i].param[ii] = spiTransfer(DUMMY_DATA); +                }  +            } +        } else +        { +            WARN("Error numParam == 0"); +            return 0; +        } + +        if (numParam != _numParam) +        { +            WARN("Mismatch numParam"); +            return 0; +        } + +        readAndCheckChar(END_CMD, &_data); +    }          +    return 1; +} + +/* +int SpiDrv::waitResponse(uint8_t cmd, tParam* params, uint8_t* numParamRead, uint8_t maxNumParams) +{ +    char _data = 0; +    int i =0, ii = 0; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        uint8_t numParam = readChar(); + +        if (numParam > maxNumParams) +        { +            numParam = maxNumParams; +        } +        *numParamRead = numParam; +        if (numParam != 0) +        { +            for (i=0; i<numParam; ++i) +            { +                params[i].paramLen = readParamLen8(); + +                for (ii=0; ii<params[i].paramLen; ++ii) +                { +                    // Get Params data +                    params[i].param[ii] = spiTransfer(DUMMY_DATA); +                }  +            } +        } else +        { +            WARN("Error numParams == 0"); +            Serial.println(cmd, 16); +            return 0; +        } +        readAndCheckChar(END_CMD, &_data); +    }          +    return 1; +} +*/ + +int SpiDrv::waitResponse(uint8_t cmd, uint8_t* numParamRead, uint8_t** params, uint8_t maxNumParams) +{ +    char _data = 0; +    int i =0, ii = 0; + +    char    *index[WL_SSID_MAX_LENGTH]; + +    for (i = 0 ; i < WL_NETWORKS_LIST_MAXNUM ; i++) +            index[i] = (char *)params + WL_SSID_MAX_LENGTH*i; + +    IF_CHECK_START_CMD(_data) +    { +        CHECK_DATA(cmd | REPLY_FLAG, _data){}; + +        uint8_t numParam = readChar(); + +        if (numParam > maxNumParams) +        { +            numParam = maxNumParams; +        } +        *numParamRead = numParam; +        if (numParam != 0) +        { +            for (i=0; i<numParam; ++i) +            { +            	uint8_t paramLen = readParamLen8(); +                for (ii=0; ii<paramLen; ++ii) +                { +                	//ssid[ii] = spiTransfer(DUMMY_DATA); +                    // Get Params data +                    index[i][ii] = (uint8_t)spiTransfer(DUMMY_DATA); + +                } +                index[i][ii]=0; +            } +        } else +        { +            WARN("Error numParams == 0"); +            readAndCheckChar(END_CMD, &_data); +            return 0; +        } +        readAndCheckChar(END_CMD, &_data); +    } +    return 1; +} + + +void SpiDrv::sendParam(uint8_t* param, uint8_t param_len, uint8_t lastParam) +{ +    int i = 0; +    // Send Spi paramLen +    sendParamLen8(param_len); + +    // Send Spi param data +    for (i=0; i<param_len; ++i) +    { +        spiTransfer(param[i]); +    } + +    // if lastParam==1 Send Spi END CMD +    if (lastParam == 1) +        spiTransfer(END_CMD); +} + +void SpiDrv::sendParamLen8(uint8_t param_len) +{ +    // Send Spi paramLen +    spiTransfer(param_len); +} + +void SpiDrv::sendParamLen16(uint16_t param_len) +{ +    // Send Spi paramLen +    spiTransfer((uint8_t)((param_len & 0xff00)>>8)); +    spiTransfer((uint8_t)(param_len & 0xff)); +} + +uint8_t SpiDrv::readParamLen8(uint8_t* param_len) +{ +    uint8_t _param_len = spiTransfer(DUMMY_DATA); +    if (param_len != NULL) +    { +        *param_len = _param_len; +    } +    return _param_len; +} + +uint16_t SpiDrv::readParamLen16(uint16_t* param_len) +{ +    uint16_t _param_len = spiTransfer(DUMMY_DATA)<<8 | (spiTransfer(DUMMY_DATA)& 0xff); +    if (param_len != NULL) +    { +        *param_len = _param_len; +    } +    return _param_len; +} + + +void SpiDrv::sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam) +{ +    uint16_t i = 0; + +    // Send Spi paramLen +    sendParamLen16(param_len); + +    // Send Spi param data +    for (i=0; i<param_len; ++i) +    { +        spiTransfer(param[i]); +    } + +    // if lastParam==1 Send Spi END CMD +    if (lastParam == 1) +        spiTransfer(END_CMD); +} + + +void SpiDrv::sendParam(uint16_t param, uint8_t lastParam) +{ +    // Send Spi paramLen +    sendParamLen8(2); + +    spiTransfer((uint8_t)((param & 0xff00)>>8)); +    spiTransfer((uint8_t)(param & 0xff)); + +    // if lastParam==1 Send Spi END CMD +    if (lastParam == 1) +        spiTransfer(END_CMD); +} + +/* Cmd Struct Message */ +/* _________________________________________________________________________________  */ +/*| START CMD | C/R  | CMD  |[TOT LEN]| N.PARAM | PARAM LEN | PARAM  | .. | END CMD | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ +/*|   8 bit   | 1bit | 7bit |  8bit   |  8bit   |   8bit    | nbytes | .. |   8bit  | */ +/*|___________|______|______|_________|_________|___________|________|____|_________| */ + +void SpiDrv::sendCmd(uint8_t cmd, uint8_t numParam) +{ +    // Send Spi START CMD +    spiTransfer(START_CMD); + +    //waitForSlaveSign(); +    //wait the interrupt trigger on slave +    delayMicroseconds(SPI_START_CMD_DELAY); + +    // Send Spi C + cmd +    spiTransfer(cmd & ~(REPLY_FLAG)); + +    // Send Spi totLen +    //spiTransfer(totLen); + +    // Send Spi numParam +    spiTransfer(numParam); + +    // If numParam == 0 send END CMD +    if (numParam == 0) +        spiTransfer(END_CMD); + +} + +SpiDrv spiDrv; diff --git a/libraries/WiFi/utility/spi_drv.h b/libraries/WiFi/utility/spi_drv.h new file mode 100644 index 0000000..5c2e706 --- /dev/null +++ b/libraries/WiFi/utility/spi_drv.h @@ -0,0 +1,83 @@ +#ifndef SPI_Drv_h
 +#define SPI_Drv_h
 +
 +#include <inttypes.h>
 +#include "wifi_spi.h"
 +
 +#define SPI_START_CMD_DELAY 	12
 +
 +#define NO_LAST_PARAM   0
 +#define LAST_PARAM      1
 +
 +#define DUMMY_DATA  0xFF
 +
 +#define WAIT_FOR_SLAVE_SELECT()	 \
 +	SpiDrv::waitForSlaveReady(); \
 +	SpiDrv::spiSlaveSelect();
 +
 +
 +
 +class SpiDrv
 +{
 +private:
 +	//static bool waitSlaveReady();
 +	static void waitForSlaveSign();
 +	static void getParam(uint8_t* param);
 +public:
 +
 +    static void begin();
 +
 +    static void end();
 +    
 +    static void spiDriverInit();
 +        
 +    static void spiSlaveSelect();
 +    
 +    static void spiSlaveDeselect();
 +    
 +    static char spiTransfer(volatile char data);
 +
 +    static void waitForSlaveReady();
 +
 +    //static int waitSpiChar(char waitChar, char* readChar);
 +
 +    static int waitSpiChar(unsigned char waitChar);
 +    
 +    static int readAndCheckChar(char checkChar, char* readChar);
 +
 +    static char readChar();
 +
 +    static int waitResponseParams(uint8_t cmd, uint8_t numParam, tParam* params);
 +    
 +    static int waitResponseCmd(uint8_t cmd, uint8_t numParam, uint8_t* param, uint8_t* param_len);
 +
 +    static int waitResponseData8(uint8_t cmd, uint8_t* param, uint8_t* param_len);
 +     
 +    static int waitResponseData16(uint8_t cmd, uint8_t* param, uint16_t* param_len);
 + /*
 +    static int waitResponse(uint8_t cmd, tParam* params, uint8_t* numParamRead, uint8_t maxNumParams);
 +    
 +    static int waitResponse(uint8_t cmd, uint8_t numParam, uint8_t* param, uint16_t* param_len);
 +*/
 +    static int waitResponse(uint8_t cmd, uint8_t* numParamRead, uint8_t** params, uint8_t maxNumParams);
 +
 +    static void sendParam(uint8_t* param, uint8_t param_len, uint8_t lastParam = NO_LAST_PARAM);
 +
 +    static void sendParamLen8(uint8_t param_len);
 +
 +    static void sendParamLen16(uint16_t param_len);
 +
 +    static uint8_t readParamLen8(uint8_t* param_len = NULL);
 +
 +    static uint16_t readParamLen16(uint16_t* param_len = NULL);
 +
 +    static void sendBuffer(uint8_t* param, uint16_t param_len, uint8_t lastParam = NO_LAST_PARAM);
 +
 +    static void sendParam(uint16_t param, uint8_t lastParam = NO_LAST_PARAM);
 +    
 +    static void sendCmd(uint8_t cmd, uint8_t numParam);
 +};                                                                 
 +
 +extern SpiDrv spiDrv;
 +
 +#endif
 diff --git a/libraries/WiFi/utility/wifi_drv.cpp b/libraries/WiFi/utility/wifi_drv.cpp new file mode 100644 index 0000000..1ca1696 --- /dev/null +++ b/libraries/WiFi/utility/wifi_drv.cpp @@ -0,0 +1,491 @@ +#include <stdio.h>
 +#include <string.h>
 +#include <stdint.h>
 +
 +#include "Arduino.h"
 +#include "spi_drv.h"
 +#include "wifi_drv.h"
 +
 +#define _DEBUG_
 +
 +extern "C" {
 +#include "wifi_spi.h"
 +#include "wl_types.h"
 +#include "debug.h"
 +}
 +
 +// Array of data to cache the information related to the networks discovered
 +char 	WiFiDrv::_networkSsid[][WL_SSID_MAX_LENGTH] = {{"1"},{"2"},{"3"},{"4"},{"5"}};
 +int32_t WiFiDrv::_networkRssi[WL_NETWORKS_LIST_MAXNUM] = { 0 };
 +uint8_t WiFiDrv::_networkEncr[WL_NETWORKS_LIST_MAXNUM] = { 0 };
 +
 +// Cached values of retrieved data
 +char 	WiFiDrv::_ssid[] = {0};
 +uint8_t	WiFiDrv::_bssid[] = {0};
 +uint8_t WiFiDrv::_mac[] = {0};
 +uint8_t WiFiDrv::_localIp[] = {0};
 +uint8_t WiFiDrv::_subnetMask[] = {0};
 +uint8_t WiFiDrv::_gatewayIp[] = {0};
 +// Firmware version
 +char    WiFiDrv::fwVersion[] = {0};
 +
 +
 +// Private Methods
 +
 +void WiFiDrv::getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip)
 +{
 +    tParam params[PARAM_NUMS_3] = { {0, (char*)ip}, {0, (char*)mask}, {0, (char*)gwip}};
 +
 +    WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_IPADDR_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, sizeof(_dummy), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    SpiDrv::waitResponseParams(GET_IPADDR_CMD, PARAM_NUMS_3, params);
 +
 +    SpiDrv::spiSlaveDeselect();
 +}
 +
 +// Public Methods
 +
 +
 +void WiFiDrv::wifiDriverInit()
 +{
 +    SpiDrv::begin();
 +}
 +
 +int8_t WiFiDrv::wifiSetNetwork(char* ssid, uint8_t ssid_len)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(SET_NET_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam((uint8_t*)ssid, ssid_len, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(SET_NET_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +        _data = WL_FAILURE;
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return(_data == WIFI_SPI_ACK) ? WL_SUCCESS : WL_FAILURE;
 +}
 +
 +int8_t WiFiDrv::wifiSetPassphrase(char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_2);
 +    SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM);
 +    SpiDrv::sendParam((uint8_t*)passphrase, len, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(SET_PASSPHRASE_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +        _data = WL_FAILURE;
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    return _data;
 +}
 +
 +
 +int8_t WiFiDrv::wifiSetKey(char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(SET_KEY_CMD, PARAM_NUMS_3);
 +    SpiDrv::sendParam((uint8_t*)ssid, ssid_len, NO_LAST_PARAM);
 +    SpiDrv::sendParam(&key_idx, KEY_IDX_LEN, NO_LAST_PARAM);
 +    SpiDrv::sendParam((uint8_t*)key, len, LAST_PARAM);
 +    
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(SET_KEY_CMD, PARAM_NUMS_1, &_data, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +        _data = WL_FAILURE;
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    return _data;
 +}
 +                        
 +int8_t WiFiDrv::disconnect()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(DISCONNECT_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    int8_t result = SpiDrv::waitResponseCmd(DISCONNECT_CMD, PARAM_NUMS_1, &_data, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return result;
 +}
 +
 +uint8_t WiFiDrv::getConnectionStatus()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_0);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = -1;
 +    uint8_t _dataLen = 0;
 +    SpiDrv::waitResponseCmd(GET_CONN_STATUS_CMD, PARAM_NUMS_1, &_data, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return _data;
 +}
 +
 +uint8_t* WiFiDrv::getMacAddress()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_MACADDR_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    SpiDrv::waitResponseCmd(GET_MACADDR_CMD, PARAM_NUMS_1, _mac, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return _mac;
 +}
 +
 +void WiFiDrv::getIpAddress(IPAddress& ip)
 +{
 +	getNetworkData(_localIp, _subnetMask, _gatewayIp);
 +	ip = _localIp;
 +}
 +
 + void WiFiDrv::getSubnetMask(IPAddress& mask)
 + {
 +	getNetworkData(_localIp, _subnetMask, _gatewayIp);
 +	mask = _subnetMask;
 + }
 +
 + void WiFiDrv::getGatewayIP(IPAddress& ip)
 + {
 +	getNetworkData(_localIp, _subnetMask, _gatewayIp);
 +	ip = _gatewayIp;
 + }
 +
 +char* WiFiDrv::getCurrentSSID()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    SpiDrv::waitResponseCmd(GET_CURR_SSID_CMD, PARAM_NUMS_1, (uint8_t*)_ssid, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return _ssid;
 +}
 +
 +uint8_t* WiFiDrv::getCurrentBSSID()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    SpiDrv::waitResponseCmd(GET_CURR_BSSID_CMD, PARAM_NUMS_1, _bssid, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return _bssid;
 +}
 +
 +int32_t WiFiDrv::getCurrentRSSI()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    int32_t rssi = 0;
 +    SpiDrv::waitResponseCmd(GET_CURR_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&rssi, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return rssi;
 +}
 +
 +uint8_t WiFiDrv::getCurrentEncryptionType()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1);
 +
 +    uint8_t _dummy = DUMMY_DATA;
 +    SpiDrv::sendParam(&_dummy, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t dataLen = 0;
 +    uint8_t encType = 0;
 +    SpiDrv::waitResponseCmd(GET_CURR_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return encType;
 +}
 +
 +int8_t WiFiDrv::startScanNetworks()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(START_SCAN_NETWORKS, PARAM_NUMS_0);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +
 +    if (!SpiDrv::waitResponseCmd(START_SCAN_NETWORKS, PARAM_NUMS_1, &_data, &_dataLen))
 +     {
 +         WARN("error waitResponse");
 +         _data = WL_FAILURE;
 +     }
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return (_data == WL_FAILURE)? _data : WL_SUCCESS;
 +}
 +
 +
 +uint8_t WiFiDrv::getScanNetworks()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(SCAN_NETWORKS, PARAM_NUMS_0);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t ssidListNum = 0;
 +    SpiDrv::waitResponse(SCAN_NETWORKS, &ssidListNum, (uint8_t**)_networkSsid, WL_NETWORKS_LIST_MAXNUM);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return ssidListNum;
 +}
 +
 +char* WiFiDrv::getSSIDNetoworks(uint8_t networkItem)
 +{
 +	if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
 +		return NULL;
 +
 +	return _networkSsid[networkItem];
 +}
 +
 +uint8_t WiFiDrv::getEncTypeNetowrks(uint8_t networkItem)
 +{
 +	if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
 +		return NULL;
 +
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1);
 +
 +    SpiDrv::sendParam(&networkItem, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t dataLen = 0;
 +    uint8_t encType = 0;
 +    SpiDrv::waitResponseCmd(GET_IDX_ENCT_CMD, PARAM_NUMS_1, (uint8_t*)&encType, &dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return encType;
 +}
 +
 +int32_t WiFiDrv::getRSSINetoworks(uint8_t networkItem)
 +{
 +	if (networkItem >= WL_NETWORKS_LIST_MAXNUM)
 +		return NULL;
 +	int32_t	networkRssi = 0;
 +
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1);
 +
 +    SpiDrv::sendParam(&networkItem, 1, LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t dataLen = 0;
 +    SpiDrv::waitResponseCmd(GET_IDX_RSSI_CMD, PARAM_NUMS_1, (uint8_t*)&networkRssi, &dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +	return networkRssi;
 +}
 +
 +uint8_t WiFiDrv::reqHostByName(const char* aHostname)
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +
 +    // Send Command
 +    SpiDrv::sendCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1);
 +    SpiDrv::sendParam((uint8_t*)aHostname, strlen(aHostname), LAST_PARAM);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _data = 0;
 +    uint8_t _dataLen = 0;
 +    uint8_t result = SpiDrv::waitResponseCmd(REQ_HOST_BY_NAME_CMD, PARAM_NUMS_1, &_data, &_dataLen);
 +
 +    SpiDrv::spiSlaveDeselect();
 +
 +    return result;
 +}
 +
 +int WiFiDrv::getHostByName(IPAddress& aResult)
 +{
 +	uint8_t  _ipAddr[WL_IPV4_LENGTH];
 +	IPAddress dummy(0xFF,0xFF,0xFF,0xFF);
 +	int result = 0;
 +
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_0);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(GET_HOST_BY_NAME_CMD, PARAM_NUMS_1, _ipAddr, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }else{
 +    	aResult = _ipAddr;
 +    	result = (aResult != dummy);
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    return result;
 +}
 +
 +int WiFiDrv::getHostByName(const char* aHostname, IPAddress& aResult)
 +{
 +	uint8_t retry = 10;
 +	if (reqHostByName(aHostname))
 +	{
 +		while(!getHostByName(aResult) && --retry > 0)
 +		{
 +			delay(1000);
 +		}
 +	}else{
 +		return 0;
 +	}
 +	return (retry>0);
 +}
 +
 +char*  WiFiDrv::getFwVersion()
 +{
 +	WAIT_FOR_SLAVE_SELECT();
 +    // Send Command
 +    SpiDrv::sendCmd(GET_FW_VERSION_CMD, PARAM_NUMS_0);
 +
 +    //Wait the reply elaboration
 +    SpiDrv::waitForSlaveReady();
 +
 +    // Wait for reply
 +    uint8_t _dataLen = 0;
 +    if (!SpiDrv::waitResponseCmd(GET_FW_VERSION_CMD, PARAM_NUMS_1, (uint8_t*)fwVersion, &_dataLen))
 +    {
 +        WARN("error waitResponse");
 +    }
 +    SpiDrv::spiSlaveDeselect();
 +    return fwVersion;
 +}
 +
 +WiFiDrv wiFiDrv;
 diff --git a/libraries/WiFi/utility/wifi_drv.h b/libraries/WiFi/utility/wifi_drv.h new file mode 100644 index 0000000..c4f04db --- /dev/null +++ b/libraries/WiFi/utility/wifi_drv.h @@ -0,0 +1,219 @@ +#ifndef WiFi_Drv_h
 +#define WiFi_Drv_h
 +
 +#include <inttypes.h>
 +#include "wifi_spi.h"
 +#include "IPAddress.h"
 +
 +// Key index length
 +#define KEY_IDX_LEN     1
 +// 5 secs of delay to have the connection established
 +#define WL_DELAY_START_CONNECTION 5000
 +// firmware version string length
 +#define WL_FW_VER_LENGTH 6
 +
 +class WiFiDrv
 +{
 +private:
 +	// settings of requested network
 +	static char 	_networkSsid[WL_NETWORKS_LIST_MAXNUM][WL_SSID_MAX_LENGTH];
 +	static int32_t 	_networkRssi[WL_NETWORKS_LIST_MAXNUM];
 +	static uint8_t 	_networkEncr[WL_NETWORKS_LIST_MAXNUM];
 +
 +	// firmware version string in the format a.b.c
 +	static char 	fwVersion[WL_FW_VER_LENGTH];
 +
 +	// settings of current selected network
 +	static char 	_ssid[WL_SSID_MAX_LENGTH];
 +	static uint8_t 	_bssid[WL_MAC_ADDR_LENGTH];
 +	static uint8_t 	_mac[WL_MAC_ADDR_LENGTH];
 +	static uint8_t  _localIp[WL_IPV4_LENGTH];
 +	static uint8_t  _subnetMask[WL_IPV4_LENGTH];
 +	static uint8_t  _gatewayIp[WL_IPV4_LENGTH];
 +
 +	/*
 +	 * Get network Data information
 +	 */
 +    static void getNetworkData(uint8_t *ip, uint8_t *mask, uint8_t *gwip);
 +
 +    static uint8_t reqHostByName(const char* aHostname);
 +
 +    static int getHostByName(IPAddress& aResult);
 +
 +public:
 +
 +    /*
 +     * Driver initialization
 +     */
 +    static void wifiDriverInit();
 +
 +    /*
 +     * Set the desired network which the connection manager should try to
 +     * connect to.
 +     *
 +     * The ssid of the desired network should be specified.
 +     *
 +     * param ssid: The ssid of the desired network.
 +     * param ssid_len: Lenght of ssid string.
 +     * return: WL_SUCCESS or WL_FAILURE
 +	 */
 +    static int8_t wifiSetNetwork(char* ssid, uint8_t ssid_len);
 +
 +    /* Start Wifi connection with passphrase
 +     * the most secure supported mode will be automatically selected
 +     *
 +     * param ssid: Pointer to the SSID string.
 +     * param ssid_len: Lenght of ssid string.
 +     * param passphrase: Passphrase. Valid characters in a passphrase
 +     *        must be between ASCII 32-126 (decimal).
 +     * param len: Lenght of passphrase string.
 +     * return: WL_SUCCESS or WL_FAILURE
 +     */
 +    static int8_t wifiSetPassphrase(char* ssid, uint8_t ssid_len, const char *passphrase, const uint8_t len);
 +
 +    /* Start Wifi connection with WEP encryption.
 +     * Configure a key into the device. The key type (WEP-40, WEP-104)
 +     * is determined by the size of the key (5 bytes for WEP-40, 13 bytes for WEP-104).
 +     *
 +     * param ssid: Pointer to the SSID string.
 +     * param ssid_len: Lenght of ssid string.
 +     * param key_idx: The key index to set. Valid values are 0-3.
 +     * param key: Key input buffer.
 +     * param len: Lenght of key string.
 +     * return: WL_SUCCESS or WL_FAILURE
 +     */
 +    static int8_t wifiSetKey(char* ssid, uint8_t ssid_len, uint8_t key_idx, const void *key, const uint8_t len);
 +
 +    /*
 +     * Disconnect from the network
 +     *
 +     * return: WL_SUCCESS or WL_FAILURE
 +     */
 +    static int8_t disconnect();
 +
 +    /*
 +     * Disconnect from the network
 +     *
 +     * return: one value of wl_status_t enum
 +     */
 +    static uint8_t getConnectionStatus();
 +
 +    /*
 +     * Get the interface MAC address.
 +     *
 +     * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
 +     */
 +    static uint8_t* getMacAddress();
 +
 +    /*
 +     * Get the interface IP address.
 +     *
 +     * return: copy the ip address value in IPAddress object
 +     */
 +    static void getIpAddress(IPAddress& ip);
 +
 +    /*
 +     * Get the interface subnet mask address.
 +     *
 +     * return: copy the subnet mask address value in IPAddress object
 +     */
 +    static void getSubnetMask(IPAddress& mask);
 +
 +    /*
 +     * Get the gateway ip address.
 +     *
 +     * return: copy the gateway ip address value in IPAddress object
 +     */
 +    static void getGatewayIP(IPAddress& ip);
 +
 +    /*
 +     * Return the current SSID associated with the network
 +     *
 +     * return: ssid string
 +     */
 +    static char* getCurrentSSID();
 +
 +    /*
 +     * Return the current BSSID associated with the network.
 +     * It is the MAC address of the Access Point
 +     *
 +     * return: pointer to uint8_t array with length WL_MAC_ADDR_LENGTH
 +     */
 +    static uint8_t* getCurrentBSSID();
 +
 +    /*
 +     * Return the current RSSI /Received Signal Strength in dBm)
 +     * associated with the network
 +     *
 +     * return: signed value
 +     */
 +    static int32_t getCurrentRSSI();
 +
 +    /*
 +     * Return the Encryption Type associated with the network
 +     *
 +     * return: one value of wl_enc_type enum
 +     */
 +    static uint8_t getCurrentEncryptionType();
 +
 +    /*
 +     * Start scan WiFi networks available
 +     *
 +     * return: Number of discovered networks
 +     */
 +    static int8_t startScanNetworks();
 +
 +    /*
 +     * Get the networks available
 +     *
 +     * return: Number of discovered networks
 +     */
 +    static uint8_t getScanNetworks();
 +
 +    /*
 +     * Return the SSID discovered during the network scan.
 +     *
 +     * param networkItem: specify from which network item want to get the information
 +	 *
 +     * return: ssid string of the specified item on the networks scanned list
 +     */
 +    static char* getSSIDNetoworks(uint8_t networkItem);
 +
 +    /*
 +     * Return the RSSI of the networks discovered during the scanNetworks
 +     *
 +     * param networkItem: specify from which network item want to get the information
 +	 *
 +     * return: signed value of RSSI of the specified item on the networks scanned list
 +     */
 +    static int32_t getRSSINetoworks(uint8_t networkItem);
 +
 +    /*
 +     * Return the encryption type of the networks discovered during the scanNetworks
 +     *
 +     * param networkItem: specify from which network item want to get the information
 +	 *
 +     * return: encryption type (enum wl_enc_type) of the specified item on the networks scanned list
 +     */
 +    static uint8_t getEncTypeNetowrks(uint8_t networkItem);
 +
 +    /*
 +     * Resolve the given hostname to an IP address.
 +     * param aHostname: Name to be resolved
 +     * param aResult: IPAddress structure to store the returned IP address
 +     * result: 1 if aIPAddrString was successfully converted to an IP address,
 +     *          else error code
 +     */
 +    static int getHostByName(const char* aHostname, IPAddress& aResult);
 +
 +    /*
 +     * Get the firmware version
 +     * result: version as string with this format a.b.c
 +     */
 +    static char* getFwVersion();
 +
 +};
 +
 +extern WiFiDrv wiFiDrv;
 +
 +#endif
 diff --git a/libraries/WiFi/utility/wifi_spi.h b/libraries/WiFi/utility/wifi_spi.h new file mode 100644 index 0000000..bf479e2 --- /dev/null +++ b/libraries/WiFi/utility/wifi_spi.h @@ -0,0 +1,144 @@ +#ifndef WiFi_Spi_h
 +#define WiFi_Spi_h
 +
 +#include "wl_definitions.h"
 +
 +#define CMD_FLAG        0
 +#define REPLY_FLAG      1<<7
 +#define DATA_FLAG 		0x40
 +
 +#define WIFI_SPI_ACK        1
 +#define WIFI_SPI_ERR        0xFF
 +
 +#define TIMEOUT_CHAR    1000
 +
 +//#define	MAX_SOCK_NUM		4	/**< Maxmium number of socket  */
 +#define NO_SOCKET_AVAIL     255
 +
 +#define START_CMD   0xE0
 +#define END_CMD     0xEE
 +#define ERR_CMD   	0xEF
 +  
 +enum {
 +	SET_NET_CMD 		= 0x10,
 +	SET_PASSPHRASE_CMD	= 0x11,
 +	SET_KEY_CMD	        = 0x12,
 +	TEST_CMD	        = 0x13,
 +
 +	GET_CONN_STATUS_CMD	= 0x20,
 +	GET_IPADDR_CMD		= 0x21,
 +	GET_MACADDR_CMD		= 0x22,
 +	GET_CURR_SSID_CMD	= 0x23,
 +	GET_CURR_BSSID_CMD	= 0x24,
 +	GET_CURR_RSSI_CMD	= 0x25,
 +	GET_CURR_ENCT_CMD	= 0x26,
 +	SCAN_NETWORKS		= 0x27,
 +	START_SERVER_TCP_CMD= 0x28,
 +	GET_STATE_TCP_CMD   = 0x29,
 +	DATA_SENT_TCP_CMD	= 0x2A,
 +    AVAIL_DATA_TCP_CMD	= 0x2B,
 +    GET_DATA_TCP_CMD	= 0x2C,
 +    START_CLIENT_TCP_CMD= 0x2D,
 +    STOP_CLIENT_TCP_CMD = 0x2E,
 +    GET_CLIENT_STATE_TCP_CMD= 0x2F,
 +    DISCONNECT_CMD		= 0x30,
 +	GET_IDX_SSID_CMD	= 0x31,
 +	GET_IDX_RSSI_CMD	= 0x32,
 +	GET_IDX_ENCT_CMD	= 0x33,
 +	REQ_HOST_BY_NAME_CMD= 0x34,
 +	GET_HOST_BY_NAME_CMD= 0x35,
 +	START_SCAN_NETWORKS	= 0x36,
 +	GET_FW_VERSION_CMD	= 0x37,
 +
 +    // All command with DATA_FLAG 0x40 send a 16bit Len
 +
 +	SEND_DATA_TCP_CMD		= 0x44,
 +    GET_DATABUF_TCP_CMD		= 0x45,
 +};
 +
 +
 +enum wl_tcp_state {
 +  CLOSED      = 0,
 +  LISTEN      = 1,
 +  SYN_SENT    = 2,
 +  SYN_RCVD    = 3,
 +  ESTABLISHED = 4,
 +  FIN_WAIT_1  = 5,
 +  FIN_WAIT_2  = 6,
 +  CLOSE_WAIT  = 7,
 +  CLOSING     = 8,
 +  LAST_ACK    = 9,
 +  TIME_WAIT   = 10
 +};
 +
 +
 +enum numParams{
 +    PARAM_NUMS_0,
 +    PARAM_NUMS_1,
 +    PARAM_NUMS_2,
 +    PARAM_NUMS_3,
 +    PARAM_NUMS_4,
 +    PARAM_NUMS_5,
 +    MAX_PARAM_NUMS
 +};
 +
 +#define MAX_PARAMS MAX_PARAM_NUMS-1
 +#define PARAM_LEN_SIZE 1
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	uint8_t     paramLen;
 +	char*	    param;
 +}tParam;
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	uint16_t     dataLen;
 +	char*	     data;
 +}tDataParam;
 +
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	unsigned char	cmd;
 +	unsigned char	tcmd;
 +	unsigned char	nParam;
 +	tParam	params[MAX_PARAMS];
 +}tSpiMsg;
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	unsigned char	cmd;
 +	unsigned char	tcmd;
 +	unsigned char	nParam;
 +	tDataParam		params[MAX_PARAMS];
 +}tSpiMsgData;
 +
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	unsigned char	cmd;
 +	unsigned char	tcmd;
 +	//unsigned char	totLen;
 +	unsigned char	nParam;
 +}tSpiHdr;
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	uint8_t     paramLen;
 +	uint32_t	param;
 +}tLongParam;
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	uint8_t     paramLen;
 +	uint16_t	param;
 +}tIntParam;
 +
 +typedef struct  __attribute__((__packed__))
 +{
 +	uint8_t     paramLen;
 +	uint8_t	param;
 +}tByteParam;
 +
 +#endif
 diff --git a/libraries/WiFi/utility/wl_definitions.h b/libraries/WiFi/utility/wl_definitions.h new file mode 100644 index 0000000..15de781 --- /dev/null +++ b/libraries/WiFi/utility/wl_definitions.h @@ -0,0 +1,50 @@ +/* + * wl_definitions.h + * + *  Created on: Mar 6, 2011 + *      Author: dlafauci + */ + +#ifndef WL_DEFINITIONS_H_ +#define WL_DEFINITIONS_H_ + +// Maximum size of a SSID +#define WL_SSID_MAX_LENGTH 32 +// Length of passphrase. Valid lengths are 8-63. +#define WL_WPA_KEY_MAX_LENGTH 63 +// Length of key in bytes. Valid values are 5 and 13. +#define WL_WEP_KEY_MAX_LENGTH 13 +// Size of a MAC-address or BSSID +#define WL_MAC_ADDR_LENGTH 6 +// Size of a MAC-address or BSSID +#define WL_IPV4_LENGTH 4 +// Maximum size of a SSID list +#define WL_NETWORKS_LIST_MAXNUM	10 +// Maxmium number of socket +#define	MAX_SOCK_NUM		4 +//Maximum number of attempts to establish wifi connection +#define WL_MAX_ATTEMPT_CONNECTION	10 + +typedef enum { +		WL_NO_SHIELD = 255, +        WL_IDLE_STATUS = 0, +        WL_NO_SSID_AVAIL, +        WL_SCAN_COMPLETED, +        WL_CONNECTED, +        WL_CONNECT_FAILED, +        WL_CONNECTION_LOST, +        WL_DISCONNECTED +} wl_status_t; + +/* Encryption modes */ +enum wl_enc_type {  /* Values map to 802.11 encryption suites... */ +        ENC_TYPE_WEP  = 5, +        ENC_TYPE_TKIP = 2, +        ENC_TYPE_CCMP = 4, +        /* ... except these two, 7 and 8 are reserved in 802.11-2007 */ +        ENC_TYPE_NONE = 7, +        ENC_TYPE_AUTO = 8 +}; + + +#endif /* WL_DEFINITIONS_H_ */ diff --git a/libraries/WiFi/utility/wl_types.h b/libraries/WiFi/utility/wl_types.h new file mode 100644 index 0000000..82b309d --- /dev/null +++ b/libraries/WiFi/utility/wl_types.h @@ -0,0 +1,31 @@ +/*
 + * wl_types.h
 + *
 + *  Created on: Jul 30, 2010
 + *      Author: dlafauci
 + */
 +
 +
 +#ifndef	_WL_TYPES_H_
 +#define	_WL_TYPES_H_
 +
 +#include <inttypes.h>
 +
 +typedef enum {
 +        WL_FAILURE = -1,
 +        WL_SUCCESS = 1,
 +} wl_error_code_t;
 +
 +/* Authentication modes */
 +enum wl_auth_mode {
 +        AUTH_MODE_INVALID,
 +        AUTH_MODE_AUTO,
 +        AUTH_MODE_OPEN_SYSTEM,
 +        AUTH_MODE_SHARED_KEY,
 +        AUTH_MODE_WPA,
 +        AUTH_MODE_WPA2,
 +        AUTH_MODE_WPA_PSK,
 +        AUTH_MODE_WPA2_PSK
 +};
 +
 +#endif //_WL_TYPES_H_
 diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp new file mode 100644 index 0000000..4e7a17c --- /dev/null +++ b/libraries/Wire/Wire.cpp @@ -0,0 +1,298 @@ +/* +  TwoWire.cpp - TWI/I2C library for Wiring & Arduino +  Copyright (c) 2006 Nicholas Zambetti.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +  +  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ + +extern "C" { +  #include <stdlib.h> +  #include <string.h> +  #include <inttypes.h> +  #include "twi.h" +} + +#include "Wire.h" + +// Initialize Class Variables ////////////////////////////////////////////////// + +uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::rxBufferIndex = 0; +uint8_t TwoWire::rxBufferLength = 0; + +uint8_t TwoWire::txAddress = 0; +uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::txBufferIndex = 0; +uint8_t TwoWire::txBufferLength = 0; + +uint8_t TwoWire::transmitting = 0; +void (*TwoWire::user_onRequest)(void); +void (*TwoWire::user_onReceive)(int); + +// Constructors //////////////////////////////////////////////////////////////// + +TwoWire::TwoWire() +{ +} + +// Public Methods ////////////////////////////////////////////////////////////// + +void TwoWire::begin(void) +{ +  rxBufferIndex = 0; +  rxBufferLength = 0; + +  txBufferIndex = 0; +  txBufferLength = 0; + +  twi_init(); +} + +void TwoWire::begin(uint8_t address) +{ +  twi_setAddress(address); +  twi_attachSlaveTxEvent(onRequestService); +  twi_attachSlaveRxEvent(onReceiveService); +  begin(); +} + +void TwoWire::begin(int address) +{ +  begin((uint8_t)address); +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) +{ +  // clamp to buffer length +  if(quantity > BUFFER_LENGTH){ +    quantity = BUFFER_LENGTH; +  } +  // perform blocking read into buffer +  uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); +  // set rx buffer iterator vars +  rxBufferIndex = 0; +  rxBufferLength = read; + +  return read; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) +{ +  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity) +{ +  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)true); +} + +uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) +{ +  return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)sendStop); +} + +void TwoWire::beginTransmission(uint8_t address) +{ +  // indicate that we are transmitting +  transmitting = 1; +  // set address of targeted slave +  txAddress = address; +  // reset tx buffer iterator vars +  txBufferIndex = 0; +  txBufferLength = 0; +} + +void TwoWire::beginTransmission(int address) +{ +  beginTransmission((uint8_t)address); +} + +// +//	Originally, 'endTransmission' was an f(void) function. +//	It has been modified to take one parameter indicating +//	whether or not a STOP should be performed on the bus. +//	Calling endTransmission(false) allows a sketch to  +//	perform a repeated start.  +// +//	WARNING: Nothing in the library keeps track of whether +//	the bus tenure has been properly ended with a STOP. It +//	is very possible to leave the bus in a hung state if +//	no call to endTransmission(true) is made. Some I2C +//	devices will behave oddly if they do not see a STOP. +// +uint8_t TwoWire::endTransmission(uint8_t sendStop) +{ +  // transmit buffer (blocking) +  int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop); +  // reset tx buffer iterator vars +  txBufferIndex = 0; +  txBufferLength = 0; +  // indicate that we are done transmitting +  transmitting = 0; +  return ret; +} + +//	This provides backwards compatibility with the original +//	definition, and expected behaviour, of endTransmission +// +uint8_t TwoWire::endTransmission(void) +{ +  return endTransmission(true); +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TwoWire::write(uint8_t data) +{ +  if(transmitting){ +  // in master transmitter mode +    // don't bother if buffer is full +    if(txBufferLength >= BUFFER_LENGTH){ +      setWriteError(); +      return 0; +    } +    // put byte in tx buffer +    txBuffer[txBufferIndex] = data; +    ++txBufferIndex; +    // update amount in buffer    +    txBufferLength = txBufferIndex; +  }else{ +  // in slave send mode +    // reply to master +    twi_transmit(&data, 1); +  } +  return 1; +} + +// must be called in: +// slave tx event callback +// or after beginTransmission(address) +size_t TwoWire::write(const uint8_t *data, size_t quantity) +{ +  if(transmitting){ +  // in master transmitter mode +    for(size_t i = 0; i < quantity; ++i){ +      write(data[i]); +    } +  }else{ +  // in slave send mode +    // reply to master +    twi_transmit(data, quantity); +  } +  return quantity; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::available(void) +{ +  return rxBufferLength - rxBufferIndex; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::read(void) +{ +  int value = -1; +   +  // get each successive byte on each call +  if(rxBufferIndex < rxBufferLength){ +    value = rxBuffer[rxBufferIndex]; +    ++rxBufferIndex; +  } + +  return value; +} + +// must be called in: +// slave rx event callback +// or after requestFrom(address, numBytes) +int TwoWire::peek(void) +{ +  int value = -1; +   +  if(rxBufferIndex < rxBufferLength){ +    value = rxBuffer[rxBufferIndex]; +  } + +  return value; +} + +void TwoWire::flush(void) +{ +  // XXX: to be implemented. +} + +// behind the scenes function that is called when data is received +void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) +{ +  // don't bother if user hasn't registered a callback +  if(!user_onReceive){ +    return; +  } +  // don't bother if rx buffer is in use by a master requestFrom() op +  // i know this drops data, but it allows for slight stupidity +  // meaning, they may not have read all the master requestFrom() data yet +  if(rxBufferIndex < rxBufferLength){ +    return; +  } +  // copy twi rx buffer into local read buffer +  // this enables new reads to happen in parallel +  for(uint8_t i = 0; i < numBytes; ++i){ +    rxBuffer[i] = inBytes[i];     +  } +  // set rx iterator vars +  rxBufferIndex = 0; +  rxBufferLength = numBytes; +  // alert user program +  user_onReceive(numBytes); +} + +// behind the scenes function that is called when data is requested +void TwoWire::onRequestService(void) +{ +  // don't bother if user hasn't registered a callback +  if(!user_onRequest){ +    return; +  } +  // reset tx buffer iterator vars +  // !!! this will kill any pending pre-master sendTo() activity +  txBufferIndex = 0; +  txBufferLength = 0; +  // alert user program +  user_onRequest(); +} + +// sets function called on slave write +void TwoWire::onReceive( void (*function)(int) ) +{ +  user_onReceive = function; +} + +// sets function called on slave read +void TwoWire::onRequest( void (*function)(void) ) +{ +  user_onRequest = function; +} + +// Preinstantiate Objects ////////////////////////////////////////////////////// + +TwoWire Wire = TwoWire(); + diff --git a/libraries/Wire/Wire.h b/libraries/Wire/Wire.h new file mode 100644 index 0000000..a93d0f5 --- /dev/null +++ b/libraries/Wire/Wire.h @@ -0,0 +1,79 @@ +/* +  TwoWire.h - TWI/I2C library for Arduino & Wiring +  Copyright (c) 2006 Nicholas Zambetti.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ + +#ifndef TwoWire_h +#define TwoWire_h + +#include <inttypes.h> +#include "Stream.h" + +#define BUFFER_LENGTH 32 + +class TwoWire : public Stream +{ +  private: +    static uint8_t rxBuffer[]; +    static uint8_t rxBufferIndex; +    static uint8_t rxBufferLength; + +    static uint8_t txAddress; +    static uint8_t txBuffer[]; +    static uint8_t txBufferIndex; +    static uint8_t txBufferLength; + +    static uint8_t transmitting; +    static void (*user_onRequest)(void); +    static void (*user_onReceive)(int); +    static void onRequestService(void); +    static void onReceiveService(uint8_t*, int); +  public: +    TwoWire(); +    void begin(); +    void begin(uint8_t); +    void begin(int); +    void beginTransmission(uint8_t); +    void beginTransmission(int); +    uint8_t endTransmission(void); +    uint8_t endTransmission(uint8_t); +    uint8_t requestFrom(uint8_t, uint8_t); +    uint8_t requestFrom(uint8_t, uint8_t, uint8_t); +    uint8_t requestFrom(int, int); +    uint8_t requestFrom(int, int, int); +    virtual size_t write(uint8_t); +    virtual size_t write(const uint8_t *, size_t); +    virtual int available(void); +    virtual int read(void); +    virtual int peek(void); +	virtual void flush(void); +    void onReceive( void (*)(int) ); +    void onRequest( void (*)(void) ); +   +    inline size_t write(unsigned long n) { return write((uint8_t)n); } +    inline size_t write(long n) { return write((uint8_t)n); } +    inline size_t write(unsigned int n) { return write((uint8_t)n); } +    inline size_t write(int n) { return write((uint8_t)n); } +    using Print::write; +}; + +extern TwoWire Wire; + +#endif + diff --git a/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino b/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino new file mode 100644 index 0000000..9c41c18 --- /dev/null +++ b/libraries/Wire/examples/SFRRanger_reader/SFRRanger_reader.ino @@ -0,0 +1,87 @@ +// I2C SRF10 or SRF08 Devantech Ultrasonic Ranger Finder  +// by Nicholas Zambetti <http://www.zambetti.com> +// and James Tichenor <http://www.jamestichenor.net>  + +// Demonstrates use of the Wire library reading data from the  +// Devantech Utrasonic Rangers SFR08 and SFR10 + +// Created 29 April 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin();                // join i2c bus (address optional for master) +  Serial.begin(9600);          // start serial communication at 9600bps +} + +int reading = 0; + +void loop() +{ +  // step 1: instruct sensor to read echoes +  Wire.beginTransmission(112); // transmit to device #112 (0x70) +                               // the address specified in the datasheet is 224 (0xE0) +                               // but i2c adressing uses the high 7 bits so it's 112 +  Wire.write(byte(0x00));      // sets register pointer to the command register (0x00)   +  Wire.write(byte(0x50));      // command sensor to measure in "inches" (0x50)  +                               // use 0x51 for centimeters +                               // use 0x52 for ping microseconds +  Wire.endTransmission();      // stop transmitting + +  // step 2: wait for readings to happen +  delay(70);                   // datasheet suggests at least 65 milliseconds + +  // step 3: instruct sensor to return a particular echo reading +  Wire.beginTransmission(112); // transmit to device #112 +  Wire.write(byte(0x02));      // sets register pointer to echo #1 register (0x02) +  Wire.endTransmission();      // stop transmitting + +  // step 4: request reading from sensor +  Wire.requestFrom(112, 2);    // request 2 bytes from slave device #112 + +  // step 5: receive reading from sensor +  if(2 <= Wire.available())    // if two bytes were received +  { +    reading = Wire.read();  // receive high byte (overwrites previous reading) +    reading = reading << 8;    // shift high byte to be high 8 bits +    reading |= Wire.read(); // receive low byte as lower 8 bits +    Serial.println(reading);   // print the reading +  } + +  delay(250);                  // wait a bit since people have to read the output :) +} + + +/* + +// The following code changes the address of a Devantech Ultrasonic Range Finder (SRF10 or SRF08) +// usage: changeAddress(0x70, 0xE6); + +void changeAddress(byte oldAddress, byte newAddress) +{ +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xA0)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xAA)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(byte(0xA5)); +  Wire.endTransmission(); + +  Wire.beginTransmission(oldAddress); +  Wire.write(byte(0x00)); +  Wire.write(newAddress); +  Wire.endTransmission(); +} + +*/ diff --git a/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino b/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino new file mode 100644 index 0000000..38da1c5 --- /dev/null +++ b/libraries/Wire/examples/digital_potentiometer/digital_potentiometer.ino @@ -0,0 +1,39 @@ +// I2C Digital Potentiometer +// by Nicholas Zambetti <http://www.zambetti.com> +// and Shawn Bonkowski <http://people.interaction-ivrea.it/s.bonkowski/> + +// Demonstrates use of the Wire library +// Controls AD5171 digital potentiometer via I2C/TWI + +// Created 31 March 2006 + +// This example code is in the public domain. + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(); // join i2c bus (address optional for master) +} + +byte val = 0; + +void loop() +{ +  Wire.beginTransmission(44); // transmit to device #44 (0x2c) +                              // device address is specified in datasheet +  Wire.write(byte(0x00));            // sends instruction byte   +  Wire.write(val);             // sends potentiometer value byte   +  Wire.endTransmission();     // stop transmitting + +  val++;        // increment value +  if(val == 64) // if reached 64th position (max) +  { +    val = 0;    // start over from lowest value +  } +  delay(500); +} + diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino new file mode 100644 index 0000000..4124d7d --- /dev/null +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin();        // join i2c bus (address optional for master) +  Serial.begin(9600);  // start serial for output +} + +void loop() +{ +  Wire.requestFrom(2, 6);    // request 6 bytes from slave device #2 + +  while(Wire.available())    // slave may send less than requested +  {  +    char c = Wire.read(); // receive a byte as character +    Serial.print(c);         // print the character +  } + +  delay(500); +} diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino new file mode 100644 index 0000000..ccaa036 --- /dev/null +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -0,0 +1,31 @@ +// Wire Master Writer +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(); // join i2c bus (address optional for master) +} + +byte x = 0; + +void loop() +{ +  Wire.beginTransmission(4); // transmit to device #4 +  Wire.write("x is ");        // sends five bytes +  Wire.write(x);              // sends one byte   +  Wire.endTransmission();    // stop transmitting + +  x++; +  delay(500); +} diff --git a/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/libraries/Wire/examples/slave_receiver/slave_receiver.ino new file mode 100644 index 0000000..60dd4bd --- /dev/null +++ b/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -0,0 +1,38 @@ +// Wire Slave Receiver +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(4);                // join i2c bus with address #4 +  Wire.onReceive(receiveEvent); // register event +  Serial.begin(9600);           // start serial for output +} + +void loop() +{ +  delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) +{ +  while(1 < Wire.available()) // loop through all but the last +  { +    char c = Wire.read(); // receive byte as a character +    Serial.print(c);         // print the character +  } +  int x = Wire.read();    // receive byte as an integer +  Serial.println(x);         // print the integer +} diff --git a/libraries/Wire/examples/slave_sender/slave_sender.ino b/libraries/Wire/examples/slave_sender/slave_sender.ino new file mode 100644 index 0000000..d3b238a --- /dev/null +++ b/libraries/Wire/examples/slave_sender/slave_sender.ino @@ -0,0 +1,32 @@ +// Wire Slave Sender +// by Nicholas Zambetti <http://www.zambetti.com> + +// Demonstrates use of the Wire library +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + + +#include <Wire.h> + +void setup() +{ +  Wire.begin(2);                // join i2c bus with address #2 +  Wire.onRequest(requestEvent); // register event +} + +void loop() +{ +  delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() +{ +  Wire.write("hello "); // respond with message of 6 bytes +                       // as expected by master +} diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt new file mode 100644 index 0000000..12f129b --- /dev/null +++ b/libraries/Wire/keywords.txt @@ -0,0 +1,31 @@ +####################################### +# Syntax Coloring Map For Wire +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin	KEYWORD2 +beginTransmission	KEYWORD2 +endTransmission	KEYWORD2 +requestFrom	KEYWORD2 +send	KEYWORD2 +receive	KEYWORD2 +onReceive	KEYWORD2 +onRequest	KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +Wire	KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/libraries/Wire/utility/twi.c b/libraries/Wire/utility/twi.c new file mode 100644 index 0000000..6b2db3c --- /dev/null +++ b/libraries/Wire/utility/twi.c @@ -0,0 +1,527 @@ +/* +  twi.c - TWI/I2C library for Wiring & Arduino +  Copyright (c) 2006 Nicholas Zambetti.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA + +  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts +*/ + +#include <math.h> +#include <stdlib.h> +#include <inttypes.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <compat/twi.h> +#include "Arduino.h" // for digitalWrite + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif + +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + +#include "pins_arduino.h" +#include "twi.h" + +static volatile uint8_t twi_state; +static volatile uint8_t twi_slarw; +static volatile uint8_t twi_sendStop;			// should the transaction end with a stop +static volatile uint8_t twi_inRepStart;			// in the middle of a repeated start + +static void (*twi_onSlaveTransmit)(void); +static void (*twi_onSlaveReceive)(uint8_t*, int); + +static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_masterBufferIndex; +static volatile uint8_t twi_masterBufferLength; + +static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_txBufferIndex; +static volatile uint8_t twi_txBufferLength; + +static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; +static volatile uint8_t twi_rxBufferIndex; + +static volatile uint8_t twi_error; + +/*  + * Function twi_init + * Desc     readys twi pins and sets twi bitrate + * Input    none + * Output   none + */ +void twi_init(void) +{ +  // initialize state +  twi_state = TWI_READY; +  twi_sendStop = true;		// default value +  twi_inRepStart = false; +   +  // activate internal pullups for twi. +  digitalWrite(SDA, 1); +  digitalWrite(SCL, 1); + +  // initialize twi prescaler and bit rate +  cbi(TWSR, TWPS0); +  cbi(TWSR, TWPS1); +  TWBR = ((F_CPU / TWI_FREQ) - 16) / 2; + +  /* twi bit rate formula from atmega128 manual pg 204 +  SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR)) +  note: TWBR should be 10 or higher for master mode +  It is 72 for a 16mhz Wiring board with 100kHz TWI */ + +  // enable twi module, acks, and twi interrupt +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); +} + +/*  + * Function twi_slaveInit + * Desc     sets slave address and enables interrupt + * Input    none + * Output   none + */ +void twi_setAddress(uint8_t address) +{ +  // set twi slave address (skip over TWGCE bit) +  TWAR = address << 1; +} + +/*  + * Function twi_readFrom + * Desc     attempts to become twi bus master and read a + *          series of bytes from a device on the bus + * Input    address: 7bit i2c device address + *          data: pointer to byte array + *          length: number of bytes to read into array + *          sendStop: Boolean indicating whether to send a stop at the end + * Output   number of bytes read + */ +uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 0; +  } + +  // wait until twi is ready, become master receiver +  while(TWI_READY != twi_state){ +    continue; +  } +  twi_state = TWI_MRX; +  twi_sendStop = sendStop; +  // reset error state (0xFF.. no error occured) +  twi_error = 0xFF; + +  // initialize buffer iteration vars +  twi_masterBufferIndex = 0; +  twi_masterBufferLength = length-1;  // This is not intuitive, read on... +  // On receive, the previously configured ACK/NACK setting is transmitted in +  // response to the received byte before the interrupt is signalled.  +  // Therefor we must actually set NACK when the _next_ to last byte is +  // received, causing that NACK to be sent in response to receiving the last +  // expected byte of data. + +  // build sla+w, slave device address + w bit +  twi_slarw = TW_READ; +  twi_slarw |= address << 1; + +  if (true == twi_inRepStart) { +    // if we're in the repeated start state, then we've already sent the start, +    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. +    // We need to remove ourselves from the repeated start state before we enable interrupts, +    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning +    // up. Also, don't enable the START interrupt. There may be one pending from the  +    // repeated start that we sent outselves, and that would really confuse things. +    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR +    TWDR = twi_slarw; +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START +  } +  else +    // send start condition +    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + +  // wait for read operation to complete +  while(TWI_MRX == twi_state){ +    continue; +  } + +  if (twi_masterBufferIndex < length) +    length = twi_masterBufferIndex; + +  // copy twi buffer to data +  for(i = 0; i < length; ++i){ +    data[i] = twi_masterBuffer[i]; +  } +	 +  return length; +} + +/*  + * Function twi_writeTo + * Desc     attempts to become twi bus master and write a + *          series of bytes to a device on the bus + * Input    address: 7bit i2c device address + *          data: pointer to byte array + *          length: number of bytes in array + *          wait: boolean indicating to wait for write or not + *          sendStop: boolean indicating whether or not to send a stop at the end + * Output   0 .. success + *          1 .. length to long for buffer + *          2 .. address send, NACK received + *          3 .. data send, NACK received + *          4 .. other twi error (lost bus arbitration, bus error, ..) + */ +uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 1; +  } + +  // wait until twi is ready, become master transmitter +  while(TWI_READY != twi_state){ +    continue; +  } +  twi_state = TWI_MTX; +  twi_sendStop = sendStop; +  // reset error state (0xFF.. no error occured) +  twi_error = 0xFF; + +  // initialize buffer iteration vars +  twi_masterBufferIndex = 0; +  twi_masterBufferLength = length; +   +  // copy data to twi buffer +  for(i = 0; i < length; ++i){ +    twi_masterBuffer[i] = data[i]; +  } +   +  // build sla+w, slave device address + w bit +  twi_slarw = TW_WRITE; +  twi_slarw |= address << 1; +   +  // if we're in a repeated start, then we've already sent the START +  // in the ISR. Don't do it again. +  // +  if (true == twi_inRepStart) { +    // if we're in the repeated start state, then we've already sent the start, +    // (@@@ we hope), and the TWI statemachine is just waiting for the address byte. +    // We need to remove ourselves from the repeated start state before we enable interrupts, +    // since the ISR is ASYNC, and we could get confused if we hit the ISR before cleaning +    // up. Also, don't enable the START interrupt. There may be one pending from the  +    // repeated start that we sent outselves, and that would really confuse things. +    twi_inRepStart = false;			// remember, we're dealing with an ASYNC ISR +    TWDR = twi_slarw;				 +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE);	// enable INTs, but not START +  } +  else +    // send start condition +    TWCR = _BV(TWINT) | _BV(TWEA) | _BV(TWEN) | _BV(TWIE) | _BV(TWSTA);	// enable INTs + +  // wait for write operation to complete +  while(wait && (TWI_MTX == twi_state)){ +    continue; +  } +   +  if (twi_error == 0xFF) +    return 0;	// success +  else if (twi_error == TW_MT_SLA_NACK) +    return 2;	// error: address send, nack received +  else if (twi_error == TW_MT_DATA_NACK) +    return 3;	// error: data send, nack received +  else +    return 4;	// other twi error +} + +/*  + * Function twi_transmit + * Desc     fills slave tx buffer with data + *          must be called in slave tx event callback + * Input    data: pointer to byte array + *          length: number of bytes in array + * Output   1 length too long for buffer + *          2 not slave transmitter + *          0 ok + */ +uint8_t twi_transmit(const uint8_t* data, uint8_t length) +{ +  uint8_t i; + +  // ensure data will fit into buffer +  if(TWI_BUFFER_LENGTH < length){ +    return 1; +  } +   +  // ensure we are currently a slave transmitter +  if(TWI_STX != twi_state){ +    return 2; +  } +   +  // set length and copy data into tx buffer +  twi_txBufferLength = length; +  for(i = 0; i < length; ++i){ +    twi_txBuffer[i] = data[i]; +  } +   +  return 0; +} + +/*  + * Function twi_attachSlaveRxEvent + * Desc     sets function called before a slave read operation + * Input    function: callback function to use + * Output   none + */ +void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) +{ +  twi_onSlaveReceive = function; +} + +/*  + * Function twi_attachSlaveTxEvent + * Desc     sets function called before a slave write operation + * Input    function: callback function to use + * Output   none + */ +void twi_attachSlaveTxEvent( void (*function)(void) ) +{ +  twi_onSlaveTransmit = function; +} + +/*  + * Function twi_reply + * Desc     sends byte or readys receive line + * Input    ack: byte indicating to ack or to nack + * Output   none + */ +void twi_reply(uint8_t ack) +{ +  // transmit master read ready signal, with or without ack +  if(ack){ +    TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); +  }else{ +	  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); +  } +} + +/*  + * Function twi_stop + * Desc     relinquishes bus master status + * Input    none + * Output   none + */ +void twi_stop(void) +{ +  // send stop condition +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + +  // wait for stop condition to be exectued on bus +  // TWINT is not set after a stop condition! +  while(TWCR & _BV(TWSTO)){ +    continue; +  } + +  // update twi state +  twi_state = TWI_READY; +} + +/*  + * Function twi_releaseBus + * Desc     releases bus control + * Input    none + * Output   none + */ +void twi_releaseBus(void) +{ +  // release bus +  TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + +  // update twi state +  twi_state = TWI_READY; +} + +SIGNAL(TWI_vect) +{ +  switch(TW_STATUS){ +    // All Master +    case TW_START:     // sent start condition +    case TW_REP_START: // sent repeated start condition +      // copy device address and r/w bit to output register and ack +      TWDR = twi_slarw; +      twi_reply(1); +      break; + +    // Master Transmitter +    case TW_MT_SLA_ACK:  // slave receiver acked address +    case TW_MT_DATA_ACK: // slave receiver acked data +      // if there is data to send, send it, otherwise stop  +      if(twi_masterBufferIndex < twi_masterBufferLength){ +        // copy data to output register and ack +        TWDR = twi_masterBuffer[twi_masterBufferIndex++]; +        twi_reply(1); +      }else{ +	if (twi_sendStop) +          twi_stop(); +	else { +	  twi_inRepStart = true;	// we're gonna send the START +	  // don't enable the interrupt. We'll generate the start, but we  +	  // avoid handling the interrupt until we're in the next transaction, +	  // at the point where we would normally issue the start. +	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; +	  twi_state = TWI_READY; +	} +      } +      break; +    case TW_MT_SLA_NACK:  // address sent, nack received +      twi_error = TW_MT_SLA_NACK; +      twi_stop(); +      break; +    case TW_MT_DATA_NACK: // data sent, nack received +      twi_error = TW_MT_DATA_NACK; +      twi_stop(); +      break; +    case TW_MT_ARB_LOST: // lost bus arbitration +      twi_error = TW_MT_ARB_LOST; +      twi_releaseBus(); +      break; + +    // Master Receiver +    case TW_MR_DATA_ACK: // data received, ack sent +      // put byte into buffer +      twi_masterBuffer[twi_masterBufferIndex++] = TWDR; +    case TW_MR_SLA_ACK:  // address sent, ack received +      // ack if more bytes are expected, otherwise nack +      if(twi_masterBufferIndex < twi_masterBufferLength){ +        twi_reply(1); +      }else{ +        twi_reply(0); +      } +      break; +    case TW_MR_DATA_NACK: // data received, nack sent +      // put final byte into buffer +      twi_masterBuffer[twi_masterBufferIndex++] = TWDR; +	if (twi_sendStop) +          twi_stop(); +	else { +	  twi_inRepStart = true;	// we're gonna send the START +	  // don't enable the interrupt. We'll generate the start, but we  +	  // avoid handling the interrupt until we're in the next transaction, +	  // at the point where we would normally issue the start. +	  TWCR = _BV(TWINT) | _BV(TWSTA)| _BV(TWEN) ; +	  twi_state = TWI_READY; +	}     +	break; +    case TW_MR_SLA_NACK: // address sent, nack received +      twi_stop(); +      break; +    // TW_MR_ARB_LOST handled by TW_MT_ARB_LOST case + +    // Slave Receiver +    case TW_SR_SLA_ACK:   // addressed, returned ack +    case TW_SR_GCALL_ACK: // addressed generally, returned ack +    case TW_SR_ARB_LOST_SLA_ACK:   // lost arbitration, returned ack +    case TW_SR_ARB_LOST_GCALL_ACK: // lost arbitration, returned ack +      // enter slave receiver mode +      twi_state = TWI_SRX; +      // indicate that rx buffer can be overwritten and ack +      twi_rxBufferIndex = 0; +      twi_reply(1); +      break; +    case TW_SR_DATA_ACK:       // data received, returned ack +    case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack +      // if there is still room in the rx buffer +      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ +        // put byte in buffer and ack +        twi_rxBuffer[twi_rxBufferIndex++] = TWDR; +        twi_reply(1); +      }else{ +        // otherwise nack +        twi_reply(0); +      } +      break; +    case TW_SR_STOP: // stop or repeated start condition received +      // put a null char after data if there's room +      if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ +        twi_rxBuffer[twi_rxBufferIndex] = '\0'; +      } +      // sends ack and stops interface for clock stretching +      twi_stop(); +      // callback to user defined callback +      twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); +      // since we submit rx buffer to "wire" library, we can reset it +      twi_rxBufferIndex = 0; +      // ack future responses and leave slave receiver state +      twi_releaseBus(); +      break; +    case TW_SR_DATA_NACK:       // data received, returned nack +    case TW_SR_GCALL_DATA_NACK: // data received generally, returned nack +      // nack back at master +      twi_reply(0); +      break; +     +    // Slave Transmitter +    case TW_ST_SLA_ACK:          // addressed, returned ack +    case TW_ST_ARB_LOST_SLA_ACK: // arbitration lost, returned ack +      // enter slave transmitter mode +      twi_state = TWI_STX; +      // ready the tx buffer index for iteration +      twi_txBufferIndex = 0; +      // set tx buffer length to be zero, to verify if user changes it +      twi_txBufferLength = 0; +      // request for txBuffer to be filled and length to be set +      // note: user must call twi_transmit(bytes, length) to do this +      twi_onSlaveTransmit(); +      // if they didn't change buffer & length, initialize it +      if(0 == twi_txBufferLength){ +        twi_txBufferLength = 1; +        twi_txBuffer[0] = 0x00; +      } +      // transmit first byte from buffer, fall +    case TW_ST_DATA_ACK: // byte sent, ack returned +      // copy data to output register +      TWDR = twi_txBuffer[twi_txBufferIndex++]; +      // if there is more to send, ack, otherwise nack +      if(twi_txBufferIndex < twi_txBufferLength){ +        twi_reply(1); +      }else{ +        twi_reply(0); +      } +      break; +    case TW_ST_DATA_NACK: // received nack, we are done  +    case TW_ST_LAST_DATA: // received ack, but we are done already! +      // ack future responses +      twi_reply(1); +      // leave slave receiver state +      twi_state = TWI_READY; +      break; + +    // All +    case TW_NO_INFO:   // no state information +      break; +    case TW_BUS_ERROR: // bus error, illegal stop/start +      twi_error = TW_BUS_ERROR; +      twi_stop(); +      break; +  } +} + diff --git a/libraries/Wire/utility/twi.h b/libraries/Wire/utility/twi.h new file mode 100644 index 0000000..6526593 --- /dev/null +++ b/libraries/Wire/utility/twi.h @@ -0,0 +1,53 @@ +/* +  twi.h - TWI/I2C library for Wiring & Arduino +  Copyright (c) 2006 Nicholas Zambetti.  All right reserved. + +  This library is free software; you can redistribute it and/or +  modify it under the terms of the GNU Lesser General Public +  License as published by the Free Software Foundation; either +  version 2.1 of the License, or (at your option) any later version. + +  This library is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +  Lesser General Public License for more details. + +  You should have received a copy of the GNU Lesser General Public +  License along with this library; if not, write to the Free Software +  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +*/ + +#ifndef twi_h +#define twi_h + +  #include <inttypes.h> + +  //#define ATMEGA8 + +  #ifndef TWI_FREQ +  #define TWI_FREQ 100000L +  #endif + +  #ifndef TWI_BUFFER_LENGTH +  #define TWI_BUFFER_LENGTH 32 +  #endif + +  #define TWI_READY 0 +  #define TWI_MRX   1 +  #define TWI_MTX   2 +  #define TWI_SRX   3 +  #define TWI_STX   4 +   +  void twi_init(void); +  void twi_setAddress(uint8_t); +  uint8_t twi_readFrom(uint8_t, uint8_t*, uint8_t, uint8_t); +  uint8_t twi_writeTo(uint8_t, uint8_t*, uint8_t, uint8_t, uint8_t); +  uint8_t twi_transmit(const uint8_t*, uint8_t); +  void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); +  void twi_attachSlaveTxEvent( void (*)(void) ); +  void twi_reply(uint8_t); +  void twi_stop(void); +  void twi_releaseBus(void); + +#endif + diff --git a/platform.txt b/platform.txt new file mode 100644 index 0000000..d439ddd --- /dev/null +++ b/platform.txt @@ -0,0 +1,75 @@ + +# AVR compile variables +# ---------------------  + +name=Arduino AVR Boards +# Default "compiler.path" is correct, change only if you want to overidde the initial value +#compiler.path={ide.path}/tools/avr/bin/.. +compiler.c.cmd=avr-gcc +compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections -MMD +compiler.c.elf.flags=-Os -Wl,--gc-sections +compiler.c.elf.cmd=avr-gcc +compiler.S.flags=-c -g -assembler-with-cpp +compiler.cpp.cmd=avr-g++ +compiler.cpp.flags=-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -MMD +compiler.ar.cmd=avr-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=avr-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=avr-objcopy +compiler.ldflags= +compiler.size.cmd=avr-size +# this can be overriden in boards.txt +build.extra_flags= + +# AVR compile patterns +# -------------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={runtime.ide.version} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -D{software}={runtime.ide.version} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.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} -mmcu={build.mcu} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm + +## Create eeprom +recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.objcopy.eep.flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.eep" + +## Create hex +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.hex" +recipe.size.regex=Total\s+([0-9]+).* + + +# AVR Uploader/Programmers tools +# ------------------- + +tools.avrdude.cmd.path={runtime.ide.path}/hardware/tools/avr/bin/avrdude +tools.avrdude.config.path={runtime.ide.path}/hardware/tools/avr/etc/avrdude.conf +tools.avrdude.cmd.path.linux={runtime.ide.path}/hardware/tools/avrdude +tools.avrdude.config.path.linux={runtime.ide.path}/hardware/tools/avrdude.conf + +tools.avrdude.upload.params.verbose=-v -v -v -v +tools.avrdude.upload.params.quiet=-q -q +tools.avrdude.upload.pattern="{cmd.path}" "-C{config.path}" {upload.verbose} -p{build.mcu} -c{upload.protocol} -P{serial.port} -b{upload.speed} -D "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.program.params.verbose=-v -v -v -v +tools.avrdude.program.params.quiet=-q -q +tools.avrdude.program.pattern="{cmd.path}" "-C{config.path}" {program.verbose} -p{build.mcu} -c{protocol} {program.extra_params} "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.erase.params.verbose=-v -v -v -v +tools.avrdude.erase.params.quiet=-q -q +tools.avrdude.erase.pattern="{cmd.path}" "-C{config.path}" {erase.verbose} -p{build.mcu} -c{protocol} {program.extra_params} -e -Ulock:w:{bootloader.unlock_bits}:m -Uefuse:w:{bootloader.extended_fuses}:m -Uhfuse:w:{bootloader.high_fuses}:m -Ulfuse:w:{bootloader.low_fuses}:m + +tools.avrdude.bootloader.params.verbose=-v -v -v -v +tools.avrdude.bootloader.params.quiet=-q -q +tools.avrdude.bootloader.pattern="{cmd.path}" "-C{config.path}" {bootloader.verbose} -p{build.mcu} -c{protocol} {program.extra_params} "-Uflash:w:{runtime.ide.path}/hardware/arduino/avr/bootloaders/{bootloader.file}:i" -Ulock:w:{bootloader.lock_bits}:m + diff --git a/programmers.txt b/programmers.txt index c34b88c..65d8cdb 100644 --- a/programmers.txt +++ b/programmers.txt @@ -1,26 +1,41 @@ -# See: http://code.google.com/p/arduino/wiki/Platforms -  avrisp.name=AVR ISP  avrisp.communication=serial  avrisp.protocol=stk500v1 +avrisp.program.protocol=stk500v1 +avrisp.program.tool=avrdude +avrisp.program.extra_params=-P{serial.port}  avrispmkii.name=AVRISP mkII  avrispmkii.communication=usb  avrispmkii.protocol=stk500v2 +avrispmkii.program.protocol=stk500v2 +avrispmkii.program.tool=avrdude +avrispmkii.program.extra_params=-Pusb  usbtinyisp.name=USBtinyISP  usbtinyisp.protocol=usbtiny +usbtinyisp.program.tool=avrdude +usbtinyisp.program.extra_params=  usbasp.name=USBasp  usbasp.communication=usb  usbasp.protocol=usbasp +usbasp.program.protocol=usbasp +usbasp.program.tool=avrdude +usbasp.program.extra_params=-Pusb  parallel.name=Parallel Programmer  parallel.protocol=dapa  parallel.force=true  # parallel.delay=200 +parallel.program.tool=avrdude +parallel.program.extra_params=-F  arduinoisp.name=Arduino as ISP  arduinoisp.communication=serial  arduinoisp.protocol=stk500v1 -arduinoisp.speed=19200 +arduinoisp.speed=9600 +arduinoisp.program.protocol=stk500v1 +arduinoisp.program.speed=9600 +arduinoisp.program.tool=avrdude +arduinoisp.program.extra_params=-P{serial.port} -b{program.speed}  | 
