wiring-sucks

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit c535c3451636fe1e7032c72287dc089e95885b08
Author: Elecon@erl <elecon@elr.lan>
Date:   Sun, 16 Oct 2016 15:34:16 +0000

Initial commit

Diffstat:
A.gitignore | 4++++
ABinary.h | 516+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AMakefile | 23+++++++++++++++++++++++
APrint.cpp | 256+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APrint.h | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ATone.cpp | 523+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWApplet.c | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWCharacter.h | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWConstants.h | 341+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWInterrupts.c | 163+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWMath.cpp | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWMemory.cpp | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWProgram.h | 335+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWPulse.cpp | 501+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWShift.cpp | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWString.cpp | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWString.h | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWTimer.c | 768+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AWVector.h | 378+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 11+++++++++++
Ainclude/EEPROM/EEPROM.cpp | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/EEPROM/EEPROM.h | 36++++++++++++++++++++++++++++++++++++
Ainclude/EEPROM/examples/StoreData/StoreData.pde | 29+++++++++++++++++++++++++++++
Ainclude/EEPROM/keywords.txt | 25+++++++++++++++++++++++++
Ainclude/Encoder/Encoder.cpp | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Encoder/Encoder.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Encoder/examples/EncoderRead/EncoderRead.pde | 26++++++++++++++++++++++++++
Ainclude/Encoder/keywords.txt | 24++++++++++++++++++++++++
Ainclude/FIFO/FIFO.h | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/Boards.h | 384+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/Firmata.cpp | 438+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/Firmata.h | 162+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/LICENSE.txt | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/TODO.txt | 14++++++++++++++
Ainclude/Firmata/examples/AllInputsFirmata/AllInputsFirmata.pde | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/AnalogFirmata/AnalogFirmata.pde | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/AnalogFirmata/Makefile | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/EchoString/EchoString.pde | 40++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/EchoString/Makefile | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/I2CFirmata/I2CFirmata.pde | 216+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/OldStandardFirmata/LICENSE.txt | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/OldStandardFirmata/OldStandardFirmata.pde | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/ServoFirmata/Makefile | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/ServoFirmata/ServoFirmata.pde | 41+++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/SimpleAnalogFirmata/Makefile | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde | 37+++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/SimpleDigitalFirmata/Makefile | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/StandardFirmata/LICENSE.txt | 458+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/StandardFirmata/Makefile | 273+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/examples/StandardFirmata/StandardFirmata.pde | 401+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Firmata/keywords.txt | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Keypad/Keypad.cpp | 153+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Keypad/Keypad.h | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Keypad/examples/CustomKeypad/CustomKeypad.pde | 31+++++++++++++++++++++++++++++++
Ainclude/Keypad/examples/DynamicKeypad/DynamicKeypad.pde | 188+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Keypad/examples/EventKeypad/EventKeypad.pde | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Keypad/examples/HelloKeypad/HelloKeypad.pde | 29+++++++++++++++++++++++++++++
Ainclude/Keypad/keywords.txt | 18++++++++++++++++++
Ainclude/LiquidCrystal/LiquidCrystal.cpp | 384+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/LiquidCrystal/LiquidCrystal.h | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/LiquidCrystal/examples/PrintData/PrintData.pde | 32++++++++++++++++++++++++++++++++
Ainclude/LiquidCrystal/examples/PrintData/PrintData.png | 0
Ainclude/LiquidCrystal/keywords.txt | 24++++++++++++++++++++++++
Ainclude/Matrix/Matrix.cpp | 214+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Matrix/Matrix.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Matrix/examples/HelloMatrix/HelloMatrix.pde | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/Matrix/examples/HelloMatrix/HelloMatrix.png | 0
Ainclude/Matrix/examples/SpriteAnimation/SpriteAnimation.pde | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Matrix/keywords.txt | 22++++++++++++++++++++++
Ainclude/Messenger/Messenger.cpp | 155+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Messenger/Messenger.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Messenger/examples/basic_communication/basic_communication.pde | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Messenger/examples/checkString/checkString.pde | 45+++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Messenger/examples/copyString/copyString.pde | 47+++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Messenger/keywords.txt | 29+++++++++++++++++++++++++++++
Ainclude/NMEA/examples/BasicPositioning/BasicPositioning.pde | 47+++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/examples/BasicPositioning/BasicPositioning.png | 0
Ainclude/NMEA/examples/CourseToDestination/CourseToDestination.pde | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/examples/CourseToDestination/CourseToDestination.png | 0
Ainclude/NMEA/examples/DeterminingSpeed/DeterminingSpeed.pde | 41+++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/examples/DeterminingSpeed/DeterminingSpeed.png | 0
Ainclude/NMEA/examples/DistanceToDestination/DistanceToDestination.pde | 44++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/examples/DistanceToDestination/DistanceToDestination.png | 0
Ainclude/NMEA/examples/NMEASentence/NMEASentence.pde | 29+++++++++++++++++++++++++++++
Ainclude/NMEA/examples/NMEASentence/NMEASentence.png | 0
Ainclude/NMEA/keywords.txt | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/nmea.cpp | 339+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NMEA/nmea.h | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NewSoftSerial/Examples/NewSoftSerialTest/NewSoftSerialTest.pde | 25+++++++++++++++++++++++++
Ainclude/NewSoftSerial/Examples/TwoNSSTest/TwoNSSTest.pde | 33+++++++++++++++++++++++++++++++++
Ainclude/NewSoftSerial/NewSoftSerial.cpp | 539+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NewSoftSerial/NewSoftSerial.h | 108+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/NewSoftSerial/keywords.txt | 30++++++++++++++++++++++++++++++
Ainclude/OneWire/OneWire.cpp | 348+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/OneWire/OneWire.h | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/OneWire/keywords.txt | 2++
Ainclude/OneWire/utility/pins_wiring.c | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/OneWire/utility/pins_wiring.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Password/Examples/HelloPassword/HelloPassword.pde | 36++++++++++++++++++++++++++++++++++++
Ainclude/Password/Examples/PasswordKeypad/PasswordKeypad.pde | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Password/Examples/SerialMonitor/SerialMonitor.pde | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Password/Password.cpp | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Password/Password.h | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Password/keywords.txt | 7+++++++
Ainclude/QSlide/QSlide.cpp | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/QSlide/QSlide.h | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/QSlide/examples/QSlideTouch/QSlideTouch.pde | 34++++++++++++++++++++++++++++++++++
Ainclude/QSlide/keywords.txt | 24++++++++++++++++++++++++
Ainclude/SPI/SPI.cpp | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SPI/SPI.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.pde | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SPI/examples/BarometricPressureSensor/BarometricPressureSensor.png | 0
Ainclude/SPI/examples/GyroMLX90609/GyroMLX90609.pde | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SPI/examples/GyroMLX90609/GyroMLX90609.png | 0
Ainclude/SPI/keywords.txt | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/HardwareSerial.cpp | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/HardwareSerial.h | 143+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/AdvancedOutput/AdvancedOutput.pde | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/Midi/Midi.pde | 40++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/MultiplePorts/MultiplePorts.pde | 29+++++++++++++++++++++++++++++
Ainclude/Serial/examples/PhotoresistorSerial/PhotoresistorSerial.pde | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/PhotoresistorSerial/PhotoresistorSerial.png | 0
Ainclude/Serial/examples/ReadString/ReadString.pde | 37+++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SendingMultipleData/SendingMultipleData.pde | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SerialRFID/SerialRFID.pde | 46++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SerialRFID/SerialRFID.png | 0
Ainclude/Serial/examples/SerialReadProcessing/SerialReadProcessing.pde | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SerialWeather/SerialWeather.pde | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SerialWeather/SerialWeather.png | 0
Ainclude/Serial/examples/SerialWriteProcessing/SerialWriteProcessing.pde | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Serial/examples/SerialWriteProcessing/SerialWriteProcessing.png | 0
Ainclude/Serial/examples/SimpleRead/SimpleRead.pde | 25+++++++++++++++++++++++++
Ainclude/Serial/examples/SimpleReadWrite/SimpleReadWrite.pde | 20++++++++++++++++++++
Ainclude/Serial/examples/SimpleWrite/SimpleWrite.pde | 19+++++++++++++++++++
Ainclude/Serial/keywords.txt | 40++++++++++++++++++++++++++++++++++++++++
Ainclude/Servo/Servo.cpp | 338+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Servo/Servo.h | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Servo/ServoTimers.h | 43+++++++++++++++++++++++++++++++++++++++++++
Ainclude/Servo/examples/ServoAnalogInput/ServoAnalogInput.pde | 26++++++++++++++++++++++++++
Ainclude/Servo/examples/ServoMotor/ServoMotor.pde | 34++++++++++++++++++++++++++++++++++
Ainclude/Servo/examples/ServoMotor/ServoMotor.png | 0
Ainclude/Servo/examples/ServoMultiple/ServoMultiple.pde | 33+++++++++++++++++++++++++++++++++
Ainclude/Servo/examples/ServoMultiple/ServoMultiple.png | 0
Ainclude/Servo/keywords.txt | 24++++++++++++++++++++++++
Ainclude/SoftwareSerial/SoftwareSerial.cpp | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SoftwareSerial/SoftwareSerial.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/SoftwareSerial/keywords.txt | 32++++++++++++++++++++++++++++++++
Ainclude/Sprite/Binary.h | 516+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Sprite/Sprite.cpp | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Sprite/Sprite.h | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Sprite/keywords.txt | 534+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Stepper/Stepper.cpp | 218+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Stepper/Stepper.h | 86+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Stepper/examples/StepperMove/StepperMove.pde | 31+++++++++++++++++++++++++++++++
Ainclude/Stepper/examples/StepperMove/StepperMove.png | 0
Ainclude/Stepper/keywords.txt | 28++++++++++++++++++++++++++++
Ainclude/Stream/Stream.h | 35+++++++++++++++++++++++++++++++++++
Ainclude/Timer2/HardwareTimer2.cpp | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Timer2/HardwareTimer2.h | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Timer2/examples/Timer2LED/Timer2LED.pde | 36++++++++++++++++++++++++++++++++++++
Ainclude/Timer2/keywords.txt | 30++++++++++++++++++++++++++++++
Ainclude/Wire/Wire.cpp | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/Wire.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/BMP085/BMP085.pde | 205+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/BMP085/BMP085.png | 0
Ainclude/Wire/examples/DigitalPotentiometer/DigitalPotentiometer.pde | 34++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/HMC6343sparkfun/HMC6343sparkfun.pde | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/HMC6343sparkfun/HMC6343sparkfun.png | 0
Ainclude/Wire/examples/HMC6352sparkfun/HMC6352sparkfun.pde | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/HMC6352sparkfun/HMC6352sparkfun.png | 0
Ainclude/Wire/examples/MasterReader/MasterReader.pde | 29+++++++++++++++++++++++++++++
Ainclude/Wire/examples/MasterWriter/MasterWriter.pde | 28++++++++++++++++++++++++++++
Ainclude/Wire/examples/RealTimeClock/RealTimeClock.pde | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/RealTimeClock/RealTimeClock.png | 0
Ainclude/Wire/examples/SlaveReceiver/SlaveReceiver.pde | 35+++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/SlaveSender/SlaveSender.pde | 29+++++++++++++++++++++++++++++
Ainclude/Wire/examples/UltrasonicSFR/UltrasonicSFR.pde | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/UltrasonicSFR/UltrasonicSFR.png | 0
Ainclude/Wire/examples/tmp102sparkfun/tmp102sparkfun.pde | 46++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/examples/tmp102sparkfun/tmp102sparkfun.png | 0
Ainclude/Wire/keywords.txt | 31+++++++++++++++++++++++++++++++
Ainclude/Wire/utility/twi.c | 476+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ainclude/Wire/utility/twi.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amain.cpp | 14++++++++++++++
Aprogram.cpp | 17+++++++++++++++++
186 files changed, 21920 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1,3 @@ +WApplet +WApplet.bin +*.o+ \ No newline at end of file diff --git a/Binary.h b/Binary.h @@ -0,0 +1,516 @@ +#ifndef Binary_h +#define Binary_h + +#define B0 0 +#define B00 0 +#define B000 0 +#define B0000 0 +#define B00000 0 +#define B000000 0 +#define B0000000 0 +#define B00000000 0 +#define B1 1 +#define B01 1 +#define B001 1 +#define B0001 1 +#define B00001 1 +#define B000001 1 +#define B0000001 1 +#define B00000001 1 +#define B10 2 +#define B010 2 +#define B0010 2 +#define B00010 2 +#define B000010 2 +#define B0000010 2 +#define B00000010 2 +#define B11 3 +#define B011 3 +#define B0011 3 +#define B00011 3 +#define B000011 3 +#define B0000011 3 +#define B00000011 3 +#define B100 4 +#define B0100 4 +#define B00100 4 +#define B000100 4 +#define B0000100 4 +#define B00000100 4 +#define B101 5 +#define B0101 5 +#define B00101 5 +#define B000101 5 +#define B0000101 5 +#define B00000101 5 +#define B110 6 +#define B0110 6 +#define B00110 6 +#define B000110 6 +#define B0000110 6 +#define B00000110 6 +#define B111 7 +#define B0111 7 +#define B00111 7 +#define B000111 7 +#define B0000111 7 +#define B00000111 7 +#define B1000 8 +#define B01000 8 +#define B001000 8 +#define B0001000 8 +#define B00001000 8 +#define B1001 9 +#define B01001 9 +#define B001001 9 +#define B0001001 9 +#define B00001001 9 +#define B1010 10 +#define B01010 10 +#define B001010 10 +#define B0001010 10 +#define B00001010 10 +#define B1011 11 +#define B01011 11 +#define B001011 11 +#define B0001011 11 +#define B00001011 11 +#define B1100 12 +#define B01100 12 +#define B001100 12 +#define B0001100 12 +#define B00001100 12 +#define B1101 13 +#define B01101 13 +#define B001101 13 +#define B0001101 13 +#define B00001101 13 +#define B1110 14 +#define B01110 14 +#define B001110 14 +#define B0001110 14 +#define B00001110 14 +#define B1111 15 +#define B01111 15 +#define B001111 15 +#define B0001111 15 +#define B00001111 15 +#define B10000 16 +#define B010000 16 +#define B0010000 16 +#define B00010000 16 +#define B10001 17 +#define B010001 17 +#define B0010001 17 +#define B00010001 17 +#define B10010 18 +#define B010010 18 +#define B0010010 18 +#define B00010010 18 +#define B10011 19 +#define B010011 19 +#define B0010011 19 +#define B00010011 19 +#define B10100 20 +#define B010100 20 +#define B0010100 20 +#define B00010100 20 +#define B10101 21 +#define B010101 21 +#define B0010101 21 +#define B00010101 21 +#define B10110 22 +#define B010110 22 +#define B0010110 22 +#define B00010110 22 +#define B10111 23 +#define B010111 23 +#define B0010111 23 +#define B00010111 23 +#define B11000 24 +#define B011000 24 +#define B0011000 24 +#define B00011000 24 +#define B11001 25 +#define B011001 25 +#define B0011001 25 +#define B00011001 25 +#define B11010 26 +#define B011010 26 +#define B0011010 26 +#define B00011010 26 +#define B11011 27 +#define B011011 27 +#define B0011011 27 +#define B00011011 27 +#define B11100 28 +#define B011100 28 +#define B0011100 28 +#define B00011100 28 +#define B11101 29 +#define B011101 29 +#define B0011101 29 +#define B00011101 29 +#define B11110 30 +#define B011110 30 +#define B0011110 30 +#define B00011110 30 +#define B11111 31 +#define B011111 31 +#define B0011111 31 +#define B00011111 31 +#define B100000 32 +#define B0100000 32 +#define B00100000 32 +#define B100001 33 +#define B0100001 33 +#define B00100001 33 +#define B100010 34 +#define B0100010 34 +#define B00100010 34 +#define B100011 35 +#define B0100011 35 +#define B00100011 35 +#define B100100 36 +#define B0100100 36 +#define B00100100 36 +#define B100101 37 +#define B0100101 37 +#define B00100101 37 +#define B100110 38 +#define B0100110 38 +#define B00100110 38 +#define B100111 39 +#define B0100111 39 +#define B00100111 39 +#define B101000 40 +#define B0101000 40 +#define B00101000 40 +#define B101001 41 +#define B0101001 41 +#define B00101001 41 +#define B101010 42 +#define B0101010 42 +#define B00101010 42 +#define B101011 43 +#define B0101011 43 +#define B00101011 43 +#define B101100 44 +#define B0101100 44 +#define B00101100 44 +#define B101101 45 +#define B0101101 45 +#define B00101101 45 +#define B101110 46 +#define B0101110 46 +#define B00101110 46 +#define B101111 47 +#define B0101111 47 +#define B00101111 47 +#define B110000 48 +#define B0110000 48 +#define B00110000 48 +#define B110001 49 +#define B0110001 49 +#define B00110001 49 +#define B110010 50 +#define B0110010 50 +#define B00110010 50 +#define B110011 51 +#define B0110011 51 +#define B00110011 51 +#define B110100 52 +#define B0110100 52 +#define B00110100 52 +#define B110101 53 +#define B0110101 53 +#define B00110101 53 +#define B110110 54 +#define B0110110 54 +#define B00110110 54 +#define B110111 55 +#define B0110111 55 +#define B00110111 55 +#define B111000 56 +#define B0111000 56 +#define B00111000 56 +#define B111001 57 +#define B0111001 57 +#define B00111001 57 +#define B111010 58 +#define B0111010 58 +#define B00111010 58 +#define B111011 59 +#define B0111011 59 +#define B00111011 59 +#define B111100 60 +#define B0111100 60 +#define B00111100 60 +#define B111101 61 +#define B0111101 61 +#define B00111101 61 +#define B111110 62 +#define B0111110 62 +#define B00111110 62 +#define B111111 63 +#define B0111111 63 +#define B00111111 63 +#define B1000000 64 +#define B01000000 64 +#define B1000001 65 +#define B01000001 65 +#define B1000010 66 +#define B01000010 66 +#define B1000011 67 +#define B01000011 67 +#define B1000100 68 +#define B01000100 68 +#define B1000101 69 +#define B01000101 69 +#define B1000110 70 +#define B01000110 70 +#define B1000111 71 +#define B01000111 71 +#define B1001000 72 +#define B01001000 72 +#define B1001001 73 +#define B01001001 73 +#define B1001010 74 +#define B01001010 74 +#define B1001011 75 +#define B01001011 75 +#define B1001100 76 +#define B01001100 76 +#define B1001101 77 +#define B01001101 77 +#define B1001110 78 +#define B01001110 78 +#define B1001111 79 +#define B01001111 79 +#define B1010000 80 +#define B01010000 80 +#define B1010001 81 +#define B01010001 81 +#define B1010010 82 +#define B01010010 82 +#define B1010011 83 +#define B01010011 83 +#define B1010100 84 +#define B01010100 84 +#define B1010101 85 +#define B01010101 85 +#define B1010110 86 +#define B01010110 86 +#define B1010111 87 +#define B01010111 87 +#define B1011000 88 +#define B01011000 88 +#define B1011001 89 +#define B01011001 89 +#define B1011010 90 +#define B01011010 90 +#define B1011011 91 +#define B01011011 91 +#define B1011100 92 +#define B01011100 92 +#define B1011101 93 +#define B01011101 93 +#define B1011110 94 +#define B01011110 94 +#define B1011111 95 +#define B01011111 95 +#define B1100000 96 +#define B01100000 96 +#define B1100001 97 +#define B01100001 97 +#define B1100010 98 +#define B01100010 98 +#define B1100011 99 +#define B01100011 99 +#define B1100100 100 +#define B01100100 100 +#define B1100101 101 +#define B01100101 101 +#define B1100110 102 +#define B01100110 102 +#define B1100111 103 +#define B01100111 103 +#define B1101000 104 +#define B01101000 104 +#define B1101001 105 +#define B01101001 105 +#define B1101010 106 +#define B01101010 106 +#define B1101011 107 +#define B01101011 107 +#define B1101100 108 +#define B01101100 108 +#define B1101101 109 +#define B01101101 109 +#define B1101110 110 +#define B01101110 110 +#define B1101111 111 +#define B01101111 111 +#define B1110000 112 +#define B01110000 112 +#define B1110001 113 +#define B01110001 113 +#define B1110010 114 +#define B01110010 114 +#define B1110011 115 +#define B01110011 115 +#define B1110100 116 +#define B01110100 116 +#define B1110101 117 +#define B01110101 117 +#define B1110110 118 +#define B01110110 118 +#define B1110111 119 +#define B01110111 119 +#define B1111000 120 +#define B01111000 120 +#define B1111001 121 +#define B01111001 121 +#define B1111010 122 +#define B01111010 122 +#define B1111011 123 +#define B01111011 123 +#define B1111100 124 +#define B01111100 124 +#define B1111101 125 +#define B01111101 125 +#define B1111110 126 +#define B01111110 126 +#define B1111111 127 +#define B01111111 127 +#define B10000000 128 +#define B10000001 129 +#define B10000010 130 +#define B10000011 131 +#define B10000100 132 +#define B10000101 133 +#define B10000110 134 +#define B10000111 135 +#define B10001000 136 +#define B10001001 137 +#define B10001010 138 +#define B10001011 139 +#define B10001100 140 +#define B10001101 141 +#define B10001110 142 +#define B10001111 143 +#define B10010000 144 +#define B10010001 145 +#define B10010010 146 +#define B10010011 147 +#define B10010100 148 +#define B10010101 149 +#define B10010110 150 +#define B10010111 151 +#define B10011000 152 +#define B10011001 153 +#define B10011010 154 +#define B10011011 155 +#define B10011100 156 +#define B10011101 157 +#define B10011110 158 +#define B10011111 159 +#define B10100000 160 +#define B10100001 161 +#define B10100010 162 +#define B10100011 163 +#define B10100100 164 +#define B10100101 165 +#define B10100110 166 +#define B10100111 167 +#define B10101000 168 +#define B10101001 169 +#define B10101010 170 +#define B10101011 171 +#define B10101100 172 +#define B10101101 173 +#define B10101110 174 +#define B10101111 175 +#define B10110000 176 +#define B10110001 177 +#define B10110010 178 +#define B10110011 179 +#define B10110100 180 +#define B10110101 181 +#define B10110110 182 +#define B10110111 183 +#define B10111000 184 +#define B10111001 185 +#define B10111010 186 +#define B10111011 187 +#define B10111100 188 +#define B10111101 189 +#define B10111110 190 +#define B10111111 191 +#define B11000000 192 +#define B11000001 193 +#define B11000010 194 +#define B11000011 195 +#define B11000100 196 +#define B11000101 197 +#define B11000110 198 +#define B11000111 199 +#define B11001000 200 +#define B11001001 201 +#define B11001010 202 +#define B11001011 203 +#define B11001100 204 +#define B11001101 205 +#define B11001110 206 +#define B11001111 207 +#define B11010000 208 +#define B11010001 209 +#define B11010010 210 +#define B11010011 211 +#define B11010100 212 +#define B11010101 213 +#define B11010110 214 +#define B11010111 215 +#define B11011000 216 +#define B11011001 217 +#define B11011010 218 +#define B11011011 219 +#define B11011100 220 +#define B11011101 221 +#define B11011110 222 +#define B11011111 223 +#define B11100000 224 +#define B11100001 225 +#define B11100010 226 +#define B11100011 227 +#define B11100100 228 +#define B11100101 229 +#define B11100110 230 +#define B11100111 231 +#define B11101000 232 +#define B11101001 233 +#define B11101010 234 +#define B11101011 235 +#define B11101100 236 +#define B11101101 237 +#define B11101110 238 +#define B11101111 239 +#define B11110000 240 +#define B11110001 241 +#define B11110010 242 +#define B11110011 243 +#define B11110100 244 +#define B11110101 245 +#define B11110110 246 +#define B11110111 247 +#define B11111000 248 +#define B11111001 249 +#define B11111010 250 +#define B11111011 251 +#define B11111100 252 +#define B11111101 253 +#define B11111110 254 +#define B11111111 255 + +#endif + diff --git a/Makefile b/Makefile @@ -0,0 +1,22 @@ +include config.mk + +OBJS = main.o program.o\ +WApplet.o WTimer.o WInterrupts.o \ +WMath.o WMemory.o WString.o WPulse.o \ +WShift.o Print.o Tone.o + +%.o : %.cpp + $(CXX) -c -o $@ $< +%.o : %.c + $(CC) -c -o $@ $< + + +WApplet: $(OBJS) + $(LD) -o $@ $^ + $(OBJCOPY) $@ WApplet.bin + +flash: + uisp -dprog=stk500 -v=2 -dserial=$(SERIAL) -dpart=$(MCU) if=WApplet.bin --upload + +clean: + rm -f WApplet WApplet.bin *.o + \ No newline at end of file diff --git a/Print.cpp b/Print.cpp @@ -0,0 +1,256 @@ +/* + WPrint.cpp - Print library for Wiring & Arduino + Class code factored out from Serial and LiquidCrytal libraries + Copyright (c) 2007-08 Hernando Barragan. 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 <stdio.h> +#include <string.h> +#include <inttypes.h> +#include "WProgram.h" +#include "Print.h" + + +void Print::print(uint8_t b) +{ + this->write(b); +} + +void Print::print(char c) +{ + print((byte) c); +} + +void Print::print(const char c[]) +{ + while (*c) + print(*c++); +} + +void Print::print(const String &str) +{ + for (int i = 0; i < str.length(); i++) { + write(str[i]); + } +} + +void Print::print(int n) +{ + print((long) n); +} + +void Print::print(double n) +{ + printFloat(n, 2); +} + +void Print::print(double n, int digits) +{ + printFloat(n, digits); +} + +void Print::print(unsigned int n) +{ + print((unsigned long) n); +} + +void Print::print(long n) +{ + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); +} + +void Print::print(unsigned long n) +{ + printNumber(n, 10); +} + +void Print::print(int n, int base) +{ + print((long)n, base); +} + +void Print::print(unsigned int n, int base) +{ + print((long)n, base); +} + +void Print::print(unsigned long n, int base) +{ + print((long)n, base); +} + +void Print::print(long n, int base) +{ + if (base == 0) + print((char) n); + else if (base == 10) + print(n); + else + printNumber(n, base); +} + +void Print::println(void) +{ + print('\r'); + print('\n'); +} + +void Print::println(char c) +{ + print(c); + println(); +} + +void Print::println(const char c[]) +{ + print(c); + println(); +} + +void Print::println(const String &str) +{ + print(str); + println(); +} + +void Print::println(uint8_t b) +{ + print(b); + println(); +} + +void Print::println(int n) +{ + print(n); + println(); +} + +void Print::println(double n) +{ + print(n); + println(); +} + +void Print::println(double n, int digits) +{ + print(n, digits); + println(); +} + +void Print::println(unsigned int n) +{ + print(n); + println(); +} + +void Print::println(long n) +{ + print(n); + println(); +} + +void Print::println(unsigned long n) +{ + print(n); + println(); +} + +void Print::println(int n, int base) +{ + print(n, base); + println(); +} + +void Print::println(unsigned int n, int base) +{ + print(n, base); + println(); +} + +void Print::println(long n, int base) +{ + print(n, base); + println(); +} + +void Print::println(unsigned long n, int base) +{ + print(n, base); + println(); +} + +// Private Methods ///////////////////////////////////////////////////////////// + +void Print::printNumber(unsigned long n, uint8_t base) +{ + unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars. + unsigned long i = 0; + + if (n == 0) { + print('0'); + return; + } + + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + + for (; i > 0; i--) + print((char) (buf[i - 1] < 10 ? + '0' + buf[i - 1] : + 'A' + buf[i - 1] - 10)); +} + +void Print::printFloat(double number, uint8_t digits) +{ + // Handle negative numbers + if (number < 0.0) + { + print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for (uint8_t i=0; i<digits; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long)number; + double remainder = number - (double)int_part; + print(int_part); + + // Print the decimal point, but only if there are digits beyond + if (digits > 0) + print("."); + + // Extract digits from the remainder one at a time + while (digits-- > 0) + { + remainder *= 10.0; + int toPrint = int(remainder); + print(toPrint); + remainder -= toPrint; + } +} diff --git a/Print.h b/Print.h @@ -0,0 +1,68 @@ +/* + WPrint.h - Print library for Wiring & Arduino + Class code factored out from Serial and LiquidCrystal libraries + Copyright (c) 2007-08 Hernando Barragan. 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 Print_h +#define Print_h + +#include "WProgram.h" +#include "WConstants.h" +#include <string.h> +#include <ctype.h> +#include <inttypes.h> + +class Print +{ + public: + virtual void write(uint8_t); + void print(char); + void print(const char[]); + void print(const String &); + void print(uint8_t); + void print(int); + void print(double); + void print(double, int); + void print(unsigned int); + void print(long); + void print(unsigned long); + void print(int, int); + void print(unsigned int, int); + void print(long, int); + void print(unsigned long, int); + void println(void); + void println(char); + void println(const char[]); + void println(const String &); + void println(uint8_t); + void println(int); + void println(double); + void println(double, int); + void println(unsigned int); + void println(long); + void println(unsigned long); + void println(int, int); + void println(unsigned int, int); + void println(long, int); + void println(unsigned long, int); + private: + void printNumber(unsigned long, uint8_t); + void printFloat(double, uint8_t); +}; + +#endif diff --git a/Tone.cpp b/Tone.cpp @@ -0,0 +1,523 @@ +/* Tone.cpp + + A Tone Generator Library + + Written by Brett Hagman + + 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 + +Version Modified By Date Comments +------- ----------- -------- -------- +0001 B Hagman 09/08/02 Initial coding +0002 B Hagman 09/08/18 Multiple pins +0003 B Hagman 09/08/18 Moved initialization from constructor to begin() +0004 B Hagman 09/09/26 Fixed problems with ATmega8 +0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers + 09/11/25 Changed pin toggle method to XOR + 09/11/25 Fixed timer0 from being excluded +0006 D Mellis 09/12/29 Replaced objects with functions +0007 D Barragan 10/01/26 Support for Wiring +0008 B Hagman 10/09/15 Fixed ck/32 prescalar divisor + +*************************************************/ +#include <avr/pgmspace.h> +#include "WProgram.h" + +// > 0 - duration specified +// = 0 - stopped +// < 0 - infinitely (until stop() method called, or new play() called) + + +volatile long timer1_toggle_count; +volatile uint8_t *timer1_pin_port; +volatile uint8_t timer1_pin_mask; +volatile long timer2_toggle_count; +volatile uint8_t *timer2_pin_port; +volatile uint8_t timer2_pin_mask; +volatile long timer3_toggle_count; +volatile uint8_t *timer3_pin_port; +volatile uint8_t timer3_pin_mask; +void ToneTimer1Service(); +void ToneTimer2Service(); +void ToneTimer3Service(); +#if defined(__AVR_ATmega1281__) || (__AVR_ATmega2561__) +volatile long timer4_toggle_count; +volatile uint8_t *timer4_pin_port; +volatile uint8_t timer4_pin_mask; +volatile long timer5_toggle_count; +volatile uint8_t *timer5_pin_port; +volatile uint8_t timer5_pin_mask; +void ToneTimer4Service(); +void ToneTimer5Service(); +#endif + + +#if defined(__AVR_ATmega128__) + +#define AVAILABLE_TONE_PINS 1 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; + +#elif defined(__AVR_ATmega1281__) || (__AVR_ATmega2561__) + +#define AVAILABLE_TONE_PINS 1 + +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; + +#else + +#define AVAILABLE_TONE_PINS 1 + +// Leave timer 0 to last. +const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; +static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; + +#endif + + + +static int8_t toneBegin(uint8_t _pin) +{ + int8_t _timer = -1; + + // if we're already using the pin, the timer should be configured. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + return pgm_read_byte(tone_pin_to_timer_PGM + i); + } + } + + // search for an unused timer. + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == 255) { + tone_pins[i] = _pin; + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + break; + } + } + + if (_timer != -1) + { + // Set timer specific stuff + // All timers in CTC mode + // 8 bit timers will require changing prescalar values, + // whereas 16 bit timers are set to either ck/1 or ck/64 prescalar + switch (_timer) + { + case 1: + // 16 bit timer + TCCR1A = 0; + TCCR1B = 0; + TCCR1B |= _BV(WGM12) | _BV(CS10); + //bitWrite(TCCR1B, WGM12, 1); + //bitWrite(TCCR1B, CS10, 1); + timer1_pin_port = digitalPinToPortReg(_pin); //portOutputRegister(digitalPinToPort(_pin)); + timer1_pin_mask = digitalPinToBit(_pin); //digitalPinToBitMask(_pin); + break; + case 2: + // 8 bit timer +#if defined(__AVR_ATmega128__) + TCCR2 = 0; + TCCR2 |= _BV(WGM21) || _BV(CS20); +#else + TCCR2A = 0; + TCCR2B = 0; + TCCR2A |= _BV(WGM21); + TCCR2B |= _BV(CS20); + //bitWrite(TCCR2A, WGM21, 1); + //bitWrite(TCCR2B, CS20, 1); +#endif + timer2_pin_port = digitalPinToPortReg(_pin); //portOutputRegister(digitalPinToPort(_pin)); + timer2_pin_mask = digitalPinToBit(_pin); //digitalPinToBitMask(_pin); + break; + case 3: + // 16 bit timer + TCCR3A = 0; + TCCR3B = 0; + TCCR3B |= _BV(WGM32) | _BV(CS30); + //bitWrite(TCCR3B, WGM32, 1); + //bitWrite(TCCR3B, CS30, 1); + timer3_pin_port = digitalPinToPortReg(_pin); //portOutputRegister(digitalPinToPort(_pin)); + timer3_pin_mask = digitalPinToBit(_pin); //digitalPinToBitMask(_pin); + break; +#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) + case 4: + // 16 bit timer + TCCR4A = 0; + TCCR4B = 0; + TCCR4B |= _BV(WGM42) | _BV(CS40); + //bitWrite(TCCR4B, WGM42, 1); + //bitWrite(TCCR4B, CS40, 1); + timer4_pin_port = digitalPinToPortReg(_pin); //portOutputRegister(digitalPinToPort(_pin)); + timer4_pin_mask = digitalPinToBit(_pin); //digitalPinToBitMask(_pin); + break; + case 5: + // 16 bit timer + TCCR5A = 0; + TCCR5B = 0; + TCCR5B |= _BV(WGM52) | _BV(CS50); + //bitWrite(TCCR5B, WGM52, 1); + //bitWrite(TCCR5B, CS50, 1); + timer5_pin_port = digitalPinToPortReg(_pin); //portOutputRegister(digitalPinToPort(_pin)); + timer5_pin_mask = digitalPinToBit(_pin); //digitalPinToBitMask(_pin); + break; +#endif + default: + break; + } + } + + return _timer; +} + + + +// frequency (in hertz) and duration (in milliseconds). + +void tone(uint8_t _pin, unsigned int frequency, long duration) +{ + uint8_t prescalar = TIMER_CLK_DIV1; + long toggle_count = 0; + uint32_t ocr = 0; + int8_t _timer; + + _timer = toneBegin(_pin); + + if (_timer >= 1) + { + // Set the pinMode as OUTPUT + pinMode(_pin, OUTPUT); + + // if we are using an 8 bit timer, scan through prescalars to find the best fit + if (_timer == 2) + { + ocr = F_CPU / frequency / 2 - 1; + prescalar = TIMER_CLK_DIV1; + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 8 - 1; + prescalar = TIMER_CLK_DIV8; + +#if !defined(__AVR_ATmega128__) + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 32 - 1; + prescalar = TIMERRTC_CLK_DIV32; + } +#endif + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 64 - 1; +#if defined(__AVR_ATmega128__) + prescalar = TIMER_CLK_DIV64; +#else + prescalar = TIMERRTC_CLK_DIV64; +#endif + + if (_timer == 2 && ocr > 255) + { + ocr = F_CPU / frequency / 2 / 128 - 1; +#if defined(__AVR_ATmega128__) + prescalar = TIMER_CLK_DIV1024; +#else + prescalar = TIMERRTC_CLK_DIV1024; +#endif + } + + if (ocr > 255) + { + ocr = F_CPU / frequency / 2 / 256 - 1; +#if defined(__AVR_ATmega128__) + prescalar = TIMER_CLK_DIV256; +#else + prescalar = TIMERRTC_CLK_DIV256; +#endif + if (ocr > 255) + { + // can't do any better than /1024 + ocr = F_CPU / frequency / 2 / 1024 - 1; +#if defined(__AVR_ATmega128__) + prescalar = TIMER_CLK_DIV1024; +#else + prescalar = TIMERRTC_CLK_DIV1024; +#endif + } + } + } + } + + timer2SetPrescaler(prescalar); + } + else + { + // two choices for the 16 bit timers: ck/1 or ck/64 + ocr = F_CPU / frequency / 2 - 1; + prescalar = TIMER_CLK_DIV1; + if (ocr > 0xffff) + { + ocr = F_CPU / frequency / 2 / 64 - 1; + prescalar = TIMER_CLK_DIV64; + } + + if (_timer == 1) + timer1SetPrescaler(prescalar); + else if (_timer == 3) + timer3SetPrescaler(prescalar); +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) + else if (_timer == 4) + timer4SetPrescaler(prescalar); + else if (_timer == 5) + timer5SetPrescaler(prescalar); +#endif + + } + + + // Calculate the toggle count + if (duration > 0) + toggle_count = 2 * frequency * duration / 1000; + else + toggle_count = -1; + + // Set the OCR for the given timer, + // set the toggle count, + // then turn on the interrupts + switch (_timer) + { + case 1: + OCR1A = ocr; + timer1_toggle_count = toggle_count; + timerAttach(TIMER1OUTCOMPAREA_INT, ToneTimer1Service); +#if defined(__AVR_ATmega128__) + TIMSK |= _BV(OCIE1A); +#else + TIMSK1 |= _BV(OCIE1A); +#endif + //bitWrite(TIMSK1, OCIE1A, 1); + break; + case 2: +#if defined(__AVR_ATmega128__) + OCR2 = ocr; +#else + OCR2A = ocr; +#endif + timer2_toggle_count = toggle_count; +#if defined(__AVR_ATmega128__) + timerAttach(TIMER2OUTCOMPARE_INT, ToneTimer2Service); + TIMSK |= _BV(OCIE2); +#else + timerAttach(TIMER2OUTCOMPAREA_INT, ToneTimer2Service); + TIMSK2 |= _BV(OCIE2A); +#endif + + //bitWrite(TIMSK2, OCIE2A, 1); + break; + case 3: + OCR3A = ocr; + timer3_toggle_count = toggle_count; + timerAttach(TIMER3OUTCOMPAREA_INT, ToneTimer2Service); +#if defined(__AVR_ATmega128__) + ETIMSK |= _BV(OCIE3A); +#else + TIMSK3 |= _BV(OCIE3A); +#endif + //bitWrite(TIMSK3, OCIE3A, 1); + break; +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) + case 4: + OCR4A = ocr; + timer4_toggle_count = toggle_count; + timerAttach(TIMER4OUTCOMPAREA_INT, ToneTimer4Service); + TIMSK4 |= _BV(OCIE4A); + //bitWrite(TIMSK4, OCIE4A, 1); + break; + case 5: + OCR5A = ocr; + timer5_toggle_count = toggle_count; + timerAttach(TIMER5OUTCOMPAREA_INT, ToneTimer5Service); + TIMSK5 |= _BV(OCIE5A); + //bitWrite(TIMSK5, OCIE5A, 1); + break; +#endif + + } + } +} + + +void noTone(uint8_t _pin) +{ + int8_t _timer = -1; + + for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { + if (tone_pins[i] == _pin) { + _timer = pgm_read_byte(tone_pin_to_timer_PGM + i); + tone_pins[i] = 255; + } + } + + switch (_timer) + { +#if defined(__AVR_ATmega128__) + case 1: + TIMSK &= ~_BV(OCIE1A); + timerDetach(TIMER1OUTCOMPAREA_INT); + //bitWrite(TIMSK1, OCIE1A, 0); + break; + case 2: + TIMSK &= ~_BV(OCIE2); + timerDetach(TIMER2OUTCOMPARE_INT); + //bitWrite(TIMSK2, OCIE2A, 0); + break; + case 3: + ETIMSK &= ~_BV(OCIE3A); + timerDetach(TIMER3OUTCOMPAREA_INT); + break; +#else + case 1: + TIMSK1 = 0; + timerDetach(TIMER1OUTCOMPAREA_INT); + break; + case 2: + TIMSK2 = 0; + timerDetach(TIMER2OUTCOMPAREA_INT); + break; + case 3: + TIMSK3 = 0; + timerDetach(TIMER3OUTCOMPAREA_INT); + break; + case 4: + TIMSK4 = 0; + timerDetach(TIMER4OUTCOMPAREA_INT); + break; + case 5: + TIMSK5 = 0; + timerDetach(TIMER5OUTCOMPAREA_INT); + break; +#endif + default: + break; + } + + digitalWrite(_pin, LOW); +} + + +void ToneTimer1Service() //ISR(TIMER1_COMPA_vect) +{ + if (timer1_toggle_count != 0) + { + // toggle the pin + *timer1_pin_port ^= _BV(timer1_pin_mask); + + if (timer1_toggle_count > 0) + timer1_toggle_count--; + } + else + { +#if defined(__AVR_ATmega128__) + TIMSK &= ~_BV(OCIE1A); +#else + TIMSK1 = 0; // disable the interrupt +#endif + *timer1_pin_port &= ~_BV(timer1_pin_mask); // keep pin low after stop + } +} + + +void ToneTimer2Service() //ISR(TIMER2_COMPA_vect) +{ + + if (timer2_toggle_count != 0) + { + // toggle the pin + *timer2_pin_port ^= _BV(timer2_pin_mask); + + if (timer2_toggle_count > 0) + timer2_toggle_count--; + } + else + { +#if defined(__AVR_ATmega128__) + TIMSK &= ~_BV(OCIE2); +#else + TIMSK2 = 0; // disable the interrupt +#endif + *timer2_pin_port &= ~_BV(timer2_pin_mask); // keep pin low after stop + } +} + + + +void ToneTimer3Service() //ISR(TIMER3_COMPA_vect) +{ + if (timer3_toggle_count != 0) + { + // toggle the pin + *timer3_pin_port ^= _BV(timer3_pin_mask); + + if (timer3_toggle_count > 0) + timer3_toggle_count--; + } + else + { +#if defined(__AVR_ATmega128__) + ETIMSK &= ~_BV(OCIE3A); +#else + TIMSK3 = 0; // disable the interrupt +#endif + *timer3_pin_port &= ~_BV(timer3_pin_mask); // keep pin low after stop + } +} + +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) +void ToneTimer4Service() //ISR(TIMER4_COMPA_vect) +{ + if (timer4_toggle_count != 0) + { + // toggle the pin + *timer4_pin_port ^= _BV(timer4_pin_mask); + + if (timer4_toggle_count > 0) + timer4_toggle_count--; + } + else + { + TIMSK4 = 0; // disable the interrupt + *timer4_pin_port &= ~_BV(timer4_pin_mask); // keep pin low after stop + } +} + +void ToneTimer5Service() //ISR(TIMER5_COMPA_vect) +{ + if (timer5_toggle_count != 0) + { + // toggle the pin + *timer5_pin_port ^= _BV(timer5_pin_mask); + + if (timer5_toggle_count > 0) + timer5_toggle_count--; + } + else + { + TIMSK5 = 0; // disable the interrupt + *timer5_pin_port &= ~_BV(timer5_pin_mask); // keep pin low after stop + } +} + +#endif diff --git a/WApplet.c b/WApplet.c @@ -0,0 +1,380 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +/************************************************************* + * Includes + *************************************************************/ + +#include <inttypes.h> +#include <stdlib.h> +#include <avr/io.h> +#include <avr/interrupt.h> + +#include "WProgram.h" + +/************************************************************* + * Delay & Timer + *************************************************************/ + +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + + +//volatile unsigned long mscount; +//volatile unsigned long timecount; + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + +extern uint8_t pwmpins[]; + +// Previuosly called initTimer, initializes main clock used for delay functions +void initWiring(void) +{ +//// TIFR |= _BV(OCIE0); +//// TCCR0 = _BV(WGM01)|_BV(CS02)|_BV(CS00); /* CTC, prescale = 128 */ +//// TCNT0 = 0; +//// TIMSK |= _BV(OCIE0); /* enable output compare interrupt */ +//// OCR0 = 125; /* match in 1 ms */ + +// TIFR |= _BV(OCIE0)|_BV(TOIE0); +// TIMSK |= _BV(OCIE0); /* enable output compare interrupt */ +// TIMSK &= ~_BV(TOIE0); /* disable overflow interrupt */ +// ASSR |= _BV(AS0); /* use asynchronous clock source */ +// TCNT0 = 0; +// OCR0 = 32; /* match in 0.9765625 ms */ +// TCCR0 = _BV(WGM01) | _BV(CS00); /* CTC, no prescale */ +// while (ASSR & 0x07) +// ; +// TIFR |= _BV(OCIE0)|_BV(TOIE0); + timer0Init(); +} + +/* +ISR(SIG_OUTPUT_COMPARE0) { + mscount++; + timecount++; +} +*/ + + +ISR(TIMER0_OVF_vect) { + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if(f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + + +unsigned long millis() { + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; + //return timecount; +} + + +unsigned long micros() { + unsigned long m, t; + uint8_t oldSREG = SREG; + + cli(); + m = timer0_overflow_count; + t = TCNT0; + +#ifdef TIFR0 + if ((TIFR0 & _BV(TOV0)) && (t < 255)) + m++; +#else + if ((TIFR & _BV(TOV0)) && (t < 255)) + m++; +#endif + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + + +void delay(unsigned long ms) { + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + if (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +// unsigned long start = millis(); + +// while (millis() - start < ms) +// ; +} + +/* Delay for the given number of microseconds. + * From D.Mellis for Arduino + * Assumes a 16 MHz clock. + * Disables interrupts, disrupts millis() if used frequently + * note: digitalWrite() executes in 2.5 microseconds + */ + +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); + +#if F_CPU >= 16000000L + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + if (--us == 0) + return; + if (--us == 0) + return; + us <<= 1; + us--; +#endif + // disable interrupts, otherwise the timer 0 overflow interrupt that + // tracks milliseconds will make us delay longer than we want. + //cli(); + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); + + // reenable interrupts. + //sei(); +} + + +/************************************************************* + * Digital I/O + *************************************************************/ + +const uint8_t pins[8] = { + WPIN0, WPIN1, WPIN2, WPIN3, WPIN4, WPIN5, WPIN6, WPIN7 +}; + +volatile uint8_t * ports[7] = { + &PORTD, &PORTC, &PORTA, &PORTB, &PORTE, &PORTF, &PORTG +}; + +volatile uint8_t * portsddr[7] = { + &DDRD, &DDRC, &DDRA, &DDRB, &DDRE, &DDRF, &DDRG +}; + +volatile uint8_t * portspin[7] = { + &PIND, &PINC, &PINA, &PINB, &PINE, &PINF, &PING +}; + +void pinMode(uint8_t pin, uint8_t mode) { + if(mode == OUTPUT) { + uint8_t oldSREG = SREG; + cli(); + *portsddr[pin/8] |= pins[pin%8]; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *portsddr[pin/8] &= ~pins[pin%8]; + SREG = oldSREG; + } +} + +inline uint8_t digitalRead(uint8_t pin) { + if(*portspin[pin/8] & pins[pin%8]) + return HIGH; + return LOW; +} + +/* + * Michael Margolis + * this version is based on Paul Stoffregen's Nov13 2009 submission to the + * Arduino developers list + */ +//inline void digitalWrite(uint8_t, uint8_t) __attribute__((always_inline, unused)); +/*inline void digitalWrite(uint8_t P, uint8_t V) +{ + (__builtin_constant_p(P) && __builtin_constant_p(V)) + ? bitWrite(*((volatile unsigned char *) digitalPinToPortReg(P)), digitalPinToBit(P), V) + : _digitalWrite(P, V); +} +*/ + +void _digitalWrite(uint8_t pin, uint8_t val) { + if(val == HIGH) { + uint8_t oldSREG = SREG; + cli(); + *ports[pin/8] |= pins[pin%8]; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *ports[pin/8] &= ~pins[pin%8]; + SREG = oldSREG; + } +} + + +void portMode(uint8_t port, uint8_t mode) { + if(mode == OUTPUT) { + *portsddr[port] = 0xff; + } else { + *portsddr[port] = 0x00; + } +} + +uint8_t portRead(uint8_t port) { + return *portspin[port]; +} + +void portWrite(uint8_t port, uint8_t val) { + *ports[port] = val; +} + + +/************************************************************* + * Analog Input + *************************************************************/ + +uint8_t adcFirstTime = true; +uint8_t adcLastPin = 0xFF; //save last pin + +void adcInit() { + DDRF = 0x00; + PORTF = 0x00; + ADMUX = _BV(REFS0); +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + ADCSRA = _BV(ADEN)|_BV(ADSC)|_BV(ADATE)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0); + ADCSRB &= ~(_BV(ADTS2)|_BV(ADTS1)|_BV(ADTS0)); +#else + ADCSR = _BV(ADEN)|_BV(ADSC)|_BV(ADFR)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0); +#endif +} + + +int analogRead(uint8_t pin) { + if(adcFirstTime == true) { + adcInit(); + adcFirstTime = false; + } + +// fixes analogRead bug when reading multiple analog inputs +// thanks to Bjoern Hartman bjoern@stanford.edu + + if(pin == adcLastPin) { +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + ADCSRA |= _BV(ADIF); //"start": set ADIF to interrupt flag + while((ADCSRA & _BV(ADIF)) == 0) ; //wait until conversion completes (ADIF set to 0) +#else + ADCSR |= _BV(ADIF); //"start": set ADIF to interrupt flag + while((ADCSR & _BV(ADIF)) == 0) ; //wait until conversion completes (ADIF set to 0) +#endif + } else { + adcLastPin=pin; //save new channel + ADMUX = (ADMUX & 0xe0) | (pin & 0x07); //set new conversion channel +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + ADCSRA |= _BV(ADIF); //"start": set ADIF to interrupt flag + while((ADCSRA & _BV(ADIF)) == 0) ; //wait until conversion completes (ADIF set to 0) + //now do it again since we don't get correct channel until 2nd conversion + ADCSRA |= _BV(ADIF); //"start" again: set ADIF to interrupt flag + while((ADCSRA & _BV(ADIF)) == 0) ; //wait until 2nd conversion completes +#else + ADCSR |= _BV(ADIF); //"start": set ADIF to interrupt flag + while((ADCSR & _BV(ADIF)) == 0) ; //wait until conversion completes (ADIF set to 0) + //now do it again since we don't get correct channel until 2nd conversion + ADCSR |= _BV(ADIF); //"start" again: set ADIF to interrupt flag + while((ADCSR & _BV(ADIF)) == 0) ; //wait until 2nd conversion completes +#endif + } + return ADC; +} + +/* +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val) { + int i; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } +} +*/ + +/************************************************************* + * Main Program + *************************************************************/ +/* +extern void setup(void); +extern void loop(void); + +int main(void) { + //initWiring(); + portMode(3, OUTPUT); + portMode(4, OUTPUT); + sei(); + setup(); + for(;;) { + loop(); + } +} +*/ diff --git a/WCharacter.h b/WCharacter.h @@ -0,0 +1,169 @@ +/* + WCharacter.h - Character utility functions for Wiring & Arduino + Copyright (c) 2010 Hernando Barragan. 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 Character_h +#define Character_h + + +#include "WProgram.h" + +// WCharacter.h prototypes +inline boolean isAlphaNumeric(int c) __attribute__((always_inline)); +inline boolean isAlpha(int c) __attribute__((always_inline)); +inline boolean isAscii(int c) __attribute__((always_inline)); +inline boolean isWhitespace(int c) __attribute__((always_inline)); +inline boolean isControl(int c) __attribute__((always_inline)); +inline boolean isDigit(int c) __attribute__((always_inline)); +inline boolean isGraph(int c) __attribute__((always_inline)); +inline boolean isLowerCase(int c) __attribute__((always_inline)); +inline boolean isPrintable(int c) __attribute__((always_inline)); +inline boolean isPunct(int c) __attribute__((always_inline)); +inline boolean isSpace(int c) __attribute__((always_inline)); +inline boolean isUpperCase(int c) __attribute__((always_inline)); +inline boolean isHexadecimalDigit(int c) __attribute__((always_inline)); +inline int toAscii(int c) __attribute__((always_inline)); +inline int toLowerCase(int c) __attribute__((always_inline)); +inline int toUpperCase(int c)__attribute__((always_inline)); + + +// Checks for an alphanumeric character. +// It is equivalent to (isalpha(c) || isdigit(c)). +inline boolean isAlphaNumeric(int c) +{ + return ( isalnum(c) == 0 ? false : true); +} + + +// Checks for an alphabetic character. +// It is equivalent to (isupper(c) || islower(c)). +inline boolean isAlpha(int c) +{ + return ( isalpha(c) == 0 ? false : true); +} + + +// Checks whether c is a 7-bit unsigned char value +// that fits into the ASCII character set. +inline boolean isAscii(int c) +{ + return ( isascii (c) == 0 ? false : true); +} + + +// Checks for a blank character, that is, a space or a tab. +inline boolean isWhitespace(int c) +{ + return ( isblank (c) == 0 ? false : true); +} + + +// Checks for a control character. +inline boolean isControl(int c) +{ + return ( iscntrl (c) == 0 ? false : true); +} + + +// Checks for a digit (0 through 9). +inline boolean isDigit(int c) +{ + return ( isdigit (c) == 0 ? false : true); +} + + +// Checks for any printable character except space. +inline boolean isGraph(int c) +{ + return ( isgraph (c) == 0 ? false : true); +} + + +// Checks for a lower-case character. +inline boolean isLowerCase(int c) +{ + return (islower (c) == 0 ? false : true); +} + + +// Checks for any printable character including space. +inline boolean isPrintable(int c) +{ + return ( isprint (c) == 0 ? false : true); +} + + +// Checks for any printable character which is not a space +// or an alphanumeric character. +inline boolean isPunct(int c) +{ + return ( ispunct (c) == 0 ? false : true); +} + + +// Checks for white-space characters. For the avr-libc library, +// these are: space, formfeed (’\f’), newline (’\n’), carriage +// return (’\r’), horizontal tab (’\t’), and vertical tab (’\v’). +inline boolean isSpace(int c) +{ + return ( isspace (c) == 0 ? false : true); +} + + +// Checks for an uppercase letter. +inline boolean isUpperCase(int c) +{ + return ( isupper (c) == 0 ? false : true); +} + + +// Checks for a hexadecimal digits, i.e. one of 0 1 2 3 4 5 6 7 +// 8 9 a b c d e f A B C D E F. +inline boolean isHexadecimalDigit(int c) +{ + return ( isxdigit (c) == 0 ? false : true); +} + + +// Converts c to a 7-bit unsigned char value that fits into the +// ASCII character set, by clearing the high-order bits. +inline int toAscii(int c) +{ + return toascii (c); +} + + +// Warning: +// Many people will be unhappy if you use this function. +// This function will convert accented letters into random +// characters. + +// Converts the letter c to lower case, if possible. +inline int toLowerCase(int c) +{ + return tolower (c); +} + + +// Converts the letter c to upper case, if possible. +inline int toUpperCase(int c) +{ + return toupper (c); +} + +#endif diff --git a/WConstants.h b/WConstants.h @@ -0,0 +1,341 @@ +/* + WConstants.h - Main definitions file for Wiring + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-2010 Hernando Barragan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef WConstants_h +#define WConstants_h + +// Wiring API version for libraries +// this is also defined at compile-time +#ifndef WIRING +#define WIRING 27 +#endif + +// passed in at compile-time +#ifndef F_CPU +#define F_CPU 16000000L +#endif + +// passed in at compile-time +#ifndef CPU_FREQ +#define CPU_FREQ 16000000L +#endif + +#define LOW 0x0 +#define HIGH 0x1 + +#define INPUT 0x0 +#define OUTPUT 0x1 + +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 + +#define LSBFIRST 0x0 +#define MSBFIRST 0x1 + +#define true 0x1 +#define false 0x0 +#define null NULL + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 +#define BYTE 0 + +#define PI (3.1415927) +#define TWO_PI (6.2831854) +#define HALF_PI (1.57079) +#define EPSILON (0.0001) +#define DEG_TO_RAD (0.01745329) +#define RAD_TO_DEG (57.2957786) + +#define int(x) ((int)(x)) +#define char(x) ((char)(x)) +#define long(x) ((long)(x)) +#define byte(x) ((uint8_t)(x)) +#define float(x) ((float)(x)) +#define boolean(x) ((uint8_t)((x)==0?0:1)) + +#define interrupts() sei() +#define noInterrupts() cli() + +// undefine stdlib's abs if encountered +#ifdef abs +#undef abs +#endif + +#define sq(x) ((x)*(x)) +#define abs(x) ((x)>0?(x):-(x)) +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) + +#define bit(x) (1<<(x)) +#define setBits(x, y) ((x)|=(y)) +#define clearBits(x, y) ((x)&=(~(y))) +#define setBit(x, y) setBits((x), (bit((y)))) +#define clearBit(x, y) clearBits((x), (bit((y)))) + +#define bitsSet(x,y) (((x) & (y)) == (y)) +#define bitsClear(x,y) (((x) & (y)) == 0) + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + +#define lowByte(x) ((x) & 0x00ff) +#define highByte(x) ((x)>>8) + + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) +#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() ) + +/* + * Michael Margolis + * this version is based on Paul Stoffregen's Nov13 2009 submission to the + * Arduino developers list + */ +#define digitalPinToPortReg(P) \ + (((P) >= 0 && (P) <= 7) ? &PORTD : \ + (((P) >= 8 && (P) <= 15) ? &PORTC : \ + (((P) >= 16 && (P) <= 23) ? &PORTA : \ + (((P) >= 24 && (P) <= 31) ? &PORTB : \ + (((P) >= 32 && (P) <= 39) ? &PORTE : \ + (((P) >= 40 && (P) <= 47) ? &PORTF : &PORTG)))))) +#define digitalPinToBit(P) ((P) & 7) + +// macros added for compatibility +#define digitalPinToBitMask(P) ((P) & 7) +#define digitalPinToPort(P) \ + (((P) >= 0 && (P) <= 7) ? 0 : \ + (((P) >= 8 && (P) <= 15) ? 1 : \ + (((P) >= 16 && (P) <= 23) ? 2 : \ + (((P) >= 24 && (P) <= 31) ? 3 : \ + (((P) >= 32 && (P) <= 39) ? 4 : \ + (((P) >= 40 && (P) <= 47) ? 5 : 6)))))) +#define portOutputRegister(P) \ + (((P) == 0 ) ? &PORTD : \ + (((P) == 1 ) ? &PORTC : \ + (((P) == 2 ) ? &PORTA : \ + (((P) == 3 ) ? &PORTB : \ + (((P) == 4 ) ? &PORTE : \ + (((P) == 5 ) ? &PORTF : &PORTG)))))) +#define portInputRegister(P) \ + (((P) == 0 ) ? &PIND : \ + (((P) == 1 ) ? &PINC : \ + (((P) == 2 ) ? &PINA : \ + (((P) == 3 ) ? &PINB : \ + (((P) == 4 ) ? &PINE : \ + (((P) == 5 ) ? &PINF : &PING)))))) +#define portModeRegister(P) \ + (((P) == 0 ) ? &DDRD : \ + (((P) == 1 ) ? &DDRC : \ + (((P) == 2 ) ? &DDRA : \ + (((P) == 3 ) ? &DDRB : \ + (((P) == 4 ) ? &DDRE : \ + (((P) == 5 ) ? &DDRF : &DDRG)))))) + + +#define WPIN0 (1<<0) +#define WPIN1 (1<<1) +#define WPIN2 (1<<2) +#define WPIN3 (1<<3) +#define WPIN4 (1<<4) +#define WPIN5 (1<<5) +#define WPIN6 (1<<6) +#define WPIN7 (1<<7) + +#define WPWMPIN5 (1<<5) // PINB5 +#define WPWMPIN4 (1<<6) // PINB6 +#define WPWMPIN3 (1<<7) // PINB7 +#define WPWMPIN2 (1<<3) // PINE3 +#define WPWMPIN1 (1<<4) // PINE4 +#define WPWMPIN0 (1<<5) // PINE5 + +#define WPORTA PORTA +#define WPORTB PORTB +#define WPORTC PORTC +#define WPORTD PORTD +#define WPORTE PORTE +#define WPORTF PORTF +#define WPORTG PORTG + +#define WPINA PINA +#define WPINB PINB +#define WPINC PINC +#define WPIND PIND +#define WPINE PINE +#define WPINF PINF +#define WPING PING + +#define WDDRA DDRA +#define WDDRB DDRB +#define WDDRC DDRC +#define WDDRD DDRD +#define WDDRE DDRE +#define WDDRF DDRF +#define WDDRG DDRG + + +/* + * Internal constants for timer management + */ +#define TIMER0OVERFLOW_INT 0 +#define TIMER0OUTCOMPARE_INT 1 +#define TIMER0OUTCOMPAREA_INT 1 +#define TIMER0OUTCOMPAREB_INT 2 +#define TIMER1OVERFLOW_INT 3 +#define TIMER1OUTCOMPAREA_INT 4 +#define TIMER1OUTCOMPAREB_INT 5 +#define TIMER1OUTCOMPAREC_INT 6 +#define TIMER1INPUTCAPTURE_INT 7 +#define TIMER2OVERFLOW_INT 8 +#define TIMER2OUTCOMPARE_INT 9 +#define TIMER2OUTCOMPAREA_INT 9 +#define TIMER2OUTCOMPAREB_INT 10 +#define TIMER3OVERFLOW_INT 11 +#define TIMER3OUTCOMPAREA_INT 12 +#define TIMER3OUTCOMPAREB_INT 13 +#define TIMER3OUTCOMPAREC_INT 14 +#define TIMER3INPUTCAPTURE_INT 15 + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#define TIMER4OVERFLOW_INT 16 +#define TIMER4OUTCOMPAREA_INT 17 +#define TIMER4OUTCOMPAREB_INT 18 +#define TIMER4OUTCOMPAREC_INT 19 +#define TIMER5OVERFLOW_INT 20 +#define TIMER5OUTCOMPAREA_INT 21 +#define TIMER5OUTCOMPAREB_INT 22 +#define TIMER5OUTCOMPAREC_INT 23 +#endif + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#define TIMER_NUM_INTERRUPTS 24 +#else +#define TIMER_NUM_INTERRUPTS 16 +#endif + + +/* + * Timer prescaler constants for normal timers + * on atmega128 Timer2, Timer1, Timer3 + * on atmega1281 and atmega2561 Timer1, Timer2, Timer3, Timer4 and Timer5 + */ +#define TIMER_CLK_STOP 0x00 +#define TIMER_CLK_DIV1 0x01 +#define TIMER_CLK_DIV8 0x02 +#define TIMER_CLK_DIV64 0x03 +#define TIMER_CLK_DIV256 0x04 +#define TIMER_CLK_DIV1024 0x05 +#define TIMER_CLK_T_FALL 0x06 +#define TIMER_CLK_T_RISE 0x07 +#define TIMER_PRESCALE_MASK 0x07 + +/* + * Timer prescaler constants for RTC type timers + * on atmega128 Timer0 + * on atmega1281 and atmega2561 Timer2 + */ +#define TIMERRTC_CLK_STOP 0x00 +#define TIMERRTC_CLK_DIV1 0x01 +#define TIMERRTC_CLK_DIV8 0x02 +#define TIMERRTC_CLK_DIV32 0x03 +#define TIMERRTC_CLK_DIV64 0x04 +#define TIMERRTC_CLK_DIV128 0x05 +#define TIMERRTC_CLK_DIV256 0x06 +#define TIMERRTC_CLK_DIV1024 0x07 +#define TIMERRTC_PRESCALE_MASK 0x07 + + +/* + * Predefined prescalers for timers Timer0, Timer1, Timer2, Timer3, Timer4 and Timer5 + */ +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#define TIMER0PRESCALE TIMER_CLK_DIV64 +#else +#define TIMER0PRESCALE TIMERRTC_CLK_DIV64 +#endif + +#define TIMER1PRESCALE TIMER_CLK_DIV64 + +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#define TIMER2PRESCALE TIMERRTC_CLK_DIV8 +#else +#define TIMER2PRESCALE TIMER_CLK_DIV8 +#endif + +#define TIMER3PRESCALE TIMER_CLK_DIV64 + +#if defined(__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#define TIMER4PRESCALE TIMER_CLK_DIV64 +#define TIMER5PRESCALE TIMER_CLK_DIV64 +#endif + + +/* + * External interrupts constants + */ +#define EXTERNAL_INT_0 0 +#define EXTERNAL_INT_1 1 +#define EXTERNAL_INT_2 2 +#define EXTERNAL_INT_3 3 +#define EXTERNAL_INT_4 4 +#define EXTERNAL_INT_5 5 +#define EXTERNAL_INT_6 6 +#define EXTERNAL_INT_7 7 + +#define EXTERNAL_NUM_INTERRUPTS 8 + +/* + * Power management constants + */ +#define POWER_ADC 0 +#define POWER_SPI 1 +#define POWER_WIRE 2 +#define POWER_TIMER0 3 +#define POWER_TIMER1 4 +#define POWER_TIMER2 5 +#define POWER_TIMER3 6 +#define POWER_TIMER4 7 +#define POWER_TIMER5 8 +#define POWER_SERIAL0 9 +#define POWER_SERIAL1 10 +#define POWER_SERIAL2 11 +#define POWER_SERIAL3 12 +#define POWER_ALL 13 + + +/* + * typedefs for extra types + */ +typedef uint8_t byte; +typedef uint8_t boolean; +typedef void (*voidFuncPtr)(void); + +#endif + diff --git a/WInterrupts.c b/WInterrupts.c @@ -0,0 +1,163 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include <inttypes.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include <stdio.h> + +#include "WProgram.h" + +static volatile voidFuncPtr intFunc[EXTERNAL_NUM_INTERRUPTS]; +static volatile voidFuncPtr spiIntFunc; +// volatile static voidFuncPtr twiIntFunc; + +/* +modes can be +LOW Trigger on LOW level +FALLING Trigger on FALLING edge +RISING Trigger on RISING edge +*/ + + +void interruptMode(uint8_t n, uint8_t mode) { + switch(n) { + case 0: + EICRA = (EICRA & ~(_BV(ISC00) | _BV(ISC01))) | (mode << ISC00); + EIMSK |= _BV(INT0); + break; + case 1: + EICRA = (EICRA & ~(_BV(ISC10) | _BV(ISC11))) | (mode << ISC10); + EIMSK |= _BV(INT1); + break; + case 2: + EICRA = (EICRA & ~(_BV(ISC20) | _BV(ISC21))) | (mode << ISC20); + EIMSK |= _BV(INT2); + break; + case 3: + EICRA = (EICRA & ~(_BV(ISC30) | _BV(ISC31))) | (mode << ISC30); + EIMSK |= _BV(INT3); + break; + case 4: + EICRB = (EICRB & ~(_BV(ISC40) | _BV(ISC41))) | (mode << ISC40); + EIMSK |= _BV(INT4); + break; + case 5: + EICRB = (EICRB & ~(_BV(ISC50) | _BV(ISC51))) | (mode << ISC50); + EIMSK |= _BV(INT5); + break; + case 6: + EICRB = (EICRB & ~(_BV(ISC60) | _BV(ISC61))) | (mode << ISC60); + EIMSK |= _BV(INT6); + break; + case 7: + EICRB = (EICRB & ~(_BV(ISC70) | _BV(ISC71))) | (mode << ISC70); + EIMSK |= _BV(INT7); + break; + default: + break; + } +} + + +void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), uint8_t mode) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + intFunc[interruptNum] = userFunc; + interruptMode(interruptNum, mode); + } +} + +void detachInterrupt(uint8_t interruptNum) { + if(interruptNum < EXTERNAL_NUM_INTERRUPTS) { + EIMSK &= ~_BV(interruptNum); + intFunc[interruptNum] = 0; + } +} + +void attachInterruptSPI(void (*userFunc)(void) ) { + spiIntFunc = userFunc; +} + +void detachInterruptSPI(void) { + spiIntFunc = 0; +} + +/* +void attachInterruptTwi(void (*userFunc)(void) ) { + twiIntFunc = userFunc; +} +*/ + +ISR(INT0_vect) { + if(intFunc[EXTERNAL_INT_0]) + intFunc[EXTERNAL_INT_0](); +} + +ISR(INT1_vect) { + if(intFunc[EXTERNAL_INT_1]) + intFunc[EXTERNAL_INT_1](); +} + +ISR(INT2_vect) { + if(intFunc[EXTERNAL_INT_2]) + intFunc[EXTERNAL_INT_2](); +} + +ISR(INT3_vect) { + if(intFunc[EXTERNAL_INT_3]) + intFunc[EXTERNAL_INT_3](); +} + +ISR(INT4_vect) { + if(intFunc[EXTERNAL_INT_4]) + intFunc[EXTERNAL_INT_4](); +} + +ISR(INT5_vect) { + if(intFunc[EXTERNAL_INT_5]) + intFunc[EXTERNAL_INT_5](); +} + +ISR(INT6_vect) { + if(intFunc[EXTERNAL_INT_6]) + intFunc[EXTERNAL_INT_6](); +} + +ISR(INT7_vect) { + if(intFunc[EXTERNAL_INT_7]) + intFunc[EXTERNAL_INT_7](); +} + +ISR(SPI_STC_vect) { + if(spiIntFunc) + spiIntFunc(); +} + +/* +ISR(SIG_2WIRE_SERIAL) { + if(twiIntFunc) + twiIntFunc(); +} +*/ + diff --git a/WMath.cpp b/WMath.cpp @@ -0,0 +1,62 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + WMath.cpp: Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "WProgram.h" + + +void randomSeed(unsigned int seed) +{ + if (seed != 0) { + srandom(seed); + } +} + + +float random(float howbig) +{ + float value; + if (howbig == 0){ + return 0; + } + value = rand(); + value = value / RAND_MAX; + return value * howbig; +} + +float random(float howsmall, float howbig) +{ + if(howsmall >= howbig){ + return howsmall; + } + float diff = howbig - howsmall; + return random(diff) + howsmall; +} + +float map(float value, float istart, float istop, float ostart, float ostop) { + return ostart + (ostop - ostart) * ((value - istart) / (istop - istart)); +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char highByte, unsigned char lowByte) { return (highByte << 8) | lowByte; } + + diff --git a/WMemory.cpp b/WMemory.cpp @@ -0,0 +1,115 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2009 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "WProgram.h" + +void * operator new(size_t size) +{ + return malloc(size); +} + +void operator delete(void * ptr) +{ + if (ptr) + free(ptr); +} + +void * operator new[](size_t size) +{ + return malloc(size); +} + +void operator delete[](void * ptr) +{ + if(ptr) + free(ptr); +} + + +int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);}; +void __cxa_guard_release (__guard *g) {*(char *)g = 1;}; +void __cxa_guard_abort (__guard *) {}; +void __cxa_pure_virtual(void) {}; + + +int splitString( const String &what, int delim, Vector<long> &splits ) +{ + what.trim(); + splits.removeAllElements(); + const char *chars = what._buffer; + int splitCount = 0; //1; + for (int i = 0; i < what.length(); i++) { + if (chars[i] == delim) splitCount++; + } + if (splitCount == 0) { + splits.addElement(atol(what._buffer)); + return 1; + } + + int pieceCount = splitCount + 1; + + int splitIndex = 0; + int startIndex = 0; + for (int i = 0; i < what.length(); i++) { + if (chars[i] == delim) { + splits.addElement(atol(what.substring(startIndex, i)._buffer)); + splitIndex++; + startIndex = i + 1; + } + } + splits.addElement(atol(what.substring(startIndex, what.length())._buffer)); + + return pieceCount; +} + +int splitString( const String &what, int delim, Vector<int> &splits ) +{ + what.trim(); + splits.removeAllElements(); + const char *chars = what._buffer; + int splitCount = 0; //1; + for (int i = 0; i < what.length(); i++) { + if (chars[i] == delim) splitCount++; + } + if (splitCount == 0) { + splits.addElement(atoi(what._buffer)); + return(1); + } + + int pieceCount = splitCount + 1; + + int splitIndex = 0; + int startIndex = 0; + for (int i = 0; i < what.length(); i++) { + if (chars[i] == delim) { + splits.addElement(atoi(what.substring(startIndex, i)._buffer)); + splitIndex++; + startIndex = i + 1; + } + } + splits.addElement(atoi(what.substring(startIndex, what.length())._buffer)); + + return pieceCount; +} + + diff --git a/WProgram.h b/WProgram.h @@ -0,0 +1,335 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef WPROGRAM_H +#define WPROGRAM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************* + * C Includes + *************************************************************/ + +#include <math.h> +#include <inttypes.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/power.h> +#include "WConstants.h" +#include "Binary.h" + +/************************************************************* + * C Core API Functions + *************************************************************/ + +// timing prototypes +void initWiring(void); +void delay(unsigned long); +void delayMicroseconds(unsigned int); +unsigned long millis(void); +unsigned long micros(void); + +// pin prototypes +void pinMode(uint8_t, uint8_t); +uint8_t digitalRead(uint8_t); +void _digitalWrite(uint8_t, uint8_t); + +/* + * Michael Margolis + * this version is based on Paul Stoffregen's Nov13 2009 submission to the + * Arduino developers list + */ +static inline void digitalWrite(uint8_t, uint8_t) __attribute__((always_inline, unused)); +static inline void digitalWrite(uint8_t P, uint8_t V) +{ + if(__builtin_constant_p(P) && __builtin_constant_p(V)) { + if(V) { + uint8_t oldSREG = SREG; + cli(); + *digitalPinToPortReg(P) |= _BV(digitalPinToBit(P)); + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + *digitalPinToPortReg(P)&= ~ _BV(digitalPinToBit(P)); + SREG = oldSREG; + } + } + else + _digitalWrite(P, V); +} + + +/* + * Power management + */ +static inline void powerEnable(uint8_t) __attribute__((always_inline, unused)); +static inline void powerEnable(uint8_t P) +{ +#if !defined(__AVR_ATmega128__) + switch(P) { + case POWER_ADC: + power_adc_enable(); + break; + case POWER_SPI: + power_spi_enable(); + break; + case POWER_WIRE: + power_twi_enable(); + break; + case POWER_TIMER0: + power_timer0_enable(); + break; + case POWER_TIMER1: + power_timer1_enable(); + break; + case POWER_TIMER2: + power_timer2_enable(); + break; + case POWER_TIMER3: + power_timer3_enable(); + break; + case POWER_TIMER4: + power_timer4_enable(); + break; + case POWER_TIMER5: + power_timer5_enable(); + break; + case POWER_SERIAL0: + power_usart0_enable(); + break; + case POWER_SERIAL1: + power_usart1_enable(); + break; + case POWER_SERIAL2: + power_usart2_enable(); + break; + case POWER_SERIAL3: + power_usart3_enable(); + break; + case POWER_ALL: + power_all_enable(); + default: + break; + } +#endif +} + +static inline void powerDisable(uint8_t) __attribute__((always_inline, unused)); +static inline void powerDisable(uint8_t P) +{ +#if !defined(__AVR_ATmega128__) + switch(P) { + case POWER_ADC: + power_adc_disable(); + break; + case POWER_SPI: + power_spi_disable(); + break; + case POWER_WIRE: + power_twi_disable(); + break; + case POWER_TIMER0: + power_timer0_disable(); + break; + case POWER_TIMER1: + power_timer1_disable(); + break; + case POWER_TIMER2: + power_timer2_disable(); + break; + case POWER_TIMER3: + power_timer3_disable(); + break; + case POWER_TIMER4: + power_timer4_disable(); + break; + case POWER_TIMER5: + power_timer5_disable(); + break; + case POWER_SERIAL0: + power_usart0_disable(); + break; + case POWER_SERIAL1: + power_usart1_disable(); + break; + case POWER_SERIAL2: + power_usart2_disable(); + break; + case POWER_SERIAL3: + power_usart3_disable(); + break; + case POWER_ALL: + power_all_disable(); + default: + break; + } +#endif +} + + +void portMode(uint8_t, uint8_t); +uint8_t portRead(uint8_t); +void portWrite(uint8_t, uint8_t); +int analogRead(uint8_t); +void analogWrite(uint8_t, uint16_t); + +// pulse prototypes +// unsigned long pulseIn(uint8_t, uint8_t); +// void shiftOut(uint8_t, uint8_t, uint8_t, uint8_t); + +// interrupt management prototypes +void attachInterrupt(uint8_t, void (*)(void), uint8_t mode); +void detachInterrupt(uint8_t); +void interruptMode(uint8_t, uint8_t); +void attachInterruptSPI(void (*)(void)); +void detachInterruptSPI(void); + +// timer management prototypes +void timerAttach(uint8_t, void(*userFunc)(void)); +void timerDetach(uint8_t); +void timer0Init(void) __attribute__ ((naked)) __attribute__ ((section (".init3"))); +void timerInit(void); +void timer1Init(void); +void timer2Init(void); +void timer3Init(void); +void timer0SetPrescaler(uint8_t); +void timer1SetPrescaler(uint8_t); +void timer2SetPrescaler(uint8_t); +void timer3SetPrescaler(uint8_t); +uint16_t timer0GetPrescaler(void); +uint16_t timer1GetPrescaler(void); +uint16_t timer2GetPrescaler(void); +uint16_t timer3GetPrescaler(void); + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +void timer4Init(void); +void timer5Init(void); +void timer4SetPrescaler(uint8_t prescale); +void timer5SetPrescaler(uint8_t prescale); +uint16_t timer4GetPrescaler(void); +uint16_t timer5GetPrescaler(void); +#endif + +void timerPause(unsigned short ); +void timer1PWMInit(uint8_t); +void timer1PWMOff(void); +void timer1PWMAOn(void); +void timer1PWMBOn(void); +void timer1PWMCOn(void); +void timer1PWMAOff(void); +void timer1PWMBOff(void); +void timer1PWMCOff(void); +void timer1PWMASet(uint16_t); +void timer1PWMBSet(uint16_t); +void timer1PWMCSet(uint16_t); +void timer3PWMInit(uint8_t); +void timer3PWMOff(void); +void timer3PWMAOn(void); +void timer3PWMBOn(void); +void timer3PWMCOn(void); +void timer3PWMAOff(void); +void timer3PWMBOff(void); +void timer3PWMCOff(void); +void timer3PWMASet(uint16_t); +void timer3PWMBSet(uint16_t); +void timer3PWMCSet(uint16_t); +void pinPWMOn(uint8_t pin); + +extern volatile uint8_t * ports[]; +extern volatile uint8_t * portsddr[]; +extern volatile uint8_t * portspin[]; + +#ifdef __cplusplus +} +#endif + +/************************************************************* + * C++ Core API Functions + *************************************************************/ + +#ifdef __cplusplus +#include "WVector.h" +#include "WString.h" +#include "Print.h" +#include "WCharacter.h" +// WMath.cpp prototypes +float random(float); +float random(float, float); +float map(float, float, float, float, float); +void randomSeed(unsigned int); +unsigned int makeWord(unsigned char, unsigned char); +unsigned int makeWord(unsigned int); +// Shift.cpp +uint16_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t count = 8, uint8_t delayTime = 5); +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint16_t value, uint8_t count = 8, uint8_t delayTime = 5); +// WPulse.cpp prototypes +// Pulse input +unsigned long pulseIn(uint8_t, uint8_t); +unsigned long pulseIn(uint8_t, uint8_t, unsigned long); +// Pulse output +void pulseOut(uint8_t, uint16_t, uint16_t); +void pulseOut(uint8_t, uint16_t); +uint16_t pulseRunning(uint8_t); +void pulseStop(uint8_t); +// WMemory.cpp prototypes +void * operator new(size_t size); +void operator delete(void * ptr); +void * operator new[](size_t size); +void operator delete[](void * ptr); +int splitString( const String &, int , Vector<int> & ); +int splitString( const String &, int, Vector<long> & ); +void tone(uint8_t _pin, unsigned int frequency, long duration = 0); +void noTone(uint8_t _pin); +__extension__ typedef int __guard __attribute__((mode (__DI__))); +extern "C" int __cxa_guard_acquire(__guard *); +extern "C" void __cxa_guard_release (__guard *); +extern "C" void __cxa_guard_abort (__guard *); +extern "C" void __cxa_pure_virtual(void); + +// definitions for analog pins, not a problem in Wiring since +// pins are properly labeled +const static uint8_t A0 = 0; +const static uint8_t A1 = 1; +const static uint8_t A2 = 2; +const static uint8_t A3 = 3; +const static uint8_t A4 = 4; +const static uint8_t A5 = 5; +const static uint8_t A6 = 6; +const static uint8_t A7 = 7; + +// main program prototypes +void setup(void); +void loop(void); +int main(void) __attribute__ ((noreturn)); + +#endif + +#endif + diff --git a/WPulse.cpp b/WPulse.cpp @@ -0,0 +1,501 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + Based on pulse.c by Pascal Stang - Copyright (C) 2000-2002 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +// The pulseOut command will work on PWM output pins 3, 4, 5 + +#include "WProgram.h" + +void pulseT1Init(void); +void pulseT1Off(void); +void pulseT1ASetFreq(uint16_t); +//void pulseT1BSetFreq(uint16_t); +//void pulseT1CSetFreq(uint16_t); +void pulseT1ARun(uint16_t); +//void pulseT1BRun(uint16_t); +//void pulseT1CRun(uint16_t); +void pulseT1AStop(void); +//void pulseT1BStop(void); +//void pulseT1CStop(void); +uint16_t pulseT1ARemaining(void); +//uint16_t pulseT1BRemaining(void); +//uint16_t pulseT1CRemaining(void); +void pulseT1AService(void); +//void pulseT1BService(void); +//void pulseT1CService(void); +void beginPulse(void); +void pulseFrequency(uint8_t, uint16_t); +void pulseRun(uint8_t, uint16_t); +void pulseOut(uint8_t pin, uint16_t freq); +void pulseOut(uint8_t, uint16_t, uint16_t); + +// pulse generation registers +volatile static uint8_t pulseT1AMode; +volatile static int pulseT1ACount; +volatile static uint16_t pulseT1APeriodTics; +//volatile static uint8_t pulseT1BMode; +//volatile static int pulseT1BCount; +//volatile static uint16_t pulseT1BPeriodTics; +//volatile static uint8_t pulseT1CMode; +//volatile static int pulseT1CCount; +//volatile static uint16_t pulseT1CPeriodTics; + +// pulse mode bit definitions +// PULSE_MODE_COUNTED +// if true, the requested number of pulses are output, then output is turned off +// if false, pulses are output continuously +#define PULSE_MODE_CONTINUOUS 0x00 +#define PULSE_MODE_COUNTED 0x01 + + +/************************************************************* + * Pulse Input + *************************************************************/ + +/* Measures the length (in microseconds) of a pulse on the pin + * by Mellis from Arduino for core API compatibility + * State is HIGH or LOW, the type of pulse to measure + * Works on pulses from 10 microseconds to 3 minutes in length + * Must be called at least N microseconds before the start of the pulse + */ +unsigned long pulseIn(uint8_t pin, uint8_t state) { + pulseIn(pin, state, 1000000UL); +} + + +unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout) +{ + // cache the port and bit of the pin in order to speed up the + // pulse width measuring loop and achieve finer resolution. calling + // digitalWrite() instead yields much coarser resolution. + //int r = port_to_input[digitalPinToPort(pin)]; + //int bit = digitalPinToBit(pin); + int r = _SFR_IO_ADDR(*portspin[pin/8]); + int bit = pin % 8; + int mask = 1 << bit; + unsigned long width = 0; + + unsigned long numloops = 0; + unsigned long maxloops = microsecondsToClockCycles(timeout) / 16; + + + // compute the desired bit pattern for the port reading (e.g. set or + // clear the bit corresponding to the pin being read). the !!state + // ensures that the function treats any non-zero value of state as HIGH. + state = (!!state) << bit; + + // wait for any previous pulse to end + while ((_SFR_IO8(r) & mask) == state) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to start + while ((_SFR_IO8(r) & mask) != state) + if (numloops++ == maxloops) + return 0; + + // wait for the pulse to stop + while ((_SFR_IO8(r) & mask) == state) + width++; + + // convert the reading to microseconds. the slower the CPU speed, the + // proportionally fewer iterations of the loop will occur (e.g. a + // 4 MHz clock will yield a width that is one-fourth of that read with + // a 16 MHz clock). each loop was empirically determined to take + // approximately 23/20 of a microsecond with a 16 MHz clock. + return clockCyclesToMicroseconds(width * 10 + 16); //width * (16000000UL / F_CPU) * 20 / 23; +} + + +/************************************************************* + * Pulse Output + *************************************************************/ + + +void pulseOut(uint8_t pin, uint16_t freq) { + pulseOut(pin, freq, 0); +} + + +void pulseT1Init(void) { + + timer1Init(); + + // try to make sure that timer1 is in "normal" mode + // most importantly, turn off PWM mode + timer1PWMOff(); + + TCCR1B |= _BV(WGM12); + + pulseT1AMode = 0; +// pulseT1BMode = 0; +// pulseT1CMode = 0; + + pulseT1ACount = 0; +// pulseT1BCount = 0; +// pulseT1CCount = 0; + + pulseT1APeriodTics = 0x8000; +// pulseT1BPeriodTics = 0x8000; +// pulseT1CPeriodTics = 0x8000; + + timerAttach(TIMER1OUTCOMPAREA_INT, pulseT1AService); +// timerAttach(TIMER1OUTCOMPAREB_INT, pulseT1BService); +// timerAttach(TIMER1OUTCOMPAREC_INT, pulseT1CService); +} + + +void pulseOut(uint8_t pin, uint16_t freq, uint16_t nPulses=0) { + beginPulse(); + pinMode(pin, OUTPUT); + pulseFrequency(pin, freq); + pulseRun(pin, nPulses); +} + + +inline void beginPulse() { + pulseT1Init(); +} + + +inline void endPulse() { + pulseT1Off(); +} + + +void pulseFrequency(uint8_t channel, uint16_t freq) { + switch (channel) { + case 5: + case 29: + //if(channel == 5) + pulseT1ASetFreq(freq); + break; +/* + case 4: + case 30: + //if(channel == 4) + pulseT1BSetFreq(freq); + break; + case 3: + case 31: + //if(channel == 3) + pulseT1CSetFreq(freq); + break; +*/ + default: + break; + } +} + + +void pulseRun(uint8_t channel, uint16_t nPulses) { + switch (channel) { + case 5: + case 29: + pulseT1ARun(nPulses); + break; +/* + case 4: + case 30: + pulseT1BRun(nPulses); + break; + case 3: + case 31: + pulseT1CRun(nPulses); + break; +*/ + default: + break; + } +} + + +void pulseStop(uint8_t channel) { + switch (channel) { + case 5: + case 29: + pulseT1AStop(); + break; +/* case 4: + case 30: + pulseT1BStop(); + break; + case 3: + case 31: + pulseT1CStop(); + break; +*/ + default: + break; + } +} + + +uint16_t pulseRunning(uint8_t channel) { + switch (channel) { + case 5: + case 29: + return pulseT1ARemaining(); + break; +/* case 4: + case 30: + return pulseT1BRemaining(); + break; + case 3: + case 31: + return pulseT1CRemaining(); + break; +*/ + default: + break; + } + return 0; +} + + +void pulseT1Off(void) { + // turns pulse outputs off immediately + + pulseT1ACount = 0; +// pulseT1BCount = 0; +// pulseT1CCount = 0; + + // disconnect OutputCompare action from OC1A pin + TCCR1A &= ~_BV(COM1A1); + TCCR1A &= ~_BV(COM1A0); + + // disconnect OutputCompare action from OC1B pin +// TCCR1A &= ~_BV(COM1B1); +// TCCR1A &= ~_BV(COM1B0); + + // disconnect OutputCompare action from OC1C pin +// TCCR1A &= ~_BV(COM1C1); +// TCCR1A &= ~_BV(COM1C0); + + timerDetach(TIMER1OUTCOMPAREA_INT); +// timerDetach(TIMER1OUTCOMPAREB_INT); +// timerDetach(TIMER1OUTCOMPAREC_INT); +} + + +void pulseT1ASetFreq(uint16_t freqHz) { + // get the current prescaler setting + // calculate how many tics in period/2 + // this is the (timer tic rate)/(2*requested freq) + pulseT1APeriodTics = ((uint32_t)CPU_FREQ/((uint32_t)timer1GetPrescaler()*2*freqHz)); +} + + +/* +void pulseT1BSetFreq(uint16_t freqHz) { + pulseT1BPeriodTics = ((uint32_t)CPU_FREQ/((uint32_t)timer1GetPrescaler()*2*freqHz)); +} + +void pulseT1CSetFreq(uint16_t freqHz) { + pulseT1CPeriodTics = ((uint32_t)CPU_FREQ/((uint32_t)timer1GetPrescaler()*2*freqHz)); +} +*/ + + +void pulseT1ARun(uint16_t nPulses) { + if(nPulses > 0) { + // if the nPulses is non-zero, use "counted" mode + pulseT1AMode = PULSE_MODE_COUNTED; + pulseT1ACount = nPulses<<1; + } + else { + // if nPulses is zero, run forever + pulseT1AMode = PULSE_MODE_CONTINUOUS; + pulseT1ACount = 1<<1; + } + + // set OutputCompare action to toggle OC1A pin + TCCR1A &= ~_BV(COM1A1); // toggle pin + TCCR1A |= _BV(COM1A0); + + //OCR1A = TCNT1 + pulseT1APeriodTics; + + //OCR1A += pulseT1APeriodTics; + OCR1A = pulseT1APeriodTics; + + // enable OutputCompare interrupt +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 |= _BV(OCIE1A); +#else + TIMSK |= _BV(OCIE1A); +#endif +} + + +/* +void pulseT1BRun(uint16_t nPulses) { + if(nPulses > 0) { + pulseT1BMode = PULSE_MODE_COUNTED; + pulseT1BCount = nPulses<<1; + } + else { + pulseT1BMode = PULSE_MODE_CONTINUOUS; + pulseT1BCount = 1<<1; + } + TCCR1A &= ~_BV(COM1B1); + TCCR1A |= _BV(COM1B0); + //OCR1B = TCNT1 + pulseT1BPeriodTics; + + //OCR1B += pulseT1BPeriodTics; + OCR1B = pulseT1BPeriodTics; + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 |= _BV(OCIE1B); +#else + TIMSK |= _BV(OCIE1B); +#endif +} + + +void pulseT1CRun(uint16_t nPulses) { + if(nPulses > 0) { + pulseT1CMode = PULSE_MODE_COUNTED; + pulseT1CCount = nPulses<<1; + } + else { + pulseT1CMode = PULSE_MODE_CONTINUOUS; + pulseT1CCount = 1<<1; + } + TCCR1A &= ~_BV(COM1C1); + TCCR1A |= _BV(COM1C0); + + + //OCR1C += pulseT1CPeriodTics; + OCR1C = pulseT1CPeriodTics; + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 |= _BV(OCIE1C); +#else + ETIMSK |= _BV(OCIE1C); +#endif +} +*/ + + +void pulseT1AStop(void) { + // stop output regardless of remaining pulses or mode + // go to "counted" mode + pulseT1AMode = PULSE_MODE_COUNTED; + pulseT1ACount = 0; +} + + +/* +void pulseT1BStop(void) { + pulseT1BMode = PULSE_MODE_COUNTED; + pulseT1BCount = 0; +} + + +void pulseT1CStop(void) { + pulseT1CMode = PULSE_MODE_COUNTED; + pulseT1CCount = 0; +} +*/ + + +uint16_t pulseT1ARemaining(void) { + return pulseT1ACount >> 1; +} + + +/* +uint16_t pulseT1BRemaining(void) { + return pulseT1BCount >> 1; +} + + +uint16_t pulseT1CRemaining(void) { + return pulseT1CCount >> 1; +} +*/ + + +void pulseT1AService(void) { + if(pulseT1ACount>0) { + //OCR1A += pulseT1APeriodTics; + + if(pulseT1AMode == PULSE_MODE_COUNTED) + pulseT1ACount--; + } + else { + // pulse count has reached zero + // disable the output compare's action on OC1A pin + TCCR1A &= ~_BV(COM1A1); + TCCR1A &= ~_BV(COM1A0); + + // disable the output compare's interrupt to stop pulsing +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 &= ~_BV(OCIE1A); +#else + TIMSK &= ~_BV(OCIE1A); +#endif + } +} + + +/* +void pulseT1BService(void) { + if(pulseT1BCount > 0) { + //OCR1B += pulseT1BPeriodTics; + + if(pulseT1BMode == PULSE_MODE_COUNTED) + pulseT1BCount--; + } + else { + TCCR1A &= ~_BV(COM1B1); + TCCR1A &= ~_BV(COM1B0); + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 &= ~_BV(OCIE1B); +#else + TIMSK &= ~_BV(OCIE1B); +#endif + } +} + + +void pulseT1CService(void) { + if(pulseT1CCount > 0) { + //OCR1C += pulseT1CPeriodTics; + + if(pulseT1CMode == PULSE_MODE_COUNTED) + pulseT1CCount--; + } + else { + pulseT1CCount-=10; + TCCR1A &= ~_BV(COM1C1); + TCCR1A &= ~_BV(COM1C0); + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +#else + ETIMSK &= ~_BV(OCIE1C); +#endif + } +} +*/ diff --git a/WShift.cpp b/WShift.cpp @@ -0,0 +1,58 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + WShift.cpp: Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2010 Brett Hagman & Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "WProgram.h" + + +uint16_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t count, uint8_t delayTime) { + uint16_t value = 0; + + for (uint8_t i = 0; i < count; ++i) { + digitalWrite(clockPin, HIGH); + //delayMicroseconds(delayTime); + if (bitOrder == LSBFIRST) + value |= digitalRead(dataPin) << i; + else + value |= digitalRead(dataPin) << ((count-1) - i); + digitalWrite(clockPin, LOW); + //delayMicroseconds(delayTime); + } + return value; +} + +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint16_t val, uint8_t count, uint8_t delayTime) { + int i; + + for (i = 0; i < count; ++i) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << ((count-1) - i)))); + + digitalWrite(clockPin, HIGH); + //delayMicroseconds(delayTime); + digitalWrite(clockPin, LOW); + //delayMicroseconds(delayTime); + } +} + diff --git a/WString.cpp b/WString.cpp @@ -0,0 +1,438 @@ +/* + WString.cpp - String library for Wiring & Arduino + Copyright (c) 2009-10 Hernando Barragan. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include <stdlib.h> +#include "WProgram.h" +#include "WString.h" + + +String::String( const char *value ) +{ + if ( value == NULL ) + value = ""; + getBuffer( _length = strlen( value ) ); + if ( _buffer != NULL ) + strcpy( _buffer, value ); +} + +String::String( const String &value ) +{ + getBuffer( _length = value._length ); + if ( _buffer != NULL ) + strcpy( _buffer, value._buffer ); +} + +String::String( const char value ) +{ + _length = 1; + getBuffer(1); + if ( _buffer != NULL ) { + _buffer[0] = value; + _buffer[1] = 0; + } +} + +String::String( const unsigned char value ) +{ + _length = 1; + getBuffer(1); + if ( _buffer != NULL ) { + _buffer[0] = value; + _buffer[1] = 0; + } +} + +String::String( const int value, const int base ) +{ + char buf[33]; + itoa((signed long)value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const unsigned int value, const int base ) +{ + char buf[33]; + ultoa((unsigned long)value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const long value, const int base ) +{ + char buf[33]; + ltoa(value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +String::String( const unsigned long value, const int base ) +{ + char buf[33]; + ultoa(value, buf, base); + getBuffer( _length = strlen(buf) ); + if ( _buffer != NULL ) + strcpy( _buffer, buf ); +} + +char String::charAt( unsigned int loc ) const +{ + return operator[]( loc ); +} + +void String::setCharAt( unsigned int loc, const char aChar ) +{ + if ( _buffer == NULL ) return; + if(_length > loc) { + _buffer[loc] = aChar; + } +} + +int String::compareTo( const String &s2 ) const +{ + return strcmp( _buffer, s2._buffer ); +} + +const String & String::concat( const String &s2 ) +{ + return (*this) += s2; +} + +const String & String::operator=( const String &rhs ) +{ + if ( this == &rhs ) + return *this; + + if ( rhs._length > _length ) + { + delete [] _buffer; + getBuffer( rhs._length ); + } + if ( _buffer != NULL ) { + _length = rhs._length; + strcpy( _buffer, rhs._buffer ); + } + return *this; +} + + +/*const String & String::operator+=( const char aChar ) +{ + if ( _length == _capacity ) + doubleBuffer(); + + _buffer[ _length++ ] = aChar; + _buffer[ _length ] = '\0'; + return *this; +} +*/ + + +const String & String::operator+=( const String &other ) +{ + _length += other._length; + if ( _length > _capacity ) + { + char *temp = _buffer; + getBuffer( _length ); + if ( _buffer != NULL ) + strcpy( _buffer, temp ); + delete [] temp; + } + if ( _buffer != NULL ) + strcat( _buffer, other._buffer ); + return *this; +} + + +int String::operator==( const String &rhs ) const +{ + return ( _length == rhs._length && strcmp( _buffer, rhs._buffer ) == 0 ); +} + +int String::operator!=( const String &rhs ) const +{ + return ( _length != rhs.length() || strcmp( _buffer, rhs._buffer ) != 0 ); +} + +int String::operator<( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) < 0; +} + +int String::operator>( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) > 0; +} + +int String::operator<=( const String &rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) <= 0; +} + +int String::operator>=( const String & rhs ) const +{ + return strcmp( _buffer, rhs._buffer ) >= 0; +} + +char & String::operator[]( unsigned int index ) +{ + static char dummy_writable_char; + if (index >= _length || !_buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return _buffer[ index ]; +} + +char String::operator[]( unsigned int index ) const +{ + // need to check for valid index, to do later + return _buffer[ index ]; +} + +boolean String::endsWith( const String &s2 ) const +{ + if ( _length < s2._length ) + return 0; + + return strcmp( &_buffer[ _length - s2._length], s2._buffer ) == 0; +} + +boolean String::equals( const String &s2 ) const +{ + return ( _length == s2._length && strcmp( _buffer,s2._buffer ) == 0 ); +} + +boolean String::equalsIgnoreCase( const String &s2 ) const +{ + if ( this == &s2 ) + return true; //1; + else if ( _length != s2._length ) + return false; //0; + + return strcmp(toLowerCase()._buffer, s2.toLowerCase()._buffer) == 0; +} + +String String::replace( char findChar, char replaceChar ) +{ + if ( _buffer == NULL ) return *this; + String theReturn = _buffer; + char* temp = theReturn._buffer; + while( (temp = strchr( temp, findChar )) != 0 ) + *temp = replaceChar; + + return theReturn; +} + +String String::replace( const String& match, const String& replace ) +{ + if ( _buffer == NULL ) return *this; + String temp = _buffer, newString; + + int loc; + while ( (loc = temp.indexOf( match )) != -1 ) + { + newString += temp.substring( 0, loc ); + newString += replace; + temp = temp.substring( loc + match._length ); + } + newString += temp; + return newString; +} + +int String::indexOf( char temp ) const +{ + return indexOf( temp, 0 ); +} + +int String::indexOf( char ch, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + const char* temp = strchr( &_buffer[fromIndex], ch ); + if ( temp == NULL ) + return -1; + + return temp - _buffer; +} + +int String::indexOf( const String &s2 ) const +{ + return indexOf( s2, 0 ); +} + +int String::indexOf( const String &s2, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + const char *theFind = strstr( &_buffer[ fromIndex ], s2._buffer ); + + if ( theFind == NULL ) + return -1; + + return theFind - _buffer; // pointer subtraction +} + +int String::lastIndexOf( char theChar ) const +{ + return lastIndexOf( theChar, _length - 1 ); +} + +int String::lastIndexOf( char ch, unsigned int fromIndex ) const +{ + if ( fromIndex >= _length ) + return -1; + + char tempchar = _buffer[fromIndex + 1]; + _buffer[fromIndex + 1] = '\0'; + char* temp = strrchr( _buffer, ch ); + _buffer[fromIndex + 1] = tempchar; + + if ( temp == NULL ) + return -1; + + return temp - _buffer; +} + +int String::lastIndexOf( const String &s2 ) const +{ + return lastIndexOf( s2, _length - s2._length ); +} + +int String::lastIndexOf( const String &s2, unsigned int fromIndex ) const +{ + // check for empty strings + if ( s2._length == 0 || s2._length - 1 > fromIndex || fromIndex >= _length ) + return -1; + + // matching first character + char temp = s2[ 0 ]; + + for ( int i = fromIndex; i >= 0; i-- ) + { + if ( _buffer[ i ] == temp && (*this).substring( i, i + s2._length ).equals( s2 ) ) + return i; + } + return -1; +} + +boolean String::startsWith( const String &s2 ) const +{ + if ( _length < s2._length ) + return 0; + + return startsWith( s2, 0 ); +} + +boolean String::startsWith( const String &s2, unsigned int offset ) const +{ + if ( offset > _length - s2._length ) + return 0; + + return strncmp( &_buffer[offset], s2._buffer, s2._length ) == 0; +} + +String String::substring( unsigned int left ) const +{ + return substring( left, _length ); +} + +String String::substring( unsigned int left, unsigned int right ) const +{ + if ( left > right ) + { + int temp = right; + right = left; + left = temp; + } + + if ( right > _length ) + { + right = _length; + } + + char temp = _buffer[ right ]; // save the replaced character + _buffer[ right ] = '\0'; + String outPut = ( _buffer + left ); // pointer arithmetic + _buffer[ right ] = temp; //restore character + return outPut; +} + +String String::toLowerCase() const +{ + String temp = _buffer; + + for ( unsigned int i = 0; i < _length; i++ ) + temp._buffer[ i ] = (char)tolower( temp._buffer[ i ] ); + return temp; +} + +String String::toUpperCase() const +{ + String temp = _buffer; + + for ( unsigned int i = 0; i < _length; i++ ) + temp._buffer[ i ] = (char)toupper( temp._buffer[ i ] ); + return temp; +} + +String String::trim() const +{ + if ( _buffer == NULL ) return *this; + String temp = _buffer; + unsigned int i,j; + + for ( i = 0; i < _length; i++ ) + { + if ( !isspace(_buffer[i]) ) + break; + } + + for ( j = temp._length - 1; j > i; j-- ) + { + if ( !isspace(_buffer[j]) ) + break; + } + + return temp.substring( i, j + 1); +} + +void String::getBytes(unsigned char *buf, unsigned int bufsize) +{ + if (!bufsize || !buf) return; + unsigned int len = bufsize - 1; + if (len > _length) len = _length; + strncpy((char *)buf, _buffer, len); + buf[len] = 0; +} + +void String::toCharArray(char *buf, unsigned int bufsize) +{ + if (!bufsize || !buf) return; + unsigned int len = bufsize - 1; + if (len > _length) len = _length; + strncpy(buf, _buffer, len); + buf[len] = 0; +} diff --git a/WString.h b/WString.h @@ -0,0 +1,125 @@ +/* + WString.h - String library for Wiring & Arduino + Copyright (c) 2009-10 Hernando Barragan. 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 String_h +#define String_h + +#include "WProgram.h" +#include <string.h> +#include <ctype.h> + +class String +{ + public: + // constructors + String( const char *value = "" ); + String( const String &value ); + String( const char ); + String( const unsigned char ); + String( const int, const int base=10); + String( const unsigned int, const int base=10 ); + String( const long, const int base=10 ); + String( const unsigned long, const int base=10 ); + virtual ~String() { delete [] _buffer; _length = _capacity = 0;} + + // operators + const String & operator = ( const String &rhs ); + const String & operator +=( const String &rhs ); + //const String & operator +=( const char ); + int operator ==( const String &rhs ) const; + int operator !=( const String &rhs ) const; + int operator < ( const String &rhs ) const; + int operator > ( const String &rhs ) const; + int operator <=( const String &rhs ) const; + int operator >=( const String &rhs ) const; + char operator []( unsigned int index ) const; + char& operator []( unsigned int index ); + //operator const char *() const { return _buffer; } + + // general methods + char charAt( unsigned int index ) const; + int compareTo( const String &anotherString ) const; + boolean endsWith( const String &suffix ) const; + boolean equals( const String &anObject ) const; + boolean equalsIgnoreCase( const String &anotherString ) const; + int indexOf( char ch ) const; + int indexOf( char ch, unsigned int fromIndex ) const; + int indexOf( const String &str ) const; + int indexOf( const String &str, unsigned int fromIndex ) const; + int lastIndexOf( char ch ) const; + int lastIndexOf( char ch, unsigned int fromIndex ) const; + int lastIndexOf( const String &str ) const; + int lastIndexOf( const String &str, unsigned int fromIndex ) const; + const unsigned int length( ) const { return _length; } + void setCharAt(unsigned int index, const char ch); + boolean startsWith( const String &prefix ) const; + boolean startsWith( const String &prefix, unsigned int toffset ) const; + String substring( unsigned int beginIndex ) const; + String substring( unsigned int beginIndex, unsigned int endIndex ) const; + String toLowerCase( ) const; + String toUpperCase( ) const; + String trim( ) const; + void getBytes(unsigned char *buf, unsigned int bufsize); + void toCharArray(char *buf, unsigned int bufsize); + const String& concat( const String &str ); + String replace( char oldChar, char newChar ); + String replace( const String& match, const String& replace ); + friend String operator + ( String lhs, const String &rhs ); + + friend int splitString( const String &what, int delim, Vector<long> &splits ); + friend int splitString( const String &what, int delim, Vector<int> &splits ); + + protected: + char *_buffer; // the actual char array + unsigned int _capacity; // the array length + unsigned int _length; // the String length + + void getBuffer(unsigned int maxStrLen); +// void doubleBuffer( ); + + private: + +}; + +// allocate buffer space +inline void String::getBuffer(unsigned int maxStrLen) +{ + _capacity = maxStrLen; + _buffer = new char[_capacity + 1]; + if (_buffer == NULL) _length = _capacity = 0; +} + + +// double the buffer size +/*inline void String::doubleBuffer( ) +{ + char *temp = _buffer; + getBuffer( ++_capacity * 2 ); + strcpy( _buffer, temp ); + delete [] temp; +}*/ + + +inline String operator+( String lhs, const String &rhs ) +{ + return lhs += rhs; +} + + +#endif diff --git a/WTimer.c b/WTimer.c @@ -0,0 +1,768 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + Based on timer128.c by Pascal Stang - Copyright (C) 2000-2003 + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include <inttypes.h> +#include <avr/io.h> +#include <avr/interrupt.h> +#include <avr/pgmspace.h> +#include <stdio.h> + +#include "WProgram.h" + + +// Program ROM constants +// the prescale division values stored in 2^n format +// STOP, CLK, CLK/8, CLK/64, CLK/256, CLK/1024 +unsigned const short __attribute__ ((progmem)) timerPrescaleFactor[] = {0,1,8,64,256,1024}; +// the prescale division values stored in 2^n format +// STOP, CLK, CLK/8, CLK/32, CLK/64, CLK/128, CLK/256, CLK/1024 +unsigned const short __attribute__ ((progmem)) timerRTCPrescaleFactor[] = {0,1,8,32,64,128,256,1024}; + +//volatile unsigned long timerPauseReg; +//volatile unsigned long timer0Reg0; +//volatile unsigned long timer0Reg1; +//volatile unsigned long timer2Reg0; +//volatile unsigned long timer2Reg1; +volatile uint8_t pwmFlags = 0x00; + +static volatile voidFuncPtr timerIntFunc[TIMER_NUM_INTERRUPTS]; +const uint8_t pwmpins[6] = {WPWMPIN0, WPWMPIN1, WPWMPIN2, WPWMPIN3, + WPWMPIN4, WPWMPIN5 }; + +void analogWrite(uint8_t pin, uint16_t value) { + // add support for regular digital I/O pin numbering + // needed in WiringMini since it doesn't have a separate section + // por PWM outputs + if(pin >= 29) { + if(pin == 31) { + pin = 3; + } else if(pin == 30) { + pin = 4; + } else if(pin == 29) { + pin = 5; + } else if(pin == 37) { + pin = 0; + } else if(pin == 36) { + pin = 1; + } else if(pin == 35) { + pin = 2; + } + } + + if(pin >= 3) { + if(bit_is_clear(pwmFlags, 6)) { + timer1Init(); + sei(); + timer1PWMInit(10); + pwmFlags |= _BV(6); + } + if(bit_is_clear(pwmFlags, pin)) { + DDRB |= pwmpins[pin]; + pinPWMOn(pin); + pwmFlags |= _BV(pin); + } + } else { + if(bit_is_clear(pwmFlags, 7)) { + timer3Init(); + sei(); + timer3PWMInit(10); + pwmFlags |= _BV(7); + } + if(bit_is_clear(pwmFlags, pin)) { + DDRE |= pwmpins[pin]; + pinPWMOn(pin); + pwmFlags |= _BV(pin); + } + } + if(pin == 5) + timer1PWMASet(value); + if(pin == 4) + timer1PWMBSet(value); + if(pin == 3) + timer1PWMCSet(value); + if(pin == 2) + timer3PWMASet(value); + if(pin == 1) + timer3PWMBSet(value); + if(pin == 0) + timer3PWMCSet(value); +} + +void pinPWMOn(uint8_t pin) { + if(pin == 5) + timer1PWMAOn(); + if(pin == 4) + timer1PWMBOn(); + if(pin == 3) + timer1PWMCOn(); + if(pin == 2) + timer3PWMAOn(); + if(pin == 1) + timer3PWMBOn(); + if(pin == 0) + timer3PWMCOn(); +} + + +void timerInit(void) +{ + uint8_t intNum; + // detach all user functions from interrupts + for(intNum=0; intNum<TIMER_NUM_INTERRUPTS; intNum++) + timerDetach(intNum); + + // initialize all timers + // timer0Init(); + timer1Init(); + timer2Init(); + timer3Init(); +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + timer4Init(); + timer5Init(); +#endif + // enable interrupts + sei(); +} + + +// Now defined in .init3 section for automatic startup +void timer0Init() { + // initialize timer 0 +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TCCR0A = _BV(WGM00) | _BV(WGM01); +#else + TCCR0 = _BV(WGM00) | _BV(WGM01); +#endif + timer0SetPrescaler( TIMER0PRESCALE ); // set prescaler + + TCNT0 = 0; // reset TCNT0 +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK0 |= _BV(TOIE0); // enable TCNT0 overflow interrupt +#else + TIMSK |= _BV(TOIE0); // enable TCNT0 overflow interrupt +#endif + //timer0ClearOverflowCount(); // initialize time registers + sei(); // enable interruptions in case any class constructor use timing functions +} + + +void timer1Init(void) { + timer1SetPrescaler( TIMER1PRESCALE ); // default to 64, defined in WConstants.h + TCNT1H = 0; + TCNT1L = 0; +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK1 |= _BV(TOIE1); // enable TCNT1 overflow +#else + TIMSK |= _BV(TOIE1); // enable TCNT1 overflow +#endif +} + +void timer2Init(void) { + timer2SetPrescaler( TIMER2PRESCALE ); // default to 8 + TCNT2 = 0; +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK2 |= _BV(TOIE2); // enable TCNT2 overflow +#else + TIMSK |= _BV(TOIE2); // enable TCNT2 overflow +#endif + //timer2ClearOverflowCount(); +} + +void timer3Init(void) { + timer3SetPrescaler( TIMER3PRESCALE ); // default to 64 + TCNT3H = 0; + TCNT3L = 0; +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TIMSK3 |= _BV(TOIE3); // enable TCNT3 overflow +#else + ETIMSK |= _BV(TOIE3); // enable TCNT3 overflow +#endif +} + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +void timer4Init(void) { + timer4SetPrescaler( TIMER4PRESCALE ); // default to 64 + TCNT4H = 0; + TCNT4L = 0; + TIMSK4 |= _BV(TOIE4); // enable TCNT4 overflow +} + + +void timer5Init(void) { + timer5SetPrescaler( TIMER5PRESCALE ); // default to 64 + TCNT3H = 0; + TCNT3L = 0; + TIMSK5 |= _BV(TOIE5); // enable TCNT3 overflow +} +#endif + + +void timer0SetPrescaler(uint8_t prescale) { +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TCCR0B = (TCCR0B & ~TIMER_PRESCALE_MASK) | prescale; +#else + TCCR0 = (TCCR0 & ~TIMER_PRESCALE_MASK) | prescale; +#endif +} + + +void timer1SetPrescaler(uint8_t prescale) { + TCCR1B = (TCCR1B & ~TIMER_PRESCALE_MASK) | prescale; +} + + +void timer2SetPrescaler(uint8_t prescale) { +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + TCCR2B = (TCCR2B & ~TIMER_PRESCALE_MASK) | prescale; +#else + TCCR2 = (TCCR2 & ~TIMER_PRESCALE_MASK) | prescale; +#endif +} + + +void timer3SetPrescaler(uint8_t prescale) { + TCCR3B = (TCCR3B & ~TIMER_PRESCALE_MASK) | prescale; +} + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +void timer4SetPrescaler(uint8_t prescale) { + TCCR4B = (TCCR4B & ~TIMER_PRESCALE_MASK) | prescale; +} + + +void timer5SetPrescaler(uint8_t prescale) { + TCCR5B = (TCCR5B & ~TIMER_PRESCALE_MASK) | prescale; +} +#endif + + +void timerAttach(uint8_t interruptNum, void (*userFunc)(void) ) { + if(interruptNum < TIMER_NUM_INTERRUPTS) { + timerIntFunc[interruptNum] = userFunc; + } +} + + +uint16_t timer0GetPrescaler(void) +{ + // get the current prescaler setting +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + return (pgm_read_word(timerPrescaleFactor+(TCCR0A & TIMER_PRESCALE_MASK))); +#else + return (pgm_read_word(timerPrescaleFactor+(TCCR0 & TIMER_PRESCALE_MASK))); +#endif +} + + +uint16_t timer1GetPrescaler(void) +{ + // get the current prescaler setting + return (pgm_read_word(timerPrescaleFactor+(TCCR1B & TIMER_PRESCALE_MASK))); +} + + +uint16_t timer2GetPrescaler(void) +{ + // get the current prescaler setting +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) + return (pgm_read_word(timerPrescaleFactor+(TCCR2B & TIMER_PRESCALE_MASK))); +#else + return (pgm_read_word(timerPrescaleFactor+(TCCR2 & TIMER_PRESCALE_MASK))); +#endif +} + + +uint16_t timer3GetPrescaler(void) +{ + // get the current prescaler setting + return (pgm_read_word(timerPrescaleFactor+(TCCR3B & TIMER_PRESCALE_MASK))); +} + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +uint16_t timer4GetPrescaler(void) +{ + // get the current prescaler setting + return (pgm_read_word(timerPrescaleFactor+(TCCR4B & TIMER_PRESCALE_MASK))); +} + + +uint16_t timer5GetPrescaler(void) +{ + // get the current prescaler setting + return (pgm_read_word(timerPrescaleFactor+(TCCR5B & TIMER_PRESCALE_MASK))); +} +#endif + + +void timerDetach(uint8_t interruptNum) { + if(interruptNum < TIMER_NUM_INTERRUPTS) { + timerIntFunc[interruptNum] = 0; + } +} + + +/* +void timerPause(unsigned short pause_ms) { + uint8_t timerThres; + uint32_t ticRateHz; + uint32_t pause; + + // capture current pause timer value + timerThres = TCNT2; + // reset pause timer overflow count + timerPauseReg = 0; + // calculate delay for [pause_ms] milliseconds + // prescaler division = 1<<(PRG_RDB(TimerPrescaleFactor + TCCR2)) + ticRateHz = CPU_FREQ/timer2GetPrescaler(); + // precision management + if( ((ticRateHz < 429497) && (pause_ms <= 10000)) ) + pause = (pause_ms*ticRateHz)/1000; + else + pause = pause_ms*(ticRateHz/1000); + // loop until time expires + while( ( (timerPauseReg<<8) | TCNT2 ) < (pause+timerThres) ); +} + + +void timer0ClearOverflowCount(void) { + timer0Reg0 = 0; + timer0Reg1 = 0; +} + + +long timer0GetOverflowCount(void) { + // return the current timer overflow count + // (this is since the last timer0ClearOverflowCount() command was called) + return timer0Reg0; +} +*/ + +// Timer2 will be managed through Timer2 library +/* +void timer2ClearOverflowCount(void) { + timer2Reg0 = 0; + timer2Reg1 = 0; +} + +long timer2GetOverflowCount(void) { + return timer2Reg0; +} +*/ + + +void timer1PWMInit(uint8_t bitRes) { + // configures timer1 for use with PWM output + // on pins OC1A, OC1B, and OC1C + + // enable Timer1 as 8,9,10bit PWM + if(bitRes == 9) { + TCCR1A |= _BV(WGM11); + TCCR1A &= ~_BV(WGM10); + } + else if( bitRes == 10 ) { // default + TCCR1A |= _BV(WGM11); + TCCR1A |= _BV(WGM10); + } + else { + // 8bit mode + TCCR1A &= ~_BV(WGM11); + TCCR1A |= _BV(WGM10); + } + // set clear-timer-on-compare-match + //cbi(TCCR1B,CTC1); + OCR1AH = 0; + OCR1AL = 0; + OCR1BH = 0; + OCR1BL = 0; + OCR1CH = 0; + OCR1CL = 0; +} + +void timer1PWMOff(void) { + TCCR1A &= ~_BV(WGM11); + TCCR1A &= ~_BV(WGM10); + // clear (disable) clear-timer-on-compare-match + //cbi(TCCR1B,CTC1); + // set PWM1A/B/C (OutputCompare action) to none + timer1PWMAOff(); + timer1PWMBOff(); + timer1PWMCOff(); +} + +void timer1PWMAOn(void) { + // turn on channel A OC1A PWM output + // set OC1A as non-inverted PWM + TCCR1A |= _BV(COM1A1); + TCCR1A &= ~_BV(COM1A0); +} + +void timer1PWMBOn(void) { + // turn on channel B OC1B PWM output + // set OC1B as non-inverted PWM + TCCR1A |= _BV(COM1B1); + TCCR1A &= ~_BV(COM1B0); +} + +void timer1PWMCOn(void) { + // turn on channel C OC1C PWM output + // set OC1C as non-inverted PWM + TCCR1A |= _BV(COM1C1); + TCCR1A &= ~_BV(COM1C0); +} + +void timer1PWMAOff(void) { + // turn off channel A (OC1A) PWM output + // set OC1A (OutputCompare action) to none + TCCR1A &= ~_BV(COM1A1); + TCCR1A &= ~_BV(COM1A0); +} + +void timer1PWMBOff(void) { + // turn off channel B (OC1B) PWM output + // set OC1B (OutputCompare action) to none + TCCR1A &= ~_BV(COM1B1); + TCCR1A &= ~_BV(COM1B0); +} + +void timer1PWMCOff(void) { + // turn off channel C (OC1C) PWM output + // set OC1C (OutputCompare action) to none + TCCR1A &= ~_BV(COM1C1); + TCCR1A &= ~_BV(COM1C0); +} + +void timer1PWMASet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel A + // this PWM output is generated on OC1A pin + // NOTE: pwmDuty should be in the range 0-255 for 8bit PWM + // pwmDuty should be in the range 0-511 for 9bit PWM + // pwmDuty should be in the range 0-1023 for 10bit PWM + OCR1AH = pwmDuty>>8; // set the high 8bits of OCR1A + OCR1AL = pwmDuty & 0x00ff; // set the low 8bits of OCR1A +} + +void timer1PWMBSet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel B + // this PWM output is generated on OC1B pin + OCR1BH = pwmDuty>>8; + OCR1BL = pwmDuty & 0x00ff; +} + +void timer1PWMCSet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel C + // this PWM output is generated on OC1C pin + OCR1CH = pwmDuty>>8; + OCR1CL = pwmDuty & 0x00ff; +} + + +void timer3PWMInit(uint8_t bitRes) { + // configures timer1 for use with PWM output + // on pins OC3A, OC3B, and OC3C + + // enable Timer3 as 8,9,10bit PWM + if(bitRes == 9) { + // 9bit mode + TCCR3A |= _BV(WGM31); + TCCR3A &= ~_BV(WGM30); + } + else if( bitRes == 10 ) { + // 10bit mode + TCCR3A |= _BV(WGM31); + TCCR3A |= _BV(WGM30); + } + else { + // default 8bit mode + TCCR3A &= ~_BV(WGM31); + TCCR3A |= _BV(WGM30); + } + + // set clear-timer-on-compare-match + //cbi(TCCR3B,CTC1); + // clear output compare value A + OCR3AH = 0; + OCR3AL = 0; + // clear output compare value B + OCR3BH = 0; + OCR3BL = 0; + // clear output compare value C + OCR3CH = 0; + OCR3CL = 0; +} + +void timer3PWMOff(void) { + // turn off PWM mode on Timer3 + TCCR3A &= ~_BV(WGM31); + TCCR3A &= ~_BV(WGM30); + timer3PWMAOff(); + timer3PWMBOff(); + timer3PWMCOff(); +} + +void timer3PWMAOn(void) { + // turn on channel A (OC3A) PWM output + // set OC3A as non-inverted PWM + TCCR3A |= _BV(COM3A1); + TCCR3A &= ~_BV(COM3A0); +} + +void timer3PWMBOn(void) { + // turn on channel B (OC3B) PWM output + // set OC3B as non-inverted PWM + TCCR3A |= _BV(COM3B1); + TCCR3A &= ~_BV(COM3B0); +} + +void timer3PWMCOn(void) { + // turn on channel C (OC3C) PWM output + // set OC3C as non-inverted PWM + TCCR3A |= _BV(COM3C1); + TCCR3A &= ~_BV(COM3C0); +} + +void timer3PWMAOff(void) { + // turn off channel A (OC3A) PWM output + // set OC3A (OutputCompare action) to none + TCCR3A &= ~_BV(COM3A1); + TCCR3A &= ~_BV(COM3A0); +} + +void timer3PWMBOff(void) { + // turn off channel B (OC3B) PWM output + // set OC3B (OutputCompare action) to none + TCCR3A &= ~_BV(COM3B1); + TCCR3A &= ~_BV(COM3B0); +} + +void timer3PWMCOff(void) { + // turn off channel C (OC3C) PWM output + // set OC3C (OutputCompare action) to none + TCCR3A &= ~_BV(COM3C1); + TCCR3A &= ~_BV(COM3C0); +} + +void timer3PWMASet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel A + // this PWM output is generated on OC3A pin + // NOTE: pwmDuty should be in the range 0-255 for 8bit PWM + // pwmDuty should be in the range 0-511 for 9bit PWM + // pwmDuty should be in the range 0-1023 for 10bit PWM + OCR3AH = pwmDuty>>8; // set the high 8bits of OCR3A + OCR3AL = pwmDuty & 0x00ff; // set the low 8bits of OCR3A +} + +void timer3PWMBSet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel B + // this PWM output is generated on OC3B pin + OCR3BH = pwmDuty>>8; + OCR3BL = pwmDuty & 0x00ff; +} + +void timer3PWMCSet(uint16_t pwmDuty) { + // set PWM (output compare) duty for channel B + // this PWM output is generated on OC3C pin + OCR3CH = pwmDuty>>8; + OCR3CL = pwmDuty & 0x00ff; +} + + +// Interrupt handler for tcnt0 overflow interrupt / this is handled in WApplet.c +// for timer0 since it is the main timer for millis() etc. +/* +ISR(SIG_OVERFLOW0) { + timer0Reg0++; // increment low-order counter + if(!timer0Reg0) // if low-order counter rollover + timer0Reg1++; // increment high-order counter + + if(timerIntFunc[TIMER0OVERFLOW_INT]) + timerIntFunc[TIMER0OVERFLOW_INT](); +} +*/ + + +// Interrupt handler for Timer1 overflow interrupt +ISR(TIMER1_OVF_vect) { + // if a user function is defined, execute it + if(timerIntFunc[TIMER1OVERFLOW_INT]) + timerIntFunc[TIMER1OVERFLOW_INT](); +} + + +// Interrupt handler for Timer2 overflow interrupt +ISR(TIMER2_OVF_vect) { + if(timerIntFunc[TIMER2OVERFLOW_INT]) + timerIntFunc[TIMER2OVERFLOW_INT](); +} + + +// Interrupt handler for Timer3 overflow interrupt +ISR(TIMER3_OVF_vect) { + if(timerIntFunc[TIMER3OVERFLOW_INT]) + timerIntFunc[TIMER3OVERFLOW_INT](); +} + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +// Interrupt handler for Timer4 overflow interrupt +ISR(TIMER4_OVF_vect) { + if(timerIntFunc[TIMER4OVERFLOW_INT]) + timerIntFunc[TIMER4OVERFLOW_INT](); +} + +// Interrupt handler for Timer5 overflow interrupt +ISR(TIMER5_OVF_vect) { + if(timerIntFunc[TIMER5OVERFLOW_INT]) + timerIntFunc[TIMER5OVERFLOW_INT](); +} +#endif + + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +ISR(TIMER0_COMPA_vect) { + if(timerIntFunc[TIMER0OUTCOMPAREA_INT]) + timerIntFunc[TIMER0OUTCOMPAREA_INT](); +} + +ISR(TIMER0_COMPB_vect) { + if(timerIntFunc[TIMER0OUTCOMPAREB_INT]) + timerIntFunc[TIMER0OUTCOMPAREB_INT](); +} +#elif defined (__AVR_ATmega128__) +// Interrupt handler for OutputCompare0 OC0 interrupt +ISR(TIMER0_COMP_vect) { + if(timerIntFunc[TIMER0OUTCOMPARE_INT]) + timerIntFunc[TIMER0OUTCOMPARE_INT](); +} +#endif + + +// Interrupt handler for OutputCompare1A OC1A interrupt +ISR(TIMER1_COMPA_vect) { + if(timerIntFunc[TIMER1OUTCOMPAREA_INT]) + timerIntFunc[TIMER1OUTCOMPAREA_INT](); +} + +// Interrupt handler for OutputCompare1B OC1B interrupt +ISR(TIMER1_COMPB_vect) { + if(timerIntFunc[TIMER1OUTCOMPAREB_INT]) + timerIntFunc[TIMER1OUTCOMPAREB_INT](); +} + +// Interrupt handler for OutputCompare1C OC1C interrupt +ISR(TIMER1_COMPC_vect) { + if(timerIntFunc[TIMER1OUTCOMPAREC_INT]) + timerIntFunc[TIMER1OUTCOMPAREC_INT](); +} + +// Interrupt handler for InputCapture1 IC1 interrupt +ISR(TIMER1_CAPT_vect) { + if(timerIntFunc[TIMER1INPUTCAPTURE_INT]) + timerIntFunc[TIMER1INPUTCAPTURE_INT](); +} + +// Interrupt handler for OutputCompare2 OC2 interrupt +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +ISR(TIMER2_COMPA_vect) { + if(timerIntFunc[TIMER2OUTCOMPAREA_INT]) + timerIntFunc[TIMER2OUTCOMPAREA_INT](); +} +ISR(TIMER2_COMPB_vect) { + if(timerIntFunc[TIMER2OUTCOMPAREB_INT]) + timerIntFunc[TIMER2OUTCOMPAREB_INT](); +} + +#elif defined (__AVR_ATmega128__) +ISR(TIMER2_COMP_vect) { + if(timerIntFunc[TIMER2OUTCOMPARE_INT]) + timerIntFunc[TIMER2OUTCOMPARE_INT](); +} +#endif + +// Interrupt handler for OutputCompare3A OC3A interrupt +ISR(TIMER3_COMPA_vect) { + if(timerIntFunc[TIMER3OUTCOMPAREA_INT]) + timerIntFunc[TIMER3OUTCOMPAREA_INT](); +} + +// Interrupt handler for OutputCompare3B OC3B interrupt +ISR(TIMER3_COMPB_vect) { + if(timerIntFunc[TIMER3OUTCOMPAREB_INT]) + timerIntFunc[TIMER3OUTCOMPAREB_INT](); +} + +// Interrupt handler for OutputCompare3C OC3C interrupt +ISR(TIMER3_COMPC_vect) { + if(timerIntFunc[TIMER3OUTCOMPAREC_INT]) + timerIntFunc[TIMER3OUTCOMPAREC_INT](); +} + +// Interrupt handler for InputCapture3 IC3 interrupt +ISR(TIMER3_CAPT_vect) { + if(timerIntFunc[TIMER3INPUTCAPTURE_INT]) + timerIntFunc[TIMER3INPUTCAPTURE_INT](); +} + + +#if defined (__AVR_ATmega1281__)||(__AVR_ATmega2561__) +// Interrupt handler for OutputCompare4A OC4A interrupt +ISR(TIMER4_COMPA_vect) { + if(timerIntFunc[TIMER4OUTCOMPAREA_INT]) + timerIntFunc[TIMER4OUTCOMPAREA_INT](); +} + +// Interrupt handler for OutputCompare4B OC4B interrupt +ISR(TIMER4_COMPB_vect) { + if(timerIntFunc[TIMER4OUTCOMPAREB_INT]) + timerIntFunc[TIMER4OUTCOMPAREB_INT](); +} + +// Interrupt handler for OutputCompare4C OC4C interrupt +ISR(TIMER4_COMPC_vect) { + if(timerIntFunc[TIMER4OUTCOMPAREC_INT]) + timerIntFunc[TIMER4OUTCOMPAREC_INT](); +} + +// Interrupt handler for OutputCompare5A OC5A interrupt +ISR(TIMER5_COMPA_vect) { + if(timerIntFunc[TIMER5OUTCOMPAREA_INT]) + timerIntFunc[TIMER5OUTCOMPAREA_INT](); +} + +// Interrupt handler for OutputCompare5B OC5B interrupt +ISR(TIMER5_COMPB_vect) { + if(timerIntFunc[TIMER5OUTCOMPAREB_INT]) + timerIntFunc[TIMER5OUTCOMPAREB_INT](); +} + +// Interrupt handler for OutputCompare5C OC5C interrupt +ISR(TIMER5_COMPC_vect) { + if(timerIntFunc[TIMER5OUTCOMPAREC_INT]) + timerIntFunc[TIMER5OUTCOMPAREC_INT](); +} + +// There is no InputCapture4 IC4 and InputCapture5 IC5 interrupt on atmega1281/2561 +#endif diff --git a/WVector.h b/WVector.h @@ -0,0 +1,378 @@ +/* + WVector.h - Vector library for Wiring & Arduino + Copyright (c) 2009 Hernando Barragan. 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 Vector_h +#define Vector_h + +#include <ctype.h> +#include <stdlib.h> + +template <class Element> +class Vector { + public: + // constructors + Vector( unsigned int initialCapacity = 10, unsigned int capacityIncrement = 10 ); + Vector( const Vector& rhv ); + virtual ~Vector(); + + // methods + unsigned int capacity() const; + boolean contains( const Element& elem ) const; + const Element& firstElement() const; + int indexOf( const Element& elem ) const; + boolean isEmpty() const; + const Element& lastElement() const; + int lastIndexOf( const Element& elem ) const; + unsigned int size() const; + void copyInto( Element* array ) const; + inline boolean add( const Element& obj ) { addElement(obj); return true; } + void addElement( const Element& obj ); + inline void clear() { removeAllElements(); } + void ensureCapacity( unsigned int minCapacity ); + void removeAllElements(); + boolean removeElement( const Element& obj ); + void setSize( unsigned int newSize ); + void trimToSize(); + const Element& elementAt( unsigned int index ) const; + void insertElementAt( const Element& obj, unsigned int index ); + const Element& remove( unsigned int index ); + void removeElementAt( unsigned int index ); + void setElementAt( const Element& obj, unsigned int index ); + inline const Element& get( unsigned int index ) const + { return elementAt(index); } + + const Element& operator[]( unsigned int index ) const; + Element& operator[]( unsigned int index ); + + protected: + unsigned int _size; + unsigned int _capacity; + unsigned int _increment; + Element** _data; + }; + +template <class Element> +Vector<Element>::Vector( unsigned int initialCapacity, unsigned int capacityIncrement ) +{ + _size = 0; + _capacity = initialCapacity; + _data = new Element*[ _capacity ]; + _increment = capacityIncrement; + if(_data == NULL) _capacity = _increment = 0; +}; + +template <class Element> +Vector<Element>::Vector( const Vector<Element>& rhv ) +{ + _size = rhv._size; + _capacity = rhv._capacity; + _data = new Element*[ _capacity ]; + _increment = rhv._increment; + if(_data == NULL) { + _size = _capacity = _increment = 0; + } + + for( unsigned int i = 0; i < _size; i++ ) + { + _data[i] = new Element( *(rhv._data[i]) ); + } +}; + +template <class Element> +Vector<Element>::~Vector() +{ + removeAllElements(); + delete [] _data; +}; + +template <class Element> +unsigned int Vector<Element>::capacity() const +{ + return _capacity; +}; + +template <class Element> +boolean Vector<Element>::contains( const Element &elem ) const +{ + for ( unsigned int i = 0; i < _size; i++ ) + { + if ( *_data[i] == elem ) + return true; + } + + return false; +}; + +template <class Element> +void Vector<Element>::copyInto( Element* array ) const +{ + if(array != NULL) + for( unsigned int i = 0; i < _size; i++ ) + array[i] = *_data[i]; +}; + + +template <class Element> +const Element & Vector<Element>::elementAt( unsigned int index ) const +{ + static Element dummy_writable_element; + if (index >= _size || !_data) { + dummy_writable_element = 0; + return dummy_writable_element; + } + // add check for valid index + return *_data[index]; +}; + +template <class Element> +const Element & Vector<Element>::firstElement() const +{ + static Element dummy_writable_element; + if ( _size == 0 || !_data) + { + dummy_writable_element = 0; + return dummy_writable_element; + } + + return *_data[ 0 ]; +}; + +template <class Element> +int Vector<Element>::indexOf( const Element &elem ) const +{ + for ( unsigned int i = 0; i < _size; i++ ) + { + if ( *_data[ i ] == elem ) + return i; + } + + return -1; +}; + +template <class Element> +boolean Vector<Element>::isEmpty() const +{ + return _size == 0; +}; + +template <class Element> +const Element & Vector<Element>::lastElement() const +{ + static Element dummy_writable_element; + if ( _size == 0 || !_data ) + { + dummy_writable_element = 0; + return dummy_writable_element; + } + + return *_data[ _size - 1 ]; +}; + +template <class Element> +int Vector<Element>::lastIndexOf( const Element &elem ) const +{ + // check for empty vector + if ( _size == 0 ) + return -1; + + unsigned int i = _size; + + do + { + i -= 1; + if ( *_data[i] == elem ) + return i; + + } + while ( i != 0 ); + + return -1; +}; + +template <class Element> +unsigned int Vector<Element>::size() const +{ + return _size; +}; + +template <class Element> +void Vector<Element>::addElement( const Element &obj ) +{ + if ( _size == _capacity ) + ensureCapacity( _capacity + _increment ); + if ( _size < _capacity ) + _data[ _size++ ] = new Element( obj ); +}; + +template <class Element> +void Vector<Element>::ensureCapacity( unsigned int minCapacity ) +{ + if ( minCapacity > _capacity ) + { + unsigned int i; + //_capacity = minCapacity; + Element** temp = new Element*[ minCapacity ]; + // copy all elements + if(temp != NULL) { + _capacity = minCapacity; + memcpy( temp, _data, sizeof(Element*) * _size ); + delete [] _data; + _data = temp; + } + } +}; + +template <class Element> +void Vector<Element>::insertElementAt( const Element &obj, unsigned int index ) +{ + if ( index == _size ) + addElement( obj ); + else + { + // need to verify index, right now you must know what you're doing + if (index > _size) return; + if ( _size == _capacity ) + ensureCapacity( _capacity + _increment); + if ( _size < _capacity ) { + Element* newItem = new Element(obj); // pointer to new item + Element* tmp; // temp to hold item to be moved over + + for( unsigned int i = index; i <= _size; i++ ) + { + tmp = _data[i]; + _data[i] = newItem; + + if ( i != _size ) + newItem = tmp; + else + break; + } + _size++; + } + } + //_size++; +}; + +template <class Element> +const Element& Vector<Element>::remove( unsigned int index ) +{ + Element retval = get(index); + removeElementAt(index); + return retval; +}; + +template <class Element> +void Vector<Element>::removeAllElements() +{ + // avoid memory leak + for ( unsigned int i = 0; i < _size; i++ ) + delete _data[i]; + + _size = 0; +}; + +template <class Element> +boolean Vector<Element>::removeElement( const Element &obj ) +{ + for ( unsigned int i = 0; i < _size; i++ ) + { + if ( *_data[i] == obj ) + { + removeElementAt( i ); + return true; + } + } + return false; +}; + +template <class Element> +void Vector<Element>::removeElementAt( unsigned int index ) +{ + // check for valid index + if(index >= _size) return; + + delete _data[ index ]; + + unsigned int i; + for ( i = index+1; i < _size; i++ ) + _data[ i - 1 ] = _data[ i ]; + + _data[i]; + _size--; +}; + +template <class Element> +void Vector<Element>::setElementAt( const Element &obj, unsigned int index ) +{ + // check for valid index + if(index >= _size) return; + *_data[ index ] = obj; +}; + +template <class Element> +void Vector<Element>::setSize( unsigned int newSize ) +{ + if ( newSize > _capacity ) + ensureCapacity( newSize ); + else if ( newSize < _size ) + { + for( unsigned int i = newSize; i < _size; i++ ) + delete _data[i]; + + _size = newSize; + } +}; + +template <class Element> +void Vector<Element>::trimToSize() +{ + if ( _size != _capacity ) + { + Element** temp = new Element*[ _size ]; + if(temp == NULL) return; + + for ( unsigned int i = 0; i < _size; i++ ) + temp[i] = _data[i]; + + delete [] _data; + + _data = temp; + _capacity = _size; + } +}; + +template <class Element> +const Element & Vector<Element>::operator[]( unsigned int index ) const +{ + return elementAt( index ); +}; + +template <class Element> +Element & Vector<Element>::operator[]( unsigned int index ) +{ + // check for valid index + static char dummy_writable_element; + if(index >= _size || !_data) { + dummy_writable_element = 0; + return dummy_writable_element; + } + return *_data[ index ]; +}; + +#endif diff --git a/config.mk b/config.mk @@ -0,0 +1,10 @@ +MCU= atmega128 + +SERIAL= /dev/ttyUSB0 + +CFLAGS= -Os -mmcu=$(MCU) -I. -Iinclude + +CC=avr-gcc $(CFLAGS) -fpermissive +CXX=avr-g++ $(CFLAGS) -fpermissive +LD=avr-gcc $(CFLAGS) -s -Wl,--gc-sections,-u,-Map=$(<:.o=.map),--cref +OBJCOPY= avr-objcopy -O srec -R .eeprom + \ No newline at end of file diff --git a/include/EEPROM/EEPROM.cpp b/include/EEPROM/EEPROM.cpp @@ -0,0 +1,86 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + + Copyright (c) 2004-10 Hernando Barragan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#include "EEPROM.h" + + +uint8_t WEEPROM::read(int address) +{ + return eeprom_read_byte((unsigned char *) address); +} + +void WEEPROM::write(int address, uint8_t value) +{ + eeprom_write_byte((unsigned char *) address, value); +} + +/* +uint8_t WEEPROM::read(uint16_t address) +{ +#if defined (__AVR_ATmega2561__)||(__AVR_ATmega2560__)||(__AVR_ATmega1281__)||(__AVR_ATmega1280__) + while( EECR & _BV(EEPE) ); +#else + while( EECR & _BV(EEWE) ); +#endif + EEARH = (uint8_t) ((address & 0xFF00) >> 8); + EEARL = (uint8_t) (address & 0x00FF); + + // set read EERE + EECR |= _BV(EERE); + + // return data byte + return EEDR; +} + +void WEEPROM::write(uint16_t address, uint8_t value) +{ + // wait until any previous write is done +#if defined (__AVR_ATmega2561__)||(__AVR_ATmega2560__)||(__AVR_ATmega1281__)||(__AVR_ATmega1280__) + while( EECR & _BV(EEPE) ); +#else + while( EECR & _BV(EEWE) ); +#endif + EEARH = (uint8_t) ((address & 0xFF00) >> 8); + EEARL = (uint8_t) (address & 0x00FF); + + EEDR = value; + +#if defined (__AVR_ATmega2561__)||(__AVR_ATmega2560__)||(__AVR_ATmega1281__)||(__AVR_ATmega1280__) + // set master write enable EMWEE + EECR |= _BV(EEMPE); + + // Set write EEPE + EECR |= _BV( EEPE ); + +#else + // set master write enable EMWEE + EECR |= _BV(EEMWE); + + // Set write EEWE + EECR |= _BV( EEWE ); +#endif +} +*/ + +WEEPROM EEPROM; + diff --git a/include/EEPROM/EEPROM.h b/include/EEPROM/EEPROM.h @@ -0,0 +1,36 @@ +/* + WEEPROM.h - EEPROM management library for Wiring + Copyright (c) 2006-07 Hernando Barragan. 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 <avr/eeprom.h> +#include <inttypes.h> +#include "WProgram.h" + +class WEEPROM +{ + public: + uint8_t read(int); + void write(int, uint8_t); +}; + +extern WEEPROM EEPROM; + +#endif diff --git a/include/EEPROM/examples/StoreData/StoreData.pde b/include/EEPROM/examples/StoreData/StoreData.pde @@ -0,0 +1,29 @@ +/** + * EEPROM store data + * by BARRAGAN <http://barraganstudio.com> + * + * Demostrates how to store data in the EEPROM + */ + +#include <EEPROM.h> + +char val; + +void setup() { + if(EEPROM.read(5) != 'H') { // If an H hassn't been stored before + // in the EEPROM address 5 + EEPROM.write(5, 'H'); // store an 'H' in EEPROM address 5 + } + val = EEPROM.read(5); // read value stored in EEPROM address 5 + + pinMode(48, OUTPUT); +} + +void loop() { + if( val == 'H' ) // if val is 'H' then turon ON the onboard LED (pin 48) + { + digitalWrite(48, HIGH); + } + delay(100); +} + diff --git a/include/EEPROM/keywords.txt b/include/EEPROM/keywords.txt @@ -0,0 +1,25 @@ +####################################### +# Syntax Coloring Map For EEPROM +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +read KEYWORD2 +write KEYWORD2 + +####################################### +# Instances (KEYWORD2) +####################################### + +EEPROM KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/include/Encoder/Encoder.cpp b/include/Encoder/Encoder.cpp @@ -0,0 +1,148 @@ +/* + Encoder.cpp - Encoder library for Wiring & Arduino + Copyright (c) 2006-10 Hernando Barragan and 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 +*/ + +#include "WProgram.h" +#include "Encoder.h" + + +Encoder* Encoder::_encoders[4]; +uint8_t Encoder::_count = 0; +const uint8_t Encoder::_interrupts[] = { 2, 3, 38, 39 }; + +Encoder::Encoder() { + _index = 0; +} + +uint8_t Encoder::attach(uint8_t pin_a, uint8_t pin_b) { + if(4 <= _count) { + return 0; + } + pinMode(_pin_a = pin_a, INPUT); + pinMode(_pin_b = pin_b, INPUT); + _position = 0; + if(this == _encoders[_index]) { + return 1; + } + + if(0 == _count) { + for(uint8_t i=0; i< 4; i++ ) { + _encoders[i] = NULL; + } + } + + for(uint8_t i = 0; i< 4; i++) { + if(NULL == _encoders[i] && _interrupts[i] == _pin_a) { + _encoders[i] = this; + _index = i; + ++_count; + break; + } + } + + noInterrupts(); + switch(_pin_a) { + case 2: + //EICRA |= _BV(ISC20)|_BV(ISC21); + //EIMSK |= _BV(INT2); + attachInterrupt(EXTERNAL_INT_2, service0, CHANGE); + break; + case 3: + //EICRA |= _BV(ISC30)|_BV(ISC31); + //EIMSK |= _BV(INT3); + attachInterrupt(EXTERNAL_INT_3, service1, CHANGE); + break; + case 38: + //EICRB |= _BV(ISC60)|_BV(ISC61); + //EIMSK |= _BV(INT6); + attachInterrupt(EXTERNAL_INT_6, service2, CHANGE); + break; + case 39: + //EICRB |= _BV(ISC70)|_BV(ISC71); + //EIMSK |= _BV(INT7); + attachInterrupt(EXTERNAL_INT_7, service3, CHANGE); + break; + default: + break; + } + interrupts(); + return 1; +} + + +void Encoder::detach() { + if(this == _encoders[_index]) { + switch(_pin_a) { + case 2: + //EIMSK &= ~_BV(INT2); + detachInterrupt(EXTERNAL_INT_2); + break; + case 3: + //EIMSK &= ~_BV(INT3); + detachInterrupt(EXTERNAL_INT_3); + break; + case 38: + //EIMSK &= ~_BV(INT6); + detachInterrupt(EXTERNAL_INT_6); + break; + case 39: + //EIMSK &= ~_BV(INT7); + detachInterrupt(EXTERNAL_INT_7); + break; + default: + break; + } + _encoders[_index] = NULL; + if(0 < _count) { + --_count; + } + } +} + + +uint8_t Encoder::attached(void) { + if(this == _encoders[_index]) { + return 1; + } + return 0; +} + + +void Encoder::write(int32_t position) { + _position = position; +} + + +int32_t Encoder::read(void) { + return _position; +} + +void Encoder::service0(void) { _encoders[0]->service(); } +void Encoder::service1(void) { _encoders[1]->service(); } +void Encoder::service2(void) { _encoders[2]->service(); } +void Encoder::service3(void) { _encoders[3]->service(); } + + +void Encoder::service(void) { + if((digitalRead(_pin_a) == LOW) ^ (digitalRead(_pin_b) == HIGH)) { + _position++; + } else { + _position--; + } +} diff --git a/include/Encoder/Encoder.h b/include/Encoder/Encoder.h @@ -0,0 +1,52 @@ +/* + Encoder.cpp - Encoder library for Wiring & Arduino + Copyright (c) 2006-10 Hernando Barragan and 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 Encoder_h +#define Encoder_h + +#include <inttypes.h> + + +class Encoder +{ + private: + uint8_t _index; + static const uint8_t _interrupts[]; + volatile uint8_t _pin_a; + volatile uint8_t _pin_b; + volatile int32_t _position; + static uint8_t _count; + static Encoder* _encoders[]; + static void service0(void); + static void service1(void); + static void service2(void); + static void service3(void); + void service(void); + + public: + Encoder(); + uint8_t attach(uint8_t, uint8_t); + void detach(); + void write(int32_t); + int32_t read(void); + uint8_t attached(void); +}; + +#endif diff --git a/include/Encoder/examples/EncoderRead/EncoderRead.pde b/include/Encoder/examples/EncoderRead/EncoderRead.pde @@ -0,0 +1,26 @@ +/** + * Encoder read + * by BARRAGAN <http://barraganstudio.com> + * + * Demonstrates the use of an encoder with the Encoder library + * Prints the encoder value + */ + +#include <Encoder.h> + +int val; +Encoder myEncoder; + +void setup() { + myEncoder.attach(2, 8); // ataches the encoder to pins 2 and 8 + myEncoder.write(0); // set the encoder position to 0 + Serial.begin(9600); +} + +void loop() { + // Reads the position or angle of the encoder variable + val = myEncoder.read(); // read position + Serial.print("Encoder is at: "); // print the position + Serial.println(val); + delay(100); // wait 100ms for next reading +} diff --git a/include/Encoder/keywords.txt b/include/Encoder/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map For Encoder +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +Encoder KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +attached KEYWORD2 +attach KEYWORD2 +detach KEYWORD2 +write KEYWORD2 +read KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/include/FIFO/FIFO.h b/include/FIFO/FIFO.h @@ -0,0 +1,97 @@ +/* +|| +|| @file FIFO.h +|| @version 1.2 +|| @author Alexander Brevig +|| @contact alexanderbrevig@gmail.com +|| +|| @description +|| | A simple FIFO class, mostly for primitive types but can be used with classes if assignment to int is allowed +|| | This FIFO is not dynamic, so be sure to choose an appropriate size for it +|| # +|| +|| @license +|| | Copyright (c) 2010 Alexander Brevig +|| | 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; version +|| | 2.1 of the License. +|| | +|| | 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 FIFO_h +#define FIFO_h + +template<typename T, int rawSize> +class FIFO { + public: + const int size; //speculative feature, in case it's needed + + FIFO(); + + T dequeue(); //get next element + bool enqueue( T element ); //add an element + T peek() const; //get the next element without releasing it from the FIFO + void flush(); //[1.1] reset to default state + + //how many elements are currently in the FIFO? + int count() { return numberOfElements; } + + private: + volatile int numberOfElements; + int nextIn; + int nextOut; + T raw[rawSize]; +}; + +template<typename T, int rawSize> +FIFO<T,rawSize>::FIFO() : size(rawSize) +{ + flush(); +} + +template<typename T, int rawSize> +bool FIFO<T,rawSize>::enqueue( T element ) +{ + if ( count() >= rawSize ) { return false; } + numberOfElements++; + raw[nextIn] = element; + if (++nextIn >= size) // advance to next index, wrap if needed + nextIn = 0; + return true; +} + +template<typename T, int rawSize> +T FIFO<T,rawSize>::dequeue() +{ + T item; + numberOfElements--; + item = raw[nextOut]; + if (++nextOut >= size) // advance to next index, wrap if needed + nextOut = 0; + return item; +} + +template<typename T, int rawSize> +T FIFO<T,rawSize>::peek() const +{ + return raw[nextOut]; +} + +template<typename T, int rawSize> +void FIFO<T,rawSize>::flush() +{ + nextIn = nextOut = numberOfElements = 0; +} + +#endif diff --git a/include/Firmata/Boards.h b/include/Firmata/Boards.h @@ -0,0 +1,384 @@ +/* Boards.h - Hardware Abstraction Layer for Firmata library */ + +#ifndef Firmata_Boards_h +#define Firmata_Boards_h + +#include <WProgram.h> // for digitalRead, digitalWrite, etc + +// 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 + *============================================================================*/ + +// Arduino Duemilanove, Diecimila, and NG +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 24 // 14 digital + 2 unused + 8 analog +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21)) +#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 23) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) (0) +#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2) +#define PIN_TO_ANALOG(p) ((p) - 16) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) ((p) - 2) +#define ARDUINO_PINOUT_OPTIMIZE 1 + + +// old Arduinos +#elif defined(__AVR_ATmega8__) +#define TOTAL_ANALOG_PINS 6 +#define TOTAL_PINS 22 // 14 digital + 2 unused + 6 analog +#define VERSION_BLINK_PIN 13 +#define IS_PIN_DIGITAL(p) (((p) >= 2 && (p) <= 13) || ((p) >= 16 && (p) <= 21)) +#define IS_PIN_ANALOG(p) ((p) >= 16 && (p) <= 21) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) <= 13 && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) (0) +#define PIN_TO_DIGITAL(p) (((p) < 16) ? (p) : (p) - 2) +#define PIN_TO_ANALOG(p) ((p) - 16) +#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__) +#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) IS_PIN_DIGITAL(p) +#define IS_PIN_SERVO(p) ((p) >= 2 && (p) - 2 < MAX_SERVOS) +#define IS_PIN_I2C(p) (0) +#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) + + +// Wiring +#elif defined(__AVR_ATmega128__)||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__) +#define TOTAL_ANALOG_PINS 8 +#define TOTAL_PINS 54 +#define VERSION_BLINK_PIN 48 +#define IS_PIN_DIGITAL(p) ((p) >= 0 && (p) < TOTAL_PINS) +#define IS_PIN_ANALOG(p) ((p) >= 40 && (p) < 48) +#define IS_PIN_PWM(p) IS_PIN_DIGITAL(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) ((p) - 40) +#define PIN_TO_PWM(p) PIN_TO_DIGITAL(p) +#define PIN_TO_SERVO(p) (p) +#define WIRING_PINOUT_OPTIMIZE 1 + + +// 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) IS_PIN_DIGITAL(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) IS_PIN_DIGITAL(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) (((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) IS_PIN_DIGITAL(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) ((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) IS_PIN_DIGITAL(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) ((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) IS_PIN_DIGITAL(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) ((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 & B11111100 & bitmask; // ignore Rx/Tx 0/1 + if (port == 1) return PINB & B00111111 & bitmask; // pins 8-13 (14,15 are disabled for the crystal) + if (port == 2) return PINC & bitmask; + return 0; +#elif defined(WIRING_PINOUT_OPTIMIZE) + if (port == 0) return PIND & bitmask; + if (port == 1) return PINC & bitmask; + if (port == 2) return PINA & bitmask; + if (port == 3) return PINB & bitmask; + if (port == 4) return PINE & B11111100 & bitmask; // ignore Rx/Tx 32/33; + if (port == 5) return PINF & bitmask; + if (port == 6) return PING & 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; // Tx & Rx pins + cli(); + PORTD = (PORTD & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 1) { + cli(); + PORTB = (PORTB & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 2) { + cli(); + PORTC = (PORTC & ~bitmask) | (bitmask & value); + sei(); + } +#elif defined(WIRING_PINOUT_OPTIMIZE) + if (port == 0) { + cli(); + PORTD = (PORTD & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 1) { + cli(); + PORTC = (PORTC & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 2) { + cli(); + PORTA = (PORTA & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 3) { + cli(); + PORTB = (PORTB & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 4) { + bitmask = bitmask & 0xFC; // Tx & Rx pins + cli(); + PORTE = (PORTE & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 5) { + cli(); + PORTF = (PORTF & ~bitmask) | (bitmask & value); + sei(); + } else if (port == 6) { + cli(); + PORTG = (PORTG & ~bitmask) | (bitmask & value); + 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/include/Firmata/Firmata.cpp b/include/Firmata/Firmata.cpp @@ -0,0 +1,438 @@ +/* + 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 "WProgram.h" +#include "HardwareSerial.h" +#include "Firmata.h" + +extern "C" { +#include <string.h> +#include <stdlib.h> +} + +//****************************************************************************** +//* Support Functions +//****************************************************************************** + +void sendValueAsTwo7bitBytes(int value) +{ + Serial.print(value & B01111111, BYTE); // LSB + Serial.print(value >> 7 & B01111111, BYTE); // MSB +} + +void startSysex(void) +{ + Serial.print(START_SYSEX, BYTE); +} + +void endSysex(void) +{ + Serial.print(END_SYSEX, BYTE); +} + +//****************************************************************************** +//* Constructors +//****************************************************************************** + +FirmataClass::FirmataClass(void) +{ + 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); + blinkVersion(); + delay(300); + printVersion(); + printFirmwareVersion(); +} + +// output the protocol version message to the serial port +void FirmataClass::printVersion(void) { + Serial.print(REPORT_VERSION, BYTE); + Serial.print(FIRMATA_MAJOR_VERSION, BYTE); + Serial.print(FIRMATA_MINOR_VERSION, BYTE); +} + +void FirmataClass::blinkVersion(void) +{ + // flash the pin with the protocol version + pinMode(VERSION_BLINK_PIN,OUTPUT); + pin13strobe(FIRMATA_MAJOR_VERSION, 200, 400); + delay(300); + pin13strobe(2,1,4); // separator, a quick burst + delay(300); + pin13strobe(FIRMATA_MINOR_VERSION, 200, 400); +} + +void FirmataClass::printFirmwareVersion(void) +{ + byte i; + + if(firmwareVersionCount) { // make sure that the name has been set before reporting + startSysex(); + Serial.print(REPORT_FIRMWARE, BYTE); + Serial.print(firmwareVersionVector[0]); // major version number + Serial.print(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 Serial.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 = Serial.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 + Serial.print(ANALOG_MESSAGE | (pin & 0xF), BYTE); + 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) +{ + Serial.print(DIGITAL_MESSAGE | (portNumber & 0xF),BYTE); + Serial.print((byte)portData % 128, BYTE); // Tx bits 0-6 + Serial.print(portData >> 7, BYTE); // Tx bits 7-13 +} + + +void FirmataClass::sendSysex(byte command, byte bytec, byte* bytev) +{ + byte i; + startSysex(); + Serial.print(command, BYTE); + 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; + + diff --git a/include/Firmata/Firmata.h b/include/Firmata/Firmata.h @@ -0,0 +1,162 @@ +/* + 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 <WProgram.h> +#include <inttypes.h> + + +/* 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 2 // for backwards compatible changes + +#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(); +/* Arduino constructors */ + void begin(); + void begin(long); +/* 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: +/* 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); +}; + +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) + +/* Hardware Abstraction Layer */ +#include "Boards.h" + +#endif /* Firmata_h */ + diff --git a/include/Firmata/LICENSE.txt b/include/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/include/Firmata/TODO.txt b/include/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/include/Firmata/examples/AllInputsFirmata/AllInputsFirmata.pde b/include/Firmata/examples/AllInputsFirmata/AllInputsFirmata.pde @@ -0,0 +1,78 @@ +/** + * 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)); + } + /* 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/include/Firmata/examples/AnalogFirmata/AnalogFirmata.pde b/include/Firmata/examples/AnalogFirmata/AnalogFirmata.pde @@ -0,0 +1,91 @@ +/** + * 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 <Firmata.h> +#include <Servo.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 nextExecuteMillis; // 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 35: + case 36: + case 37: + case 29: + case 30: + case 31: // 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 > nextExecuteMillis) { + nextExecuteMillis = currentMillis + 19; // run this every 20ms + for(analogPin=0;analogPin<TOTAL_ANALOG_PINS;analogPin++) { + if( analogInputsToReport & (1 << analogPin) ) + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } +} + diff --git a/include/Firmata/examples/AnalogFirmata/Makefile b/include/Firmata/examples/AnalogFirmata/Makefile @@ -0,0 +1,263 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +CC = avr-gcc +CXX = avr-g++ +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + + diff --git a/include/Firmata/examples/EchoString/EchoString.pde b/include/Firmata/examples/EchoString/EchoString.pde @@ -0,0 +1,40 @@ +/** + * This sketch accepts strings and raw sysex messages and echos them back. + * + * This example code is in the public domain. + */ + +#include <Firmata.h> + + +void stringCallback(char *myString) +{ + Firmata.sendString(myString); +} + + +void sysexCallback(byte command, byte argc, byte *argv) +{ + Serial.print(START_SYSEX, BYTE); + Serial.print(command, BYTE); + for(byte i=0; i<argc; i++) { + Serial.print(argv[i], BYTE); + } + Serial.print(END_SYSEX, BYTE); +} + +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/include/Firmata/examples/EchoString/Makefile b/include/Firmata/examples/EchoString/Makefile @@ -0,0 +1,263 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +CC = avr-gcc +CXX = avr-g++ +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + + diff --git a/include/Firmata/examples/I2CFirmata/I2CFirmata.pde b/include/Firmata/examples/I2CFirmata/I2CFirmata.pde @@ -0,0 +1,216 @@ +/** + * 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 nextExecuteMillis; // 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.send((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.receive(); + } + // 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.send(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(PORTD3, PORTD2); + } + + 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 2 and 3 to be used as GND and Power +// so that I2C devices can be plugged directly +// into Wiring header (pins 0 - 3) +static void enablePowerPins(byte pwrpin, byte gndpin) +{ + if(powerPinsEnabled == 0) { + DDRD |= _BV(pwrpin) | _BV(gndpin); + PORTD &=~ _BV(gndpin); + PORTD |= _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 > nextExecuteMillis) { + nextExecuteMillis = currentMillis + samplingInterval; + + for (byte i = 0; i < queryIndex; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } +} diff --git a/include/Firmata/examples/OldStandardFirmata/LICENSE.txt b/include/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/include/Firmata/examples/OldStandardFirmata/OldStandardFirmata.pde b/include/Firmata/examples/OldStandardFirmata/OldStandardFirmata.pde @@ -0,0 +1,287 @@ +/** + * 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 <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 nextExecuteMillis; // 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); + break; + case 1: + outputPort(1, PINC); + break; + case 2: + outputPort(2, PINA); + break; + case 3: + outputPort(3, PINB); + break; + case 4: + outputPort(4, PINE &~ B00000011); + break; // ignore Rx/Tx 0/1 + case 5: + outputPort(5, PINF); + break; + case 6: + outputPort(6, PING); + 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 < 16) { + port = 1; + offset = 8; + } + else if (pin < 24) { + port = 2; + offset = 16; + } + else if (pin < 32) { + port = 3; + offset = 24; + } + else if (pin < 40) { + port = 4; + offset = 32; + } + else if (pin < 48) { + port = 5; + offset = 40; + } + else if (pin < 54) { + port = 6; + offset = 48; + } + + if((pin<32)&&(pin > 33)) { // ignore RxTx (pins 32 and 33) + 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 0-7 + PORTD = (byte)value; + break; + case 1: // pins 8-15 + PORTC = (byte)value; + break; + case 2: // pins 16-23 + PORTA = (byte)value; + break; + case 3: // pins 24-31 + PORTB = (byte)value; + break; + case 4: // pins 34-39 (don't change Rx/Tx, pins 32 and 33) + // 0xFF03 == B1111111100000011 0x03 == B00000011 + PORTE = (value &~ 0xFF03) | (PORTE & 0x03); + break; + case 5: // pins 40-47 + PORTF = (byte)value; + break; + case 6: // pins 48-53 + PORTG = (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 == 5) // 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] = B00000000; + portStatus[1] = B00000000; + portStatus[2] = B00000000; + portStatus[3] = B00000000; + portStatus[4] = B00000011; // ignore Tx/RX pins + portStatus[5] = B00000000; + portStatus[6] = B00000000; + + // for(i=0; i<TOTAL_DIGITAL_PINS; ++i) { // TODO make this work with analogs + for(i=0; i<40; ++i) { + setPinModeCallback(i,OUTPUT); + } + // set all outputs to 0 to make sure internal pull-up resistors are off + PORTD = 0; // pins 0-7 + PORTC = 0; // pins 8-15 + PORTA = 0; // pins 16-23 + PORTB = 0; // pins 24-31 + PORTE = 0; // pins 32-39 + PORTF = 0; // analog port + PORTG = 0; // pins 48-53 + + // 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); + if(reportPINs[1]) outputPort(1, PINC); + if(reportPINs[2]) outputPort(2, PINA); + if(reportPINs[3]) outputPort(3, PINB); + if(reportPINs[4]) outputPort(4, PINE &~ B00000011); // ignore Rx/Tx 0/1 + if(reportPINs[5]) outputPort(5, PINF); + if(reportPINs[6]) outputPort(6, PING); + + 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 > nextExecuteMillis) { + nextExecuteMillis = currentMillis + 19; // 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/include/Firmata/examples/ServoFirmata/Makefile b/include/Firmata/examples/ServoFirmata/Makefile @@ -0,0 +1,263 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +CC = avr-gcc +CXX = avr-g++ +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + + diff --git a/include/Firmata/examples/ServoFirmata/ServoFirmata.pde b/include/Firmata/examples/ServoFirmata/ServoFirmata.pde @@ -0,0 +1,41 @@ +/** + * This firmware supports as many servos as possible using the Servo library + * + * 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/include/Firmata/examples/SimpleAnalogFirmata/Makefile b/include/Firmata/examples/SimpleAnalogFirmata/Makefile @@ -0,0 +1,263 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +CC = avr-gcc +CXX = avr-g++ +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + + diff --git a/include/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde b/include/Firmata/examples/SimpleAnalogFirmata/SimpleAnalogFirmata.pde @@ -0,0 +1,37 @@ +/** + * 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/include/Firmata/examples/SimpleDigitalFirmata/Makefile b/include/Firmata/examples/SimpleDigitalFirmata/Makefile @@ -0,0 +1,263 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +CC = avr-gcc +CXX = avr-g++ +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + + diff --git a/include/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde b/include/Firmata/examples/SimpleDigitalFirmata/SimpleDigitalFirmata.pde @@ -0,0 +1,64 @@ +/** + * 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)); + } + + while(Firmata.available()) { + Firmata.processInput(); + } +} + diff --git a/include/Firmata/examples/StandardFirmata/LICENSE.txt b/include/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/include/Firmata/examples/StandardFirmata/Makefile b/include/Firmata/examples/StandardFirmata/Makefile @@ -0,0 +1,273 @@ +# Arduino makefile +# +# This makefile allows you to build sketches from the command line +# without the Arduino environment (or Java). +# +# The Arduino environment does preliminary processing on a sketch before +# compiling it. If you're using this makefile instead, you'll need to do +# a few things differently: +# +# - Give your program's file a .cpp extension (e.g. foo.cpp). +# +# - Put this line at top of your code: #include <WProgram.h> +# +# - Write prototypes for all your functions (or define them before you +# call them). A prototype declares the types of parameters a +# function will take and what type of value it will return. This +# means that you can have a call to a function before the definition +# of the function. A function prototype looks like the first line of +# the function, with a semi-colon at the end. For example: +# int digitalRead(int pin); +# +# Instructions for using the makefile: +# +# 1. Copy this file into the folder with your sketch. +# +# 2. Below, modify the line containing "TARGET" to refer to the name of +# of your program's file without an extension (e.g. TARGET = foo). +# +# 3. Modify the line containg "ARDUINO" to point the directory that +# contains the Arduino core (for normal Arduino installations, this +# is the hardware/cores/arduino sub-directory). +# +# 4. Modify the line containing "PORT" to refer to the filename +# representing the USB or serial connection to your Arduino board +# (e.g. PORT = /dev/tty.USB0). If the exact name of this file +# changes, you can use * as a wildcard (e.g. PORT = /dev/tty.USB*). +# +# 5. At the command line, change to the directory containing your +# program's file and the makefile. +# +# 6. Type "make" and press enter to compile/verify your program. +# +# 7. Type "make upload", reset your Arduino board, and press enter to +# upload your program to the Arduino board. +# +# $Id: Makefile,v 1.7 2007/04/13 05:28:23 eighthave Exp $ + +PORT = /dev/tty.usbserial-* +TARGET := $(shell pwd | sed 's|.*/\(.*\)|\1|') +ARDUINO = /Applications/arduino +ARDUINO_SRC = $(ARDUINO)/hardware/cores/arduino +ARDUINO_LIB_SRC = $(ARDUINO)/hardware/libraries +ARDUINO_TOOLS = $(ARDUINO)/hardware/tools +INCLUDE = -I$(ARDUINO_SRC) -I$(ARDUINO)/hardware/tools/avr/avr/include \ + -I$(ARDUINO_LIB_SRC)/EEPROM \ + -I$(ARDUINO_LIB_SRC)/Firmata \ + -I$(ARDUINO_LIB_SRC)/Matrix \ + -I$(ARDUINO_LIB_SRC)/Servo \ + -I$(ARDUINO_LIB_SRC)/Wire \ + -I$(ARDUINO_LIB_SRC) +SRC = $(wildcard $(ARDUINO_SRC)/*.c) +CXXSRC = applet/$(TARGET).cpp $(ARDUINO_SRC)/HardwareSerial.cpp \ + $(ARDUINO_LIB_SRC)/EEPROM/EEPROM.cpp \ + $(ARDUINO_LIB_SRC)/Firmata/Firmata.cpp \ + $(ARDUINO_LIB_SRC)/Servo/Servo.cpp \ + $(ARDUINO_SRC)/Print.cpp \ + $(ARDUINO_SRC)/WMath.cpp +HEADERS = $(wildcard $(ARDUINO_SRC)/*.h) $(wildcard $(ARDUINO_LIB_SRC)/*/*.h) + +MCU = atmega168 +#MCU = atmega8 +F_CPU = 16000000 +FORMAT = ihex +UPLOAD_RATE = 19200 + +# Name of this Makefile (used for "make depend"). +MAKEFILE = Makefile + +# Debugging format. +# Native formats for AVR-GCC's -g are stabs [default], or dwarf-2. +# AVR (extended) COFF requires stabs, plus an avr-objcopy run. +DEBUG = stabs + +OPT = s + +# Place -D or -U options here +CDEFS = -DF_CPU=$(F_CPU) +CXXDEFS = -DF_CPU=$(F_CPU) + +# Compiler flag to set the C Standard level. +# c89 - "ANSI" C +# gnu89 - c89 plus GCC extensions +# c99 - ISO C99 standard (not yet fully implemented) +# gnu99 - c99 plus GCC extensions +CSTANDARD = -std=gnu99 +CDEBUG = -g$(DEBUG) +CWARN = -Wall -Wstrict-prototypes +CTUNING = -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +#CEXTRA = -Wa,-adhlns=$(<:.c=.lst) + +CFLAGS = $(CDEBUG) $(CDEFS) $(INCLUDE) -O$(OPT) $(CWARN) $(CSTANDARD) $(CEXTRA) +CXXFLAGS = $(CDEFS) $(INCLUDE) -O$(OPT) +#ASFLAGS = -Wa,-adhlns=$(<:.S=.lst),-gstabs +LDFLAGS = + + +# Programming support using avrdude. Settings and variables. +AVRDUDE_PROGRAMMER = stk500 +AVRDUDE_PORT = $(PORT) +AVRDUDE_WRITE_FLASH = -U flash:w:applet/$(TARGET).hex +AVRDUDE_FLAGS = -F -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) \ + -b $(UPLOAD_RATE) -q -V + +# Program settings +ARDUINO_AVR_BIN = $(ARDUINO_TOOLS)/avr/bin +CC = $(ARDUINO_AVR_BIN)/avr-gcc +CXX = $(ARDUINO_AVR_BIN)/avr-g++ +OBJCOPY = $(ARDUINO_AVR_BIN)/avr-objcopy +OBJDUMP = $(ARDUINO_AVR_BIN)/avr-objdump +SIZE = $(ARDUINO_AVR_BIN)/avr-size +NM = $(ARDUINO_AVR_BIN)/avr-nm +#AVRDUDE = $(ARDUINO_AVR_BIN)/avrdude +AVRDUDE = avrdude +REMOVE = rm -f +MV = mv -f + +# Define all object files. +OBJ = $(SRC:.c=.o) $(CXXSRC:.cpp=.o) $(ASRC:.S=.o) + +# Define all listing files. +LST = $(ASRC:.S=.lst) $(CXXSRC:.cpp=.lst) $(SRC:.c=.lst) + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) +ALL_CXXFLAGS = -mmcu=$(MCU) -I. $(CXXFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + +# Default target. +all: build + +build: applet/$(TARGET).hex + +eep: applet/$(TARGET).eep +lss: applet/$(TARGET).lss +sym: applet/$(TARGET).sym + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT=$(OBJCOPY) --debugging \ +--change-section-address .data-0x800000 \ +--change-section-address .bss-0x800000 \ +--change-section-address .noinit-0x800000 \ +--change-section-address .eeprom-0x810000 + + +coff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +extcoff: applet/$(TARGET).elf + $(COFFCONVERT) -O coff-ext-avr applet/$(TARGET).elf applet/$(TARGET).cof + + +.SUFFIXES: .elf .hex .eep .lss .sym .pde + +.elf.hex: + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +.elf.eep: + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O $(FORMAT) $< $@ + +# Create extended listing file from ELF output file. +.elf.lss: + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +.elf.sym: + $(NM) -n $< > $@ + + +# Compile: create object files from C++ source files. +.cpp.o: $(HEADERS) + $(CXX) -c $(ALL_CXXFLAGS) $< -o $@ + +# Compile: create object files from C source files. +.c.o: $(HEADERS) + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +.c.s: + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +.S.o: + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + + +applet/$(TARGET).cpp: $(TARGET).pde + test -d applet || mkdir applet + echo '#include "WProgram.h"' > applet/$(TARGET).cpp + echo '#include "avr/interrupt.h"' >> applet/$(TARGET).cpp + sed -n 's|^\(void .*)\).*|\1;|p' $(TARGET).pde | grep -v 'setup()' | \ + grep -v 'loop()' >> applet/$(TARGET).cpp + cat $(TARGET).pde >> applet/$(TARGET).cpp + cat $(ARDUINO_SRC)/main.cxx >> applet/$(TARGET).cpp + +# Link: create ELF output file from object files. +applet/$(TARGET).elf: applet/$(TARGET).cpp $(OBJ) + $(CC) $(ALL_CFLAGS) $(OBJ) -lm --output $@ $(LDFLAGS) +# $(CC) $(ALL_CFLAGS) $(OBJ) $(ARDUINO_TOOLS)/avr/avr/lib/avr5/crtm168.o --output $@ $(LDFLAGS) + +pd_close_serial: + echo 'close;' | /Applications/Pd-extended.app/Contents/Resources/bin/pdsend 34567 || true + +# Program the device. +upload: applet/$(TARGET).hex + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) + + +pd_test: build pd_close_serial upload + +# Target: clean project. +clean: + $(REMOVE) -- applet/$(TARGET).hex applet/$(TARGET).eep \ + applet/$(TARGET).cof applet/$(TARGET).elf $(TARGET).map \ + applet/$(TARGET).sym applet/$(TARGET).lss applet/$(TARGET).cpp \ + $(OBJ) $(LST) $(SRC:.c=.s) $(SRC:.c=.d) $(CXXSRC:.cpp=.s) $(CXXSRC:.cpp=.d) + rmdir -- applet + +depend: + if grep '^# DO NOT DELETE' $(MAKEFILE) >/dev/null; \ + then \ + sed -e '/^# DO NOT DELETE/,$$d' $(MAKEFILE) > \ + $(MAKEFILE).$$$$ && \ + $(MV) $(MAKEFILE).$$$$ $(MAKEFILE); \ + fi + echo '# DO NOT DELETE THIS LINE -- make depend depends on it.' \ + >> $(MAKEFILE); \ + $(CC) -M -mmcu=$(MCU) $(CDEFS) $(INCLUDE) $(SRC) $(ASRC) >> $(MAKEFILE) + +.PHONY: all build eep lss sym coff extcoff clean depend pd_close_serial pd_test + +# for emacs +etags: + make etags_`uname -s` + etags *.pde \ + $(ARDUINO_SRC)/*.[ch] \ + $(ARDUINO_SRC)/*.cpp \ + $(ARDUINO_LIB_SRC)/*/*.[ch] \ + $(ARDUINO_LIB_SRC)/*/*.cpp \ + $(ARDUINO)/hardware/tools/avr/avr/include/avr/*.[ch] \ + $(ARDUINO)/hardware/tools/avr/avr/include/*.[ch] + +etags_Darwin: +# etags -a + +etags_Linux: +# etags -a /usr/include/*.h linux/input.h /usr/include/sys/*.h + +etags_MINGW: +# etags -a /usr/include/*.h /usr/include/sys/*.h + + +path: + echo $(PATH) + echo $$PATH + diff --git a/include/Firmata/examples/StandardFirmata/StandardFirmata.pde b/include/Firmata/examples/StandardFirmata/StandardFirmata.pde @@ -0,0 +1,401 @@ +/** + * 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. + * formatted using the GNU C formatting and indenting + */ + +/* + * TODO: use Program Control to load stored profiles from EEPROM + */ + +#include <Servo.h> +#include <Firmata.h> + +/*============================================================================== + * 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) + +Servo servos[MAX_SERVOS]; + +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +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 (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)); + } + else { + Firmata.sendString("Servo only on pins from 2 to 13"); + } + } + break; + case I2C: + pinConfig[pin] = mode; + Firmata.sendString("I2C mode not yet supported"); + 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) +{ + switch(command) { + 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)) { + // servos are pins from 2 to 13, so offset for array + 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); + 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); + } + 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; + } +} + + +/*============================================================================== + * SETUP() + *============================================================================*/ +void setup() +{ + byte i; + + Firmata.setFirmwareVersion(2, 2); + + 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); + + // TODO: load state from EEPROM here + + /* these are initialized to zero by the compiler startup code + for (i=0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; + portConfigInputs[i] = 0; + previousPINs[i] = 0; + } + */ + for (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 defult, do not report any analog inputs + analogInputsToReport = 0; + + Firmata.begin(57600); + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + for (i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } +} + +/*============================================================================== + * 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)); + } + } + } + } +} + diff --git a/include/Firmata/keywords.txt b/include/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/include/Keypad/Keypad.cpp b/include/Keypad/Keypad.cpp @@ -0,0 +1,152 @@ +/* +|| +|| @file Keypad.h +|| @version 1.8 +|| @author Mark Stanley, Alexander Brevig +|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com +|| +|| @description +|| | This library provides a simple interface for using matrix +|| | keypads. It supports the use of multiple keypads with the +|| | same or different sets of keys. It also supports user +|| | selectable pins and definable keymaps. +|| # +|| +|| @license +|| | 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; version +|| | 2.1 of the License. +|| | +|| | 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 "Keypad.h" + +// <<constructor>> Allows custom keymap. pin configuration and keypad size +Keypad::Keypad(char *userKeymap, byte *row, byte *col, byte rows, byte cols) +{ + rowPins = row; + columnPins = col; + + size.rows = rows; + size.columns = cols; + + begin(userKeymap); + + lastUpdate = 0; + debounceTime = 50; + holdTime = 1000; + keypadEventListener = 0; + currentKey = NO_KEY; + state = IDLE; + + initializePins(); +} + +// Let the user define a keymap - assume the same row- / columncount as defined in constructor +void Keypad::begin( char *userKeymap){ + keymap = userKeymap; +} + +// Returns the keykode of the pressed key, or NO_KEY if no key is pressed +char Keypad::getKey(){ + char key = NO_KEY; // Assume that no key is pressed, this is the default return for getKey() + for (byte c=0; c<size.columns; c++){ + digitalWrite(columnPins[c],LOW); // Activate the current column. + for (byte r=0; r<size.rows; r++){ // Scan all the rows for a key press. + // The user pressed a button for more then debounceTime microseconds. + if (currentKey == keymap[c+(r*size.columns)]){ + // Button hold + if (((millis()-lastUpdate) >= holdTime) && digitalRead(rowPins[r]) == LOW){ + transitionTo(HOLD); + } + // Button release + if (((millis()-lastUpdate) >= debounceTime) && digitalRead(rowPins[r]) == HIGH){ + transitionTo(RELEASED); + currentKey = NO_KEY; + } + } + // Button pressed event. The user pressed a button. + else if (((millis()-lastUpdate) >= debounceTime) && digitalRead(rowPins[r]) == LOW){ + digitalWrite(columnPins[c],HIGH); // De-activate the current column. + key = keymap[c+(r*size.columns)]; + lastUpdate = millis(); + goto EVALUATE_KEY; // Save resources and do not attempt to parse to keys at a time + } + } + digitalWrite(columnPins[c],HIGH); // De-activate the current column. + } + + EVALUATE_KEY: + if (key != NO_KEY && key != currentKey){ + currentKey = key; + transitionTo(PRESSED); + return currentKey; + } + else{ + return NO_KEY; + } +} + + +KeypadState Keypad::getState(){ + return state; +} + +void Keypad::setDebounceTime(unsigned int debounce){ + debounceTime = debounce; +} +void Keypad::setHoldTime(unsigned int hold){ + holdTime = hold; +} + +void Keypad::addEventListener(void (*listener)(char)){ + keypadEventListener = listener; +} + +//private +void Keypad::transitionTo(KeypadState newState){ + if (state!=newState){ + state = newState; + if (keypadEventListener!=NULL){ + keypadEventListener(currentKey); + } + } +} + +void Keypad::initializePins(){ + for (byte r=0; r<size.rows; r++){ + for (byte c=0; c<size.columns; c++){ + pinMode(columnPins[c],OUTPUT); + digitalWrite(columnPins[c],HIGH); + } + //configure row pin modes and states + pinMode(rowPins[r],INPUT); + digitalWrite(rowPins[r],HIGH); + } +} + +/* +|| @changelog +|| | 2009-07-08 - Alexander Brevig : Library does not use 2d arrays +|| | 2009-06-15 - Alexander Brevig : Added transitionTo +|| | 2009-06-15 - Alexander Brevig : Added getState() +|| | 2009-06-13 - Mark Stanley : Fixed bug in getKey() that returns the wrong key if debounceTime is too short. +|| | 2009-06-13 - Mark Stanley : Minor bug fix: Added 'currentKey = NO_KEY' to constructors. +|| | 2009-05-19 - Alexander Brevig : Added setHoldTime() +|| | 2009-05-15 - Alexander Brevig : Changed begin() amd getKey(), this Library should be operational. +|| | 2009-05-09 - Alexander Brevig : Changed getKey() +|| | 2009-04-28 - Alexander Brevig : Modified API, and made variables private +|| | 2007-XX-XX - Mark Stanley : Initial Release +|| # +*/+ \ No newline at end of file diff --git a/include/Keypad/Keypad.h b/include/Keypad/Keypad.h @@ -0,0 +1,107 @@ +/* +|| +|| @file Keypad.h +|| @version 1.8 +|| @author Mark Stanley, Alexander Brevig +|| @contact mstanley@technologist.com, alexanderbrevig@gmail.com +|| +|| @description +|| | This library provides a simple interface for using matrix +|| | keypads. It supports the use of multiple keypads with the +|| | same or different sets of keys. It also supports user +|| | selectable pins and definable keymaps. +|| # +|| +|| @license +|| | 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; version +|| | 2.1 of the License. +|| | +|| | 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 KEYPAD_H +#define KEYPAD_H + +#include <WProgram.h> + +#define makeKeymap(x) ((char*)x) + +typedef char KeypadEvent; + +typedef enum { + IDLE=0, + PRESSED, + RELEASED, + HOLD +} KeypadState; + +typedef struct { + byte rows : 4; + byte columns : 4; +} KeypadSize; + +const char NO_KEY = '\0'; +#define KEY_RELEASED NO_KEY + +class Keypad { +public: + /* + Keypad(); + Keypad(byte row[], byte col[], byte rows, byte cols); + */ + Keypad(char *userKeymap, byte *row, byte *col, byte rows, byte cols); + + //void begin(); //DEPRECATED! + void begin(char *userKeymap); + char getKey(); + KeypadState getState(); + void setDebounceTime(unsigned int debounce); + void setHoldTime(unsigned int hold); + void addEventListener(void (*listener)(char)); + +private: + void transitionTo(KeypadState newState); + void initializePins(); + + char *keymap; + byte *rowPins; + byte *columnPins; + KeypadSize size; + KeypadState state; + char currentKey; + unsigned long lastUpdate; + unsigned int debounceTime; + unsigned int holdTime; + void (*keypadEventListener)(char); +}; + +#endif + +/* +|| @changelog +|| | 1.8 2009-07-08 - Alexander Brevig : No longer uses arrays +|| | 1.7 2009-06-18 - Alexander Brevig : This library is a Finite State Machine +|| | every time a state changes the keypadEventListener will trigger, if set +|| | 1.7 2009-06-18 - Alexander Brevig : Added setDebounceTime +|| | setHoldTime specifies the amount of microseconds before a HOLD state triggers +|| | 1.7 2009-06-18 - Alexander Brevig : Added transitionTo +|| | 1.6 2009-06-15 - Alexander Brevig : Added getState() and state variable +|| | 1.5 2009-05-19 - Alexander Brevig : Added setHoldTime() +|| | 1.4 2009-05-15 - Alexander Brevig : Added addEventListener +|| | 1.3 2009-05-12 - Alexander Brevig : Added lastUdate, in order to do simple debouncing +|| | 1.2 2009-05-09 - Alexander Brevig : Changed getKey() +|| | 1.1 2009-04-28 - Alexander Brevig : Modified API, and made variables private +|| | 1.0 2007-XX-XX - Mark Stanley : Initial Release +|| # +*/ diff --git a/include/Keypad/examples/CustomKeypad/CustomKeypad.pde b/include/Keypad/examples/CustomKeypad/CustomKeypad.pde @@ -0,0 +1,31 @@ +//INSERT HEADER +//If you are a user and see this header, please contact alexanderbrevig@gmail.com + +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 4; //four columns +//define the cymbols on the buttons of the keypads +char hexaKeys[ROWS][COLS] = { + {'0','1','2','3'}, + {'4','5','6','7'}, + {'8','9','A','B'}, + {'C','D','E','F'} +}; +byte rowPins[ROWS] = {3, 2, 1, 0}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {7, 6, 5, 4}; //connect to the column pinouts of the keypad + +//initialize an instance of class NewKeypad +Keypad cusomKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, cols); + +void setup(){ + Serial.begin(9600); +} + +void loop(){ + char customKey = cusomKeypad.getKey(); + + if (customKey != NO_KEY){ + Serial.println(customKey); + } +} diff --git a/include/Keypad/examples/DynamicKeypad/DynamicKeypad.pde b/include/Keypad/examples/DynamicKeypad/DynamicKeypad.pde @@ -0,0 +1,187 @@ +/* keypad_alnum sketch + * + * Difficulty: Intermediate + * + * ******* THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. ******* + * + * Description: + * This is a demonstration of using keypadEvents to switch between keymaps + * while using only one keypad. The main concepts being demonstrated are: + * + * Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding. + * How to use setHoldTime() and why. + * Making more than one thing happen with the same key. + * Assigning and changing keymaps on the fly. + * + * Another useful feature is also included with this demonstration although + * it's not really one of the concepts that I wanted to show you. If you look + * at the code in the PRESSED event you will see that the first section of that + * code is used to scroll through three different letters on each key. For + * example, pressing the '2' key will step through the letters 'd', 'e' and 'f'. + * + * + * Using the keypad events, PRESSED, HOLD and RELEASED to simplify coding + * Very simply, the PRESSED event occurs imediately upon detecting a pressed + * key and will not happen again until after a RELEASED event. When the HOLD + * event fires it always falls between PRESSED and RELEASED. However, it will + * only occur if a key has been pressed for longer than the setHoldTime() interval. + * + * How to use setHoldTime() and why + * Take a look at keypad.setHoldTime(500) in the code. It is used to set the + * time delay between a PRESSED event and the start of a HOLD event. The value + * 500 is in milliseconds (mS) and is equivalent to half a second. After pressing + * a key for 500mS the HOLD event will fire and any code contained therein will be + * executed. This event will stay active for as long as you hold the key except + * in the case of bug #1 listed above. + * + * Making more than one thing happen with the same key. + * If you look under the PRESSED event (case PRESSED:) you will see that the '#' + * is used to print a new line, Serial.println(). But take a look at the first + * half of the HOLD event and you will see the same key being used to switch back + * and forth between the letter and number keymaps that were created with alphaKeys[4][5] + * and numberKeys[4][5] respectively. + * + * Assigning and changing keymaps on the fly + * You will see that the '#' key has been designated to perform two different functions + * depending on how long you hold it down. If you press the '#' key for less than the + * setHoldTime() then it will print a new line. However, if you hold if for longer + * than that it will switch back and forth between numbers and letters. You can see the + * keymap changes in the HOLD event. + * + * + * In addition... + * You might notice a couple of things that you won't find in the Arduino language + * reference. The first would be #include <ctype.h>. This is a standard library from + * the C programming language and though I don't normally demonstrate these types of + * things from outside the Arduino language reference I felt that its use here was + * justified by the simplicity that it brings to this sketch. + * That simplicity is provided by the two calls to isalpha(key) and isdigit(key). + * The first one is used to decide if the key that was pressed is any letter from a-z + * or A-Z and the second one decides if the key was any number from 0-9. The return + * value from these two functions is either a zero or some positive number greater + * than zero. This makes it very simple to test a key and see if it is a number or + * a letter. So when you see the following: + * + * if (isalpha(key)) // this is a letter key + * + * then just remember that it is equivalent to: + * + * if (isalpha(key) != 0) // this is a letter key + * + * And Finally... + * To better understand how the event handler affects your code you will need to remember + * that it only gets called when you press, release or hold a key. And once you do then + * the event handler runs at the full speed of the loop(). + * + * + * ******* THE KEYPAD REQUIRES PULL-UP RESISTORS ON THE ROW PINS. ******* + * + */ + + +#include <Keypad.h> +#include <ctype.h> + +// Define the keymaps. The blank spot (lower left) is the space character. +char alphaKeys[4][3] = { + { 'a','d','g' }, + { 'j','m','p' }, + { 's','v','y' }, + { ' ','.','#' } +}; + +char numberKeys[4][3] = { + { '1','2','3' }, + { '4','5','6' }, + { '7','8','9' }, + { ' ','0','#' } +}; + +boolean alpha = false; // Start with the numeric keypad. + +char* keypadMap = (alpha == true) ? makeKeymap(alphaKeys) : makeKeymap(numberKeys); + +// Connect keypad ROW0, ROW1, ROW2 and ROW3 to these pins, eg. ROW0 = Arduino pin2. +byte rowPins[] = { 9, 8, 7, 6 }; + +// Connect keypad COL0, COL1 and COL2 to these pins, eg. COL0 = Arduino pin6. +byte colPins[] = { 12, 11, 10 }; + +//create a new Keypad +Keypad keypad = Keypad(keypadMap, rowPins, colPins, sizeof(rowPins), sizeof(colPins)); + +const byte ledPin = 13; // Use the LED on pin 13. + +void setup() { + Serial.begin(9600); + digitalWrite(ledPin, HIGH); // Turns the LED on. + keypad.addEventListener(keypadEvent); // Add an event listener. + keypad.setHoldTime(500); // Default is 1000mS + keypad.setDebounceTime(250); // Default is 50mS +} + +void loop() { + char key = keypad.getKey(); + + if (alpha) { // Flash the LED if we are using the letter keymap. + digitalWrite(ledPin,!digitalRead(ledPin)); + delay(100); + } +} + +// Take care of some special events. +void keypadEvent(KeypadEvent key) { + static char virtKey = NO_KEY; // Stores the last virtual key press. (Alpha keys only) + static char physKey = NO_KEY; // Stores the last physical key press. (Alpha keys only) + static char buildStr[12]; + static byte buildCount; + static byte pressCount; + + switch (keypad.getState()) + { + case PRESSED: + if (isalpha(key)) { // This is a letter key so we're using the letter keymap. + if (physKey != key) { // New key so start with the first of 3 characters. + pressCount = 0; + virtKey = key; + physKey = key; + } + else { // Pressed the same key again... + virtKey++; // so select the next character on that key. + pressCount++; // Tracks how many times we press the same key. + } + if (pressCount > 2) { // Last character reached so cycle back to start. + pressCount = 0; + virtKey = key; + } + Serial.print(virtKey); // Used for testing. + } + if (isdigit(key) || key == ' ' || key == '.') Serial.print(key); + if (key == '#') Serial.println(); + break; + + case HOLD: + if (key == '#') { // Toggle between keymaps. + if (alpha == true) { // We are currently using a keymap with letters + keypad.begin(*numberKeys); // and want to change to numbers. + alpha = false; + } + else { // Or, we are currently using a keymap with numbers + keypad.begin(*alphaKeys); // and want to change to letters. + alpha = true; + } + } + else { // Some key other than '#' was pressed. + buildStr[buildCount++] = (isalpha(key)) ? virtKey : key; + buildStr[buildCount] = '\0'; + Serial.println(); + Serial.println(buildStr); + } + break; + + case RELEASED: + if (buildCount >= sizeof(buildStr)) buildCount = 0; // Our string is full. Start fresh. + break; + + } // end switch-case +} // end keypad events+ \ No newline at end of file diff --git a/include/Keypad/examples/EventKeypad/EventKeypad.pde b/include/Keypad/examples/EventKeypad/EventKeypad.pde @@ -0,0 +1,66 @@ +//INSERT HEADER +//If you are a user and see this header, please contact alexanderbrevig@gmail.com + +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 4; //four columns +char keys[ROWS][COLS] = { + {'1','2','3','A'}, + {'4','5','6','B'}, + {'7','8','9','C'}, + {'#','0','*','D'} +}; +byte rowPins[ROWS] = {2,3,4,5}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {6,7,8,9}; //connect to the column pinouts of the keypad + +Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); +byte ledPin = 13; + +boolean blink = false; + +void setup(){ + Serial.begin(9600); + pinMode(ledPin, OUTPUT); // sets the digital pin as output + digitalWrite(ledPin, HIGH); // sets the LED on + keypad.addEventListener(keypadEvent); //add an event listener for this keypad +} + +void loop(){ + char key = keypad.getKey(); + + if (key != NO_KEY) { + Serial.println(key); + } + if (blink){ + digitalWrite(ledPin,!digitalRead(ledPin)); + delay(100); + } +} + +//take care of some special events +void keypadEvent(KeypadEvent key){ + switch (keypad.getState()){ + case PRESSED: + switch (key){ + case '#': digitalWrite(ledPin,!digitalRead(ledPin)); break; + case '*': + digitalWrite(ledPin,!digitalRead(ledPin)); + break; + } + break; + case RELEASED: + switch (key){ + case '*': + digitalWrite(ledPin,!digitalRead(ledPin)); + blink = false; + break; + } + break; + case HOLD: + switch (key){ + case '*': blink = true; break; + } + break; + } +} diff --git a/include/Keypad/examples/HelloKeypad/HelloKeypad.pde b/include/Keypad/examples/HelloKeypad/HelloKeypad.pde @@ -0,0 +1,29 @@ +//INSERT HEADER +//If you are a user and see this header, please contact alexanderbrevig@gmail.com + +#include <Keypad.h> + +const byte ROWS = 4; //four rows +const byte COLS = 3; //three columns +char keys[ROWS][COLS] = { + {'1','2','3'}, + {'4','5','6'}, + {'7','8','9'}, + {'#','0','*'} +}; +byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad +byte colPins[COLS] = {8, 7, 6}; //connect to the column pinouts of the keypad + +Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); + +void setup(){ + Serial.begin(9600); +} + +void loop(){ + char key = keypad.getKey(); + + if (key != NO_KEY){ + Serial.println(key); + } +} diff --git a/include/Keypad/keywords.txt b/include/Keypad/keywords.txt @@ -0,0 +1,17 @@ +Keypad KEYWORD1 +KeypadEvent KEYWORD1 + +begin KEYWORD2 +getKey KEYWORD2 +getState KEYWORD2 +setHoldTime KEYWORD2 +addEventListener KEYWORD2 + +# this is a macro that converts 2d arrays to pointers +makeKeymap KEYWORD2 + +# this is a way to standardize the client code, help enhance the use of the name keypadEvent +keypadEvent KEYWORD2 + +NO_KEY LITERAL1 +KEY_RELEASED LITERAL1+ \ No newline at end of file diff --git a/include/LiquidCrystal/LiquidCrystal.cpp b/include/LiquidCrystal/LiquidCrystal.cpp @@ -0,0 +1,384 @@ +/* + LiquidCrystal.cpp - Liquid Crystal Display library for Wiring & Arduino + Copyright (c) 2006-08 Hernando Barragan and 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 +*/ + +#include "WProgram.h" + +extern "C" { + extern void pinMode(uint8_t, uint8_t); + extern void digitalWrite(uint8_t, uint8_t); + extern uint8_t digitalRead(uint8_t); + extern void portMode(uint8_t, uint8_t); + extern void portWrite(uint8_t, uint8_t); + extern uint8_t portRead(uint8_t); +} + +#include "LiquidCrystal.h" + + +#define WD_LINE0_DDRAMADDR 0x00 +#define WD_LINE1_DDRAMADDR 0x40 +#define WD_LINE2_DDRAMADDR 0x14 +#define WD_LINE3_DDRAMADDR 0x54 + +#define WD_CLR 0 +#define WD_HOME 1 +#define WD_ENTRY_MODE 2 +#define WD_ENTRY_INC 1 +#define WD_ENTRY_SHIFT 0 +#define WD_ON_CTRL 3 +#define WD_ON_DISPLAY 2 +#define WD_ON_CURSOR 1 +#define WD_ON_BLINK 0 +#define WD_MOVE 4 +#define WD_MOVE_DISP 3 +#define WD_MOVE_RIGHT 2 +#define WD_FUNCTION 5 +#define WD_FUNCTION_8BIT 4 +#define WD_FUNCTION_2LINES 3 +#define WD_FUNCTION_10DOTS 2 +#define WD_CGRAM 6 +#define WD_DDRAM 7 +#define WD_BUSY 7 +#define WD_DELAY asm volatile ("nop"); asm volatile ("nop") +//#define DATA_8_BITS 0x0 +//#define DATA_4_BITS 0x1 + + +void LiquidCrystal::display_init(void) { + // initialize WD control lines + digitalWrite(_control_rs, LOW); + digitalWrite(_control_rw, LOW); + digitalWrite(_control_e, LOW); + // initialize WD control lines to output + pinMode(_control_rs, OUTPUT); + pinMode(_control_rw, OUTPUT); + pinMode(_control_e, OUTPUT); + portMode(_port, INPUT); + portWrite(_port, 0xff); +} + +void LiquidCrystal::display_wait(void) { + digitalWrite(_control_rs, LOW); + + portMode(_port, INPUT); + portWrite(_port, 0x00); + + digitalWrite(_control_rw, HIGH); + digitalWrite(_control_e, HIGH); + + WD_DELAY; + while(portRead(_port) & 1<<WD_BUSY) { + digitalWrite(_control_e, LOW); + WD_DELAY; + WD_DELAY; + digitalWrite(_control_e, HIGH); + WD_DELAY; + WD_DELAY; + } + digitalWrite(_control_e, LOW); +} + + +void LiquidCrystal::display_control_write(uint8_t data) { + display_wait(); + digitalWrite(_control_rs, LOW); + digitalWrite(_control_rw, LOW); + + digitalWrite(_control_e, HIGH); + portMode(_port, OUTPUT); + portWrite(_port, data); + + WD_DELAY; + WD_DELAY; + digitalWrite(_control_e, LOW); + + portMode(_port, INPUT); + portWrite(_port, 0xff); +} + + +uint8_t LiquidCrystal::display_control_read(void) { + register uint8_t data; + display_wait(); + portMode(_port, INPUT); + portWrite(_port, 0xff); + + digitalWrite(_control_rs, LOW); + digitalWrite(_control_rw, HIGH); + + digitalWrite(_control_e, HIGH); + WD_DELAY; + WD_DELAY; + data = portRead(_port); + digitalWrite(_control_e, LOW); + return data; +} + +void LiquidCrystal::display_data_write(uint8_t data) { + display_wait(); + digitalWrite(_control_rs, HIGH); + digitalWrite(_control_rw, LOW); + + digitalWrite(_control_e, HIGH); + portMode(_port, OUTPUT); + portWrite(_port, data); + + WD_DELAY; + WD_DELAY; + digitalWrite(_control_e, LOW); + + portMode(_port, INPUT); + portWrite(_port, 0xff); +} + +uint8_t LiquidCrystal::display_data_read(void) { + register uint8_t data; + display_wait(); + portMode(_port, INPUT); + portWrite(_port, 0xff); + + digitalWrite(_control_rs, HIGH); + digitalWrite(_control_rw, HIGH); + + digitalWrite(_control_e, HIGH); + WD_DELAY; + WD_DELAY; + data = portRead(_port); + digitalWrite(_control_e, LOW); + return data; +} + +/* +void LiquidCrystal::display_load_char(uint8_t* wdCustomCharArray, uint8_t romCharNum, uint8_t wdCharNum) { + register uint8_t i; + uint8_t saveDDRAMAddr; + + // backup the current cursor position + saveDDRAMAddr = display_control_read() & 0x7F; + + // multiply the character index by 8 + wdCharNum = (wdCharNum<<3); // each character occupies 8 bytes + romCharNum = (romCharNum<<3); // each character occupies 8 bytes + + // copy the 8 bytes into CG (character generator) RAM + for(i=0; i<8; i++) { + // set CG RAM address + display_control_write((1<<WD_CGRAM) | (wdCharNum+i)); + // write character data + display_data_drite( pgm_read_byte(wdCustomCharArray+romCharNum+i) ); + } + // restore the previous cursor position + display_control_write(1<<WD_DDRAM | saveDDRAMAddr); +} +*/ + +void LiquidCrystal::display_write(char* data, uint8_t len) { + register uint8_t i; + if (!data) return; + for(i=0; i<len; i++) { + display_data_write(data[i]); + } +} + + + +//////////////////Public API + + + +/* +LiquidCrystal::LiquidCrystal() +{ + _control_rs = 8; + _control_rw = 9; + _control_e = 10; + _port = 2; + display_start(); +} +*/ + +LiquidCrystal::LiquidCrystal(uint8_t rs, uint8_t rw, uint8_t e, uint8_t port) { + _control_rs = rs; + _control_rw = rw; + _control_e = e; + _port = port; + display_start(); +} + +void LiquidCrystal::display_start() +{ + display_init(); + display_control_write(((1<<WD_FUNCTION) | (1<<WD_FUNCTION_8BIT) | (1<<WD_FUNCTION_2LINES))); + display_control_write(1<<WD_CLR); + display_control_write(1<<WD_ENTRY_MODE | 1<<WD_ENTRY_INC); + // set display to on + //display_control_write(1<<WD_ON_CTRL | 1<<WD_ON_DISPLAY | 1<<WD_ON_BLINK); + display_control_write(1<<WD_ON_CTRL | 1<<WD_ON_DISPLAY ); + display_control_write(1<<WD_HOME); + // set data address to 0 + display_control_write(1<<WD_DDRAM | 0x00); +} + +/* +uint8_t LiquidCrystal::read(void) +{ + return display_data_read(); +} +*/ + +void LiquidCrystal::clear() { + display_control_write(1<<WD_CLR); +} + +void LiquidCrystal::home() { + display_control_write(1<<WD_HOME); +} + +void LiquidCrystal::setCursor(uint8_t x, uint8_t y) { + register uint8_t DDRAMAddr; + + // remap lines into proper order + switch(y) { + case 0: DDRAMAddr = WD_LINE0_DDRAMADDR+x; break; + case 1: DDRAMAddr = WD_LINE1_DDRAMADDR+x; break; + case 2: DDRAMAddr = WD_LINE2_DDRAMADDR+x; break; + case 3: DDRAMAddr = WD_LINE3_DDRAMADDR+x; break; + default: DDRAMAddr = WD_LINE0_DDRAMADDR+x; + } + // set data address + display_control_write(1<<WD_DDRAM | DDRAMAddr); +} + +/* +void LiquidCrystal::print(char c) +{ + display_write(&c, 1); +} + +void LiquidCrystal::print(char c[]) +{ + display_write(c, strlen(c)); +} + + +void LiquidCrystal::print(String &str) +{ + print(str.toCharArray()); +} +*/ + +void LiquidCrystal::write(uint8_t b) +{ + char c = b; + display_write(&c, 1); +} + +/* +void LiquidCrystal::print(int n) +{ + print((long) n); +} + +void LiquidCrystal::print(long n) +{ + if (n < 0) { + print('-'); + n = -n; + } + printNumber(n, 10); +} + +void LiquidCrystal::print(long n, int base) +{ + if (base == 0) + print((char) n); + else if (base == 10) + print(n); + else + printNumber(n, base); +} + +void LiquidCrystal::println(void) +{ + print('\n'); +} + +void LiquidCrystal::println(char c) +{ + print(c); + println(); +} + +void LiquidCrystal::println(char c[]) +{ + display_write(c, strlen(c)); + println(); +} + + +void LiquidCrystal::println(String &str) +{ + print(str); + println(); +} + + +void LiquidCrystal::println(uint8_t b) +{ + print(b); + println(); +} + +void LiquidCrystal::println(int n) +{ + println((long) n); +} + +void LiquidCrystal::println(long n) +{ + print(n); + println(); +} + +void LiquidCrystal::println(long n, int base) +{ + print(n, base); + println(); +} + +// Private Methods ///////////////////////////////////////////////////////////// + +void LiquidCrystal::printNumber(unsigned long n, uint8_t base) +{ + uint8_t buf[8 * sizeof(long)]; // Assumes 8-bit chars. + int i = 0; + if (n == 0) { + print('0'); + return; + } + while (n > 0) { + buf[i++] = n % base; + n /= base; + } + for (i--; i >= 0; i--){ + print((char)(buf[i] < 10 ? '0' + buf[i] : 'A' + buf[i] - 10)); + } +} +*/ diff --git a/include/LiquidCrystal/LiquidCrystal.h b/include/LiquidCrystal/LiquidCrystal.h @@ -0,0 +1,74 @@ +/* + LiquidCrystal.cpp - Liquid Crystal Display library for Wiring & Arduino + Copyright (c) 2006-08 Hernando Barragan and 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 LiquidCrystal_h +#define LiquidCrystal_h + + +#include <inttypes.h> +#include "Print.h" + +class LiquidCrystal : public Print +{ + private: + uint8_t _control_rs; + uint8_t _control_rw; + uint8_t _control_e; + uint8_t _port; + void display_init(void); + void display_start(void); + void display_wait(void); + void display_control_write(uint8_t); + uint8_t display_control_read(void); + void display_data_write(uint8_t); + uint8_t display_data_read(void); + void display_write(char *, uint8_t); + void printNumber(unsigned long, uint8_t); + public: + //LiquidCrystal(); + LiquidCrystal(uint8_t, uint8_t, uint8_t, uint8_t); +// uint8_t read(void); + void clear(void); + void home(void); + void setCursor(uint8_t, uint8_t); + virtual void write(uint8_t); + +/* + void print(char); + void print(char[]); + void print(String &); + void print(uint8_t); + void print(int); + void print(long); + void print(long, int); + void println(void); + void println(char); + void println(char[]); + void println(String &); + void println(uint8_t); + void println(int); + void println(long); + void println(long, int); +*/ +}; + + +#endif diff --git a/include/LiquidCrystal/examples/PrintData/PrintData.pde b/include/LiquidCrystal/examples/PrintData/PrintData.pde @@ -0,0 +1,32 @@ +/** + * LCD print + * by BARRAGAN <http://barraganstudio.com> + * + * Demonstrates the use of a generic text liquid crystal dsplay (LCD) + * to print the value of a variable + */ + +#include <LiquidCrystal.h> + +// creates a LiquidDisplay object with R/S, R/W and E on pins 8,9,10 and +// data pins on port 2 +LiquidCrystal myDisplay = LiquidCrystal(8,9,10,2); + +void setup() +{ + // nothing for setup +} + +int a = 0; + +void loop() +{ + myDisplay.clear(); + myDisplay.home(); + myDisplay.print("Variable a is: "); + myDisplay.setCursor(16, 0); + myDisplay.print(a); + a = a + 1; + delay(200); +} + diff --git a/include/LiquidCrystal/examples/PrintData/PrintData.png b/include/LiquidCrystal/examples/PrintData/PrintData.png Binary files differ. diff --git a/include/LiquidCrystal/keywords.txt b/include/LiquidCrystal/keywords.txt @@ -0,0 +1,24 @@ +####################################### +# Syntax Coloring Map For LiquidCrystal +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +LiquidCrystal KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +clear KEYWORD2 +home KEYWORD2 +print KEYWORD2 +println KEYWORD2 +setCursor KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + diff --git a/include/Matrix/Matrix.cpp b/include/Matrix/Matrix.cpp @@ -0,0 +1,214 @@ +/* + Matrix.cpp - Max7219 LED Matrix 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 +*/ + +// TODO: Support segment displays in api? +// TODO: Support varying vendor layouts? + +/****************************************************************************** + * Includes + ******************************************************************************/ + +#include "Matrix.h" + +// include description files for other libraries depended on (if any) +#include "Sprite.h" + + +/****************************************************************************** + * Definitions + ******************************************************************************/ + +// Matrix registers +#define REG_NOOP 0x00 +#define REG_DIGIT0 0x01 +#define REG_DIGIT1 0x02 +#define REG_DIGIT2 0x03 +#define REG_DIGIT3 0x04 +#define REG_DIGIT4 0x05 +#define REG_DIGIT5 0x06 +#define REG_DIGIT6 0x07 +#define REG_DIGIT7 0x08 +#define REG_DECODEMODE 0x09 +#define REG_INTENSITY 0x0A +#define REG_SCANLIMIT 0x0B +#define REG_SHUTDOWN 0x0C +#define REG_DISPLAYTEST 0x0F + +/****************************************************************************** + * Constructors + ******************************************************************************/ + +Matrix::Matrix(byte data, byte clock, byte load, byte screens /* = 1 */) +{ + // record pins for sw spi + _pinData = data; + _pinClock = clock; + _pinLoad = load;