diff --git a/cores/validation/validation_firmata/build_as6/test.atsln b/cores/validation/validation_firmata/build_as6/test.atsln new file mode 100644 index 0000000000000000000000000000000000000000..749e8031642f7e15c4630fbe5342fce033772a6c --- /dev/null +++ b/cores/validation/validation_firmata/build_as6/test.atsln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Atmel Studio Solution File, Format Version 11.00 +Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "test", "test.cppproj", "{B3F859AD-E162-4C2F-9684-EAC6932FEC80}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM = Debug|ARM + Release|ARM = Release|ARM + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3F859AD-E162-4C2F-9684-EAC6932FEC80}.Debug|ARM.ActiveCfg = Debug|ARM + {B3F859AD-E162-4C2F-9684-EAC6932FEC80}.Debug|ARM.Build.0 = Debug|ARM + {B3F859AD-E162-4C2F-9684-EAC6932FEC80}.Release|ARM.ActiveCfg = Release|ARM + {B3F859AD-E162-4C2F-9684-EAC6932FEC80}.Release|ARM.Build.0 = Release|ARM + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/cores/validation/validation_firmata/build_as6/test.cppproj b/cores/validation/validation_firmata/build_as6/test.cppproj new file mode 100644 index 0000000000000000000000000000000000000000..9b7f439503a2060204f41696ce078cc27c346db1 --- /dev/null +++ b/cores/validation/validation_firmata/build_as6/test.cppproj @@ -0,0 +1,458 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <SchemaVersion>2.0</SchemaVersion> + <ProjectVersion>6.2</ProjectVersion> + <ToolchainName>com.Atmel.ARMGCC.CPP</ToolchainName> + <ProjectGuid>{b3f859ad-e162-4c2f-9684-eac6932fec80}</ProjectGuid> + <avrdevice>ATSAMD21G18A</avrdevice> + <avrdeviceseries>none</avrdeviceseries> + <OutputType>Executable</OutputType> + <Language>CPP</Language> + <OutputFileName>$(MSBuildProjectName)</OutputFileName> + <OutputFileExtension>.elf</OutputFileExtension> + <OutputDirectory>$(MSBuildProjectDirectory)\$(Configuration)</OutputDirectory> + <AssemblyName>test</AssemblyName> + <Name>test</Name> + <RootNamespace>test</RootNamespace> + <ToolchainFlavour>Native</ToolchainFlavour> + <KeepTimersRunning>true</KeepTimersRunning> + <OverrideVtor>false</OverrideVtor> + <CacheFlash>false</CacheFlash> + <ProgFlashFromRam>true</ProgFlashFromRam> + <RamSnippetAddress>0x20000000</RamSnippetAddress> + <UncachedRange /> + <OverrideVtorValue>exception_table</OverrideVtorValue> + <BootSegment>2</BootSegment> + <eraseonlaunchrule>1</eraseonlaunchrule> + <AsfFrameworkConfig> + <framework-data xmlns=""> + <options /> + <configurations /> + <files /> + <documentation help="" /> + <offline-documentation help="" /> + <dependencies> + <content-extension eid="atmel.asf" uuidref="Atmel.ASF" version="3.17.0" /> + </dependencies> + </framework-data> + </AsfFrameworkConfig> + <avrtool>com.atmel.avrdbg.tool.edbg</avrtool> + <avrtoolinterface>SWD</avrtoolinterface> + <com_atmel_avrdbg_tool_samice> + <ToolOptions> + <InterfaceProperties> + </InterfaceProperties> + <InterfaceName>SWD</InterfaceName> + </ToolOptions> + <ToolType>com.atmel.avrdbg.tool.samice</ToolType> + <ToolNumber>28010306</ToolNumber> + <ToolName>SAM-ICE</ToolName> + </com_atmel_avrdbg_tool_samice> + <UseGdb>True</UseGdb> + <com_atmel_avrdbg_tool_edbg> + <ToolOptions> + <InterfaceProperties> + <SwdClock>4000000</SwdClock> + </InterfaceProperties> + <InterfaceName>SWD</InterfaceName> + </ToolOptions> + <ToolType>com.atmel.avrdbg.tool.edbg</ToolType> + <ToolNumber>ATML2320021800000009</ToolNumber> + <ToolName>EDBG</ToolName> + </com_atmel_avrdbg_tool_edbg> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Release' "> + <ToolchainSettings> + <ArmGccCpp> + <armgcc.common.outputfiles.hex>True</armgcc.common.outputfiles.hex> + <armgcc.common.outputfiles.lss>True</armgcc.common.outputfiles.lss> + <armgcc.common.outputfiles.eep>True</armgcc.common.outputfiles.eep> + <armgcc.common.outputfiles.bin>True</armgcc.common.outputfiles.bin> + <armgcc.common.outputfiles.srec>True</armgcc.common.outputfiles.srec> + <armgcc.compiler.symbols.DefSymbols> + <ListValues> + <Value>NDEBUG</Value> + </ListValues> + </armgcc.compiler.symbols.DefSymbols> + <armgcc.compiler.directories.IncludePaths> + <ListValues> + <Value>../../../../../../../tools/CMSIS/Device/ATMEL</Value> + <Value>../../../../../../../tools/CMSIS/CMSIS/Include</Value> + <Value>../../../../arduino</Value> + <Value>../../../../arduino/USB</Value> + <Value>../../../../../variants/arduino_zero</Value> + <Value>../../../../../libraries/SPI</Value> + <Value>../../../../../libraries/Wire</Value> + </ListValues> + </armgcc.compiler.directories.IncludePaths> + <armgcc.compiler.optimization.level>Optimize for size (-Os)</armgcc.compiler.optimization.level> + <armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection> + <armgcc.compiler.warnings.AllWarnings>True</armgcc.compiler.warnings.AllWarnings> + <armgcccpp.compiler.symbols.DefSymbols> + <ListValues> + <Value>NDEBUG</Value> + </ListValues> + </armgcccpp.compiler.symbols.DefSymbols> + <armgcccpp.compiler.directories.IncludePaths> + <ListValues> + <Value>../../../../../../../tools/CMSIS/Device/ATMEL</Value> + <Value>../../../../../../../tools/CMSIS/CMSIS/Include</Value> + <Value>../../../../arduino</Value> + <Value>../../../../arduino/USB</Value> + <Value>../../../../../variants/arduino_zero</Value> + <Value>../../../../../libraries/SPI</Value> + <Value>../../../../../libraries/Wire</Value> + </ListValues> + </armgcccpp.compiler.directories.IncludePaths> + <armgcccpp.compiler.optimization.level>Optimize for size (-Os)</armgcccpp.compiler.optimization.level> + <armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection> + <armgcccpp.compiler.warnings.AllWarnings>True</armgcccpp.compiler.warnings.AllWarnings> + <armgcccpp.linker.libraries.Libraries> + <ListValues> + <Value>libm</Value> + </ListValues> + </armgcccpp.linker.libraries.Libraries> + <armgcccpp.linker.libraries.LibrarySearchPaths> + <ListValues> + <Value>../cmsis/linkerScripts</Value> + </ListValues> + </armgcccpp.linker.libraries.LibrarySearchPaths> + <armgcccpp.linker.optimization.GarbageCollectUnusedSections>True</armgcccpp.linker.optimization.GarbageCollectUnusedSections> + <armgcccpp.linker.miscellaneous.LinkerFlags>-Tsamd21g18a_flash.ld</armgcccpp.linker.miscellaneous.LinkerFlags> + <armgcccpp.preprocessingassembler.general.IncludePaths> + <ListValues> + <Value>../../../../../../../tools/CMSIS/Device/ATMEL</Value> + <Value>../../../../../../../tools/CMSIS/CMSIS/Include</Value> + <Value>../../../../arduino</Value> + <Value>../../../../arduino/USB</Value> + <Value>../../../../../variants/arduino_zero</Value> + <Value>../../../../../libraries/SPI</Value> + <Value>../../../../../libraries/Wire</Value> + </ListValues> + </armgcccpp.preprocessingassembler.general.IncludePaths> + </ArmGccCpp> + </ToolchainSettings> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> + <ToolchainSettings> + <ArmGccCpp> + <armgcc.common.outputfiles.hex>True</armgcc.common.outputfiles.hex> + <armgcc.common.outputfiles.lss>True</armgcc.common.outputfiles.lss> + <armgcc.common.outputfiles.eep>True</armgcc.common.outputfiles.eep> + <armgcc.common.outputfiles.bin>True</armgcc.common.outputfiles.bin> + <armgcc.common.outputfiles.srec>True</armgcc.common.outputfiles.srec> + <armgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</armgcc.compiler.general.ChangeDefaultCharTypeUnsigned> + <armgcc.compiler.symbols.DefSymbols> + <ListValues> + <Value>DEBUG</Value> + </ListValues> + </armgcc.compiler.symbols.DefSymbols> + <armgcc.compiler.directories.DefaultIncludePath>False</armgcc.compiler.directories.DefaultIncludePath> + <armgcc.compiler.directories.IncludePaths> + <ListValues> + <Value>../../../../../../../tools/CMSIS/Device/ATMEL</Value> + <Value>../../../../../../../tools/CMSIS/CMSIS/Include</Value> + <Value>../../../../arduino</Value> + <Value>../../../../arduino/USB</Value> + <Value>../../../../../variants/arduino_zero</Value> + <Value>../../../../../libraries/SPI</Value> + <Value>../../../../../libraries/Wire</Value> + </ListValues> + </armgcc.compiler.directories.IncludePaths> + <armgcc.compiler.optimization.level>Optimize (-O1)</armgcc.compiler.optimization.level> + <armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcc.compiler.optimization.PrepareFunctionsForGarbageCollection> + <armgcc.compiler.optimization.PrepareDataForGarbageCollection>True</armgcc.compiler.optimization.PrepareDataForGarbageCollection> + <armgcc.compiler.optimization.DebugLevel>Maximum (-g3)</armgcc.compiler.optimization.DebugLevel> + <armgcc.compiler.warnings.AllWarnings>True</armgcc.compiler.warnings.AllWarnings> + <armgcc.compiler.miscellaneous.OtherFlags>-std=c99</armgcc.compiler.miscellaneous.OtherFlags> + <armgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</armgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned> + <armgcccpp.compiler.symbols.DefSymbols> + <ListValues> + <Value>DEBUG</Value> + <Value>USB_VID=0x2341</Value> + <Value>USB_PID=0x004d</Value> + </ListValues> + </armgcccpp.compiler.symbols.DefSymbols> + <armgcccpp.compiler.directories.DefaultIncludePath>False</armgcccpp.compiler.directories.DefaultIncludePath> + <armgcccpp.compiler.directories.IncludePaths> + <ListValues> + <Value>../../../../../../../tools/CMSIS/Device/ATMEL</Value> + <Value>../../../../../../../tools/CMSIS/CMSIS/Include</Value> + <Value>../../../../arduino</Value> + <Value>../../../../arduino/USB</Value> + <Value>../../../../../variants/arduino_zero</Value> + <Value>../../../../../libraries/SPI</Value> + <Value>../../../../../libraries/Wire</Value> + </ListValues> + </armgcccpp.compiler.directories.IncludePaths> + <armgcccpp.compiler.optimization.level>Optimize (-O1)</armgcccpp.compiler.optimization.level> + <armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareFunctionsForGarbageCollection> + <armgcccpp.compiler.optimization.PrepareDataForGarbageCollection>True</armgcccpp.compiler.optimization.PrepareDataForGarbageCollection> + <armgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</armgcccpp.compiler.optimization.DebugLevel> + <armgcccpp.compiler.warnings.AllWarnings>True</armgcccpp.compiler.warnings.AllWarnings> + <armgcccpp.compiler.miscellaneous.OtherFlags>-std=c++98</armgcccpp.compiler.miscellaneous.OtherFlags> + <armgcccpp.linker.general.UseNewlibNano>True</armgcccpp.linker.general.UseNewlibNano> + <armgcccpp.linker.libraries.Libraries> + <ListValues> + <Value>libm</Value> + </ListValues> + </armgcccpp.linker.libraries.Libraries> + <armgcccpp.linker.libraries.LibrarySearchPaths> + <ListValues> + <Value>../../../../../variants/arduino_zero/linker_scripts/gcc</Value> + </ListValues> + </armgcccpp.linker.libraries.LibrarySearchPaths> + <armgcccpp.linker.optimization.GarbageCollectUnusedSections>True</armgcccpp.linker.optimization.GarbageCollectUnusedSections> + <armgcccpp.linker.memorysettings.ExternalRAM /> + <armgcccpp.linker.miscellaneous.LinkerFlags>--specs=nosys.specs -Tflash_with_bootloader.ld</armgcccpp.linker.miscellaneous.LinkerFlags> + <armgcccpp.assembler.general.IncludePaths> + <ListValues> + <Value>../../../arduino</Value> + </ListValues> + </armgcccpp.assembler.general.IncludePaths> + <armgcccpp.assembler.debugging.DebugLevel>Default (-g)</armgcccpp.assembler.debugging.DebugLevel> + <armgcccpp.preprocessingassembler.general.DefaultIncludePath>False</armgcccpp.preprocessingassembler.general.DefaultIncludePath> + <armgcccpp.preprocessingassembler.general.IncludePaths> + <ListValues> + <Value>../../../arduino</Value> + </ListValues> + </armgcccpp.preprocessingassembler.general.IncludePaths> + <armgcccpp.preprocessingassembler.debugging.DebugLevel>Default (-Wa,-g)</armgcccpp.preprocessingassembler.debugging.DebugLevel> + </ArmGccCpp> + </ToolchainSettings> + </PropertyGroup> + <ItemGroup> + <Folder Include="core" /> + <Folder Include="Wire" /> + <Folder Include="SPI" /> + <Folder Include="variant" /> + </ItemGroup> + <ItemGroup> + <Compile Include="..\..\..\..\libraries\SPI\SPI.cpp"> + <SubType>compile</SubType> + <Link>SPI\SPI.cpp</Link> + </Compile> + <Compile Include="..\..\..\..\libraries\SPI\SPI.h"> + <SubType>compile</SubType> + <Link>SPI\SPI.h</Link> + </Compile> + <Compile Include="..\..\..\..\libraries\Wire\Wire.cpp"> + <SubType>compile</SubType> + <Link>Wire\Wire.cpp</Link> + </Compile> + <Compile Include="..\..\..\..\libraries\Wire\Wire.h"> + <SubType>compile</SubType> + <Link>Wire\Wire.h</Link> + </Compile> + <Compile Include="..\..\..\..\variants\arduino_zero\pins_arduino.h"> + <SubType>compile</SubType> + <Link>variant\pins_arduino.h</Link> + </Compile> + <Compile Include="..\..\..\..\variants\arduino_zero\variant.cpp"> + <SubType>compile</SubType> + <Link>variant\variant.cpp</Link> + </Compile> + <Compile Include="..\..\..\..\variants\arduino_zero\variant.h"> + <SubType>compile</SubType> + <Link>variant\variant.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Arduino.h"> + <SubType>compile</SubType> + <Link>core\Arduino.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\binary.h"> + <SubType>compile</SubType> + <Link>core\binary.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Client.h"> + <SubType>compile</SubType> + <Link>core\Client.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\delay.c"> + <SubType>compile</SubType> + <Link>core\delay.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\delay.h"> + <SubType>compile</SubType> + <Link>core\delay.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\HardwareSerial.h"> + <SubType>compile</SubType> + <Link>core\HardwareSerial.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\hooks.c"> + <SubType>compile</SubType> + <Link>core\hooks.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\IPAddress.cpp"> + <SubType>compile</SubType> + <Link>core\IPAddress.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\IPAddress.h"> + <SubType>compile</SubType> + <Link>core\IPAddress.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\itoa.c"> + <SubType>compile</SubType> + <Link>core\itoa.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\itoa.h"> + <SubType>compile</SubType> + <Link>core\itoa.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\main.cpp"> + <SubType>compile</SubType> + <Link>core\main.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\Print.cpp"> + <SubType>compile</SubType> + <Link>core\Print.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\Print.h"> + <SubType>compile</SubType> + <Link>core\Print.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Printable.h"> + <SubType>compile</SubType> + <Link>core\Printable.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Reset.cpp"> + <SubType>compile</SubType> + <Link>core\Reset.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\Reset.h"> + <SubType>compile</SubType> + <Link>core\Reset.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\RingBuffer.cpp"> + <SubType>compile</SubType> + <Link>core\RingBuffer.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\RingBuffer.h"> + <SubType>compile</SubType> + <Link>core\RingBuffer.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\SERCOM.cpp"> + <SubType>compile</SubType> + <Link>core\SERCOM.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\SERCOM.h"> + <SubType>compile</SubType> + <Link>core\SERCOM.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Server.h"> + <SubType>compile</SubType> + <Link>core\Server.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\startup.c"> + <SubType>compile</SubType> + <Link>core\startup.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\Stream.cpp"> + <SubType>compile</SubType> + <Link>core\Stream.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\Stream.h"> + <SubType>compile</SubType> + <Link>core\Stream.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Tone.h"> + <SubType>compile</SubType> + <Link>core\Tone.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Uart.cpp"> + <SubType>compile</SubType> + <Link>core\Uart.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\Uart.h"> + <SubType>compile</SubType> + <Link>core\Uart.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\Udp.h"> + <SubType>compile</SubType> + <Link>core\Udp.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\WCharacter.h"> + <SubType>compile</SubType> + <Link>core\WCharacter.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\WInterrupts.c"> + <SubType>compile</SubType> + <Link>core\WInterrupts.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\WInterrupts.h"> + <SubType>compile</SubType> + <Link>core\WInterrupts.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring.c"> + <SubType>compile</SubType> + <Link>core\wiring.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring.h"> + <SubType>compile</SubType> + <Link>core\wiring.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_analog.c"> + <SubType>compile</SubType> + <Link>core\wiring_analog.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_analog.h"> + <SubType>compile</SubType> + <Link>core\wiring_analog.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_constants.h"> + <SubType>compile</SubType> + <Link>core\wiring_constants.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_digital.c"> + <SubType>compile</SubType> + <Link>core\wiring_digital.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_digital.h"> + <SubType>compile</SubType> + <Link>core\wiring_digital.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_private.h"> + <SubType>compile</SubType> + <Link>core\wiring_private.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_pulse.h"> + <SubType>compile</SubType> + <Link>core\wiring_pulse.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_shift.c"> + <SubType>compile</SubType> + <Link>core\wiring_shift.c</Link> + </Compile> + <Compile Include="..\..\..\arduino\wiring_shift.h"> + <SubType>compile</SubType> + <Link>core\wiring_shift.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\WMath.cpp"> + <SubType>compile</SubType> + <Link>core\WMath.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\WMath.h"> + <SubType>compile</SubType> + <Link>core\WMath.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\WString.cpp"> + <SubType>compile</SubType> + <Link>core\WString.cpp</Link> + </Compile> + <Compile Include="..\..\..\arduino\WString.h"> + <SubType>compile</SubType> + <Link>core\WString.h</Link> + </Compile> + <Compile Include="..\..\..\arduino\WVariant.h"> + <SubType>compile</SubType> + <Link>core\WVariant.h</Link> + </Compile> + <Compile Include="..\test.cpp"> + <SubType>compile</SubType> + <Link>test.cpp</Link> + </Compile> + </ItemGroup> + <Import Project="$(AVRSTUDIO_EXE_PATH)\\Vs\\Compiler.targets" /> +</Project> \ No newline at end of file diff --git a/cores/validation/validation_firmata/test.cpp b/cores/validation/validation_firmata/test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d3ba59281565d03f060ce16b0a53a5458e3a0c0 --- /dev/null +++ b/cores/validation/validation_firmata/test.cpp @@ -0,0 +1,668 @@ +/* + Copyright (c) 2014 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "Arduino.h" + +/* + * Firmata is a generic protocol for communicating with microcontrollers + * from software on a host computer. It is intended to work with + * any host computer software package. + * + * To download a host software package, please clink on the following link + * to open the download page in your default browser. + * + * http://firmata.org/wiki/Download + */ + +/* + Copyright (C) 2006-2008 Hans-Christoph Steiner. All rights reserved. + Copyright (C) 2010-2011 Paul Stoffregen. All rights reserved. + Copyright (C) 2009 Shigeru Kobayashi. All rights reserved. + Copyright (C) 2009-2011 Jeff Hoefs. All rights reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + See file LICENSE.txt for further informations on licensing terms. + + formatted using the GNU C formatting and indenting +*/ + +/* + * TODO: use Program Control to load stored profiles from EEPROM + */ + +//#include <Servo.h> +#include <Wire.h> +#include <Firmata.h> + +// move the following defines to Firmata.h? +#define I2C_WRITE B00000000 +#define I2C_READ B00001000 +#define I2C_READ_CONTINUOUSLY B00010000 +#define I2C_STOP_READING B00011000 +#define I2C_READ_WRITE_MODE_MASK B00011000 +#define I2C_10BIT_ADDRESS_MODE_MASK B00100000 + +#define MAX_QUERIES 8 +#define MINIMUM_SAMPLING_INTERVAL 10 + +#define REGISTER_NOT_SPECIFIED -1 + +/*============================================================================== + * GLOBAL VARIABLES + *============================================================================*/ + +/* analog inputs */ +int analogInputsToReport = 0; // bitwise array to store pin reporting + +/* digital input ports */ +byte reportPINs[TOTAL_PORTS]; // 1 = report this port, 0 = silence +byte previousPINs[TOTAL_PORTS]; // previous 8 bits sent + +/* pins configuration */ +byte pinConfig[TOTAL_PINS]; // configuration of every pin +byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else +int pinState[TOTAL_PINS]; // any value that has been written + +/* timer variables */ +unsigned long currentMillis; // store the current value from millis() +unsigned long previousMillis; // for comparison with currentMillis +int samplingInterval = 19; // how often to run the main loop (in ms) + +/* i2c data */ +struct i2c_device_info { + byte addr; + byte reg; + byte bytes; +}; + +/* for i2c read continuous more */ +i2c_device_info query[MAX_QUERIES]; + +byte i2cRxData[32]; +boolean isI2CEnabled = false; +signed char queryIndex = -1; +unsigned int i2cReadDelayTime = 0; // default delay time between i2c read request and Wire.requestFrom() + +//Servo servos[MAX_SERVOS]; +/*============================================================================== + * FUNCTIONS + *============================================================================*/ + +void readAndReportData(byte address, int theRegister, byte numBytes) { + // allow I2C requests that don't require a register read + // for example, some devices using an interrupt pin to signify new data available + // do not always require the register read so upon interrupt you call Wire.requestFrom() + if (theRegister != REGISTER_NOT_SPECIFIED) { + Wire.beginTransmission(address); +#if ARDUINO >= 100 + Wire.write((byte)theRegister); +#else + Wire.send((byte)theRegister); +#endif + Wire.endTransmission(); + // do not set a value of 0 + if (i2cReadDelayTime > 0) { + // delay is necessary for some devices such as WiiNunchuck + delayMicroseconds(i2cReadDelayTime); + } + } else { + theRegister = 0; // fill the register with a dummy value + } + + Wire.requestFrom(address, numBytes); // all bytes are returned in requestFrom + + // check to be sure correct number of bytes were returned by slave + if (numBytes == Wire.available()) { + i2cRxData[0] = address; + i2cRxData[1] = theRegister; + for (int i = 0; i < numBytes; i++) { +#if ARDUINO >= 100 + i2cRxData[2 + i] = Wire.read(); +#else + i2cRxData[2 + i] = Wire.receive(); +#endif + } + } + else { + if (numBytes > Wire.available()) { + Firmata.sendString("I2C Read Error: Too many bytes received"); + } else { + Firmata.sendString("I2C Read Error: Too few bytes received"); + } + } + + // send slave address, register and received bytes + Firmata.sendSysex(SYSEX_I2C_REPLY, numBytes + 2, i2cRxData); +} + +void outputPort(byte portNumber, byte portValue, byte forceSend) +{ + // pins not configured as INPUT are cleared to zeros + portValue = portValue & portConfigInputs[portNumber]; + // only send if the value is different than previously sent + if (forceSend || previousPINs[portNumber] != portValue) { + Firmata.sendDigitalPort(portNumber, portValue); + previousPINs[portNumber] = portValue; + } +} + +/* ----------------------------------------------------------------------------- + * check all the active digital inputs for change of state, then add any events + * to the Serial output queue using Serial.print() */ +void checkDigitalInputs(void) +{ + /* Using non-looping code allows constants to be given to readPort(). + * The compiler will apply substantial optimizations if the inputs + * to readPort() are compile-time constants. */ + if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false); + if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false); + if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false); + if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false); + if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false); + if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false); + if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false); + if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false); + if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false); + if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false); + if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false); + if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false); + if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false); + if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false); + if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false); + if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false); +} + +// ----------------------------------------------------------------------------- +/* sets the pin mode to the correct state and sets the relevant bits in the + * two bit-arrays that track Digital I/O and PWM status + */ +void setPinModeCallback(byte pin, int mode) +{ + if (pinConfig[pin] == I2C && isI2CEnabled && mode != I2C) { + // disable i2c so pins can be used for other functions + // the following if statements should reconfigure the pins properly + disableI2CPins(); + } +/* + if (IS_PIN_SERVO(pin) && mode != SERVO && servos[PIN_TO_SERVO(pin)].attached()) { + servos[PIN_TO_SERVO(pin)].detach(); + } +*/ + if (IS_PIN_ANALOG(pin)) { + reportAnalogCallback(PIN_TO_ANALOG(pin), mode == ANALOG ? 1 : 0); // turn on/off reporting + } + if (IS_PIN_DIGITAL(pin)) { + if (mode == INPUT) { + portConfigInputs[pin / 8] |= (1 << (pin & 7)); + } else { + portConfigInputs[pin / 8] &= ~(1 << (pin & 7)); + } + } + pinState[pin] = 0; + switch (mode) { + case ANALOG: + if (IS_PIN_ANALOG(pin)) { + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + } + pinConfig[pin] = ANALOG; + } + break; + case INPUT: + if (IS_PIN_DIGITAL(pin)) { + pinMode(PIN_TO_DIGITAL(pin), INPUT); // disable output driver + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups + pinConfig[pin] = INPUT; + } + break; + case OUTPUT: + if (IS_PIN_DIGITAL(pin)) { + digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable PWM + pinMode(PIN_TO_DIGITAL(pin), OUTPUT); + pinConfig[pin] = OUTPUT; + } + break; + case PWM: + if (IS_PIN_PWM(pin)) { + pinMode(PIN_TO_PWM(pin), OUTPUT); + analogWrite(PIN_TO_PWM(pin), 0); + pinConfig[pin] = PWM; + } + break; +/* + case SERVO: + if (IS_PIN_SERVO(pin)) { + pinConfig[pin] = SERVO; + if (!servos[PIN_TO_SERVO(pin)].attached()) { + servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin)); + } + } + break; +*/ + case I2C: + if (IS_PIN_I2C(pin)) { + // mark the pin as i2c + // the user must call I2C_CONFIG to enable I2C for a device + pinConfig[pin] = I2C; + } + break; + default: + Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM + } + // TODO: save status to EEPROM here, if changed +} + +void analogWriteCallback(byte pin, int value) +{ + if (pin < TOTAL_PINS) { + switch (pinConfig[pin]) { +/* + case SERVO: + if (IS_PIN_SERVO(pin)) + servos[PIN_TO_SERVO(pin)].write(value); + pinState[pin] = value; + break; +*/ + case PWM: + if (IS_PIN_PWM(pin)) + analogWrite(PIN_TO_PWM(pin), value); + pinState[pin] = value; + break; + } + } +} + +void digitalWriteCallback(byte port, int value) +{ + byte pin, lastPin, mask = 1, pinWriteMask = 0; + + if (port < TOTAL_PORTS) { + // create a mask of the pins on this port that are writable. + lastPin = port * 8 + 8; + if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS; + for (pin = port * 8; pin < lastPin; pin++) { + // do not disturb non-digital pins (eg, Rx & Tx) + if (IS_PIN_DIGITAL(pin)) { + // only write to OUTPUT and INPUT (enables pullup) + // do not touch pins in PWM, ANALOG, SERVO or other modes + if (pinConfig[pin] == OUTPUT || pinConfig[pin] == INPUT) { + pinWriteMask |= mask; + pinState[pin] = ((byte)value & mask) ? 1 : 0; + } + } + mask = mask << 1; + } + writePort(port, (byte)value, pinWriteMask); + } +} + + +// ----------------------------------------------------------------------------- +/* sets bits in a bit array (int) to toggle the reporting of the analogIns + */ +//void FirmataClass::setAnalogPinReporting(byte pin, byte state) { +//} +void reportAnalogCallback(byte analogPin, int value) +{ + if (analogPin < TOTAL_ANALOG_PINS) { + if (value == 0) { + analogInputsToReport = analogInputsToReport &~ (1 << analogPin); + } else { + analogInputsToReport = analogInputsToReport | (1 << analogPin); + } + } + // TODO: save status to EEPROM here, if changed +} + +void reportDigitalCallback(byte port, int value) +{ + if (port < TOTAL_PORTS) { + reportPINs[port] = (byte)value; + } + // do not disable analog reporting on these 8 pins, to allow some + // pins used for digital, others analog. Instead, allow both types + // of reporting to be enabled, but check if the pin is configured + // as analog when sampling the analog inputs. Likewise, while + // scanning digital pins, portConfigInputs will mask off values from any + // pins configured as analog +} + +/*============================================================================== + * SYSEX-BASED commands + *============================================================================*/ + +void sysexCallback(byte command, byte argc, byte *argv) +{ + byte mode; + byte slaveAddress; + byte slaveRegister; + byte data; + unsigned int delayTime; + + switch (command) { + case I2C_REQUEST: + mode = argv[1] & I2C_READ_WRITE_MODE_MASK; + if (argv[1] & I2C_10BIT_ADDRESS_MODE_MASK) { + Firmata.sendString("10-bit addressing mode is not yet supported"); + return; + } + else { + slaveAddress = argv[0]; + } + + switch (mode) { + case I2C_WRITE: + Wire.beginTransmission(slaveAddress); + for (byte i = 2; i < argc; i += 2) { + data = argv[i] + (argv[i + 1] << 7); +#if ARDUINO >= 100 + Wire.write(data); +#else + Wire.send(data); +#endif + } + Wire.endTransmission(); + delayMicroseconds(70); + break; + case I2C_READ: + if (argc == 6) { + // a slave register is specified + slaveRegister = argv[2] + (argv[3] << 7); + data = argv[4] + (argv[5] << 7); // bytes to read + readAndReportData(slaveAddress, (int)slaveRegister, data); + } + else { + // a slave register is NOT specified + data = argv[2] + (argv[3] << 7); // bytes to read + readAndReportData(slaveAddress, (int)REGISTER_NOT_SPECIFIED, data); + } + break; + case I2C_READ_CONTINUOUSLY: + if ((queryIndex + 1) >= MAX_QUERIES) { + // too many queries, just ignore + Firmata.sendString("too many queries"); + break; + } + queryIndex++; + query[queryIndex].addr = slaveAddress; + query[queryIndex].reg = argv[2] + (argv[3] << 7); + query[queryIndex].bytes = argv[4] + (argv[5] << 7); + break; + case I2C_STOP_READING: + byte queryIndexToSkip; + // if read continuous mode is enabled for only 1 i2c device, disable + // read continuous reporting for that device + if (queryIndex <= 0) { + queryIndex = -1; + } else { + // if read continuous mode is enabled for multiple devices, + // determine which device to stop reading and remove it's data from + // the array, shifiting other array data to fill the space + for (byte i = 0; i < queryIndex + 1; i++) { + if (query[i].addr = slaveAddress) { + queryIndexToSkip = i; + break; + } + } + + for (byte i = queryIndexToSkip; i < queryIndex + 1; i++) { + if (i < MAX_QUERIES) { + query[i].addr = query[i + 1].addr; + query[i].reg = query[i + 1].addr; + query[i].bytes = query[i + 1].bytes; + } + } + queryIndex--; + } + break; + default: + break; + } + break; + case I2C_CONFIG: + delayTime = (argv[0] + (argv[1] << 7)); + + if (delayTime > 0) { + i2cReadDelayTime = delayTime; + } + + if (!isI2CEnabled) { + enableI2CPins(); + } + + break; +/* + case SERVO_CONFIG: + if (argc > 4) { + // these vars are here for clarity, they'll optimized away by the compiler + byte pin = argv[0]; + int minPulse = argv[1] + (argv[2] << 7); + int maxPulse = argv[3] + (argv[4] << 7); + + if (IS_PIN_SERVO(pin)) { + if (servos[PIN_TO_SERVO(pin)].attached()) + servos[PIN_TO_SERVO(pin)].detach(); + servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin), minPulse, maxPulse); + setPinModeCallback(pin, SERVO); + } + } + break; +*/ + case SAMPLING_INTERVAL: + if (argc > 1) { + samplingInterval = argv[0] + (argv[1] << 7); + if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) { + samplingInterval = MINIMUM_SAMPLING_INTERVAL; + } + } else { + //Firmata.sendString("Not enough data"); + } + break; + case EXTENDED_ANALOG: + if (argc > 1) { + int val = argv[1]; + if (argc > 2) val |= (argv[2] << 7); + if (argc > 3) val |= (argv[3] << 14); + analogWriteCallback(argv[0], val); + } + break; + case CAPABILITY_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(CAPABILITY_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_DIGITAL(pin)) { + Firmata.write((byte)INPUT); + Firmata.write(1); + Firmata.write((byte)OUTPUT); + Firmata.write(1); + } + if (IS_PIN_ANALOG(pin)) { + Firmata.write(ANALOG); + Firmata.write(10); + } + if (IS_PIN_PWM(pin)) { + Firmata.write(PWM); + Firmata.write(8); + } + if (IS_PIN_SERVO(pin)) { + Firmata.write(SERVO); + Firmata.write(14); + } + if (IS_PIN_I2C(pin)) { + Firmata.write(I2C); + Firmata.write(1); // to do: determine appropriate value + } + Firmata.write(127); + } + Firmata.write(END_SYSEX); + break; + case PIN_STATE_QUERY: + if (argc > 0) { + byte pin = argv[0]; + Firmata.write(START_SYSEX); + Firmata.write(PIN_STATE_RESPONSE); + Firmata.write(pin); + if (pin < TOTAL_PINS) { + Firmata.write((byte)pinConfig[pin]); + Firmata.write((byte)pinState[pin] & 0x7F); + if (pinState[pin] & 0xFF80) Firmata.write((byte)(pinState[pin] >> 7) & 0x7F); + if (pinState[pin] & 0xC000) Firmata.write((byte)(pinState[pin] >> 14) & 0x7F); + } + Firmata.write(END_SYSEX); + } + break; + case ANALOG_MAPPING_QUERY: + Firmata.write(START_SYSEX); + Firmata.write(ANALOG_MAPPING_RESPONSE); + for (byte pin = 0; pin < TOTAL_PINS; pin++) { + Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127); + } + Firmata.write(END_SYSEX); + break; + } +} + +void enableI2CPins() +{ + byte i; + // is there a faster way to do this? would probaby require importing + // Arduino.h to get SCL and SDA pins + for (i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_I2C(i)) { + // mark pins as i2c so they are ignore in non i2c data requests + setPinModeCallback(i, I2C); + } + } + + isI2CEnabled = true; + + // is there enough time before the first I2C request to call this here? + Wire.begin(); +} + +/* disable the i2c pins so they can be used for other functions */ +void disableI2CPins() { + isI2CEnabled = false; + // disable read continuous mode for all devices + queryIndex = -1; + // uncomment the following if or when the end() method is added to Wire library + // Wire.end(); +} + +/*============================================================================== + * SETUP() + *============================================================================*/ + +void systemResetCallback() +{ + // initialize a defalt state + // TODO: option to load config from EEPROM instead of default + if (isI2CEnabled) { + disableI2CPins(); + } + for (byte i = 0; i < TOTAL_PORTS; i++) { + reportPINs[i] = false; // by default, reporting off + portConfigInputs[i] = 0; // until activated + previousPINs[i] = 0; + } + // pins with analog capability default to analog input + // otherwise, pins default to digital output + for (byte i = 0; i < TOTAL_PINS; i++) { + if (IS_PIN_ANALOG(i)) { + // turns off pullup, configures everything + setPinModeCallback(i, ANALOG); + } else { + // sets the output to 0, configures portConfigInputs + setPinModeCallback(i, OUTPUT); + } + } + // by default, do not report any analog inputs + analogInputsToReport = 0; + + /* send digital inputs to set the initial state on the host computer, + * since once in the loop(), this firmware will only send on change */ + /* + TODO: this can never execute, since no pins default to digital input + but it will be needed when/if we support EEPROM stored config + for (byte i=0; i < TOTAL_PORTS; i++) { + outputPort(i, readPort(i, portConfigInputs[i]), true); + } + */ +} + +void setup() +{ + Firmata.setFirmwareVersion(FIRMATA_MAJOR_VERSION, FIRMATA_MINOR_VERSION); + + Firmata.attach(ANALOG_MESSAGE, analogWriteCallback); + Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback); + Firmata.attach(REPORT_ANALOG, reportAnalogCallback); + Firmata.attach(REPORT_DIGITAL, reportDigitalCallback); + Firmata.attach(SET_PIN_MODE, setPinModeCallback); + Firmata.attach(START_SYSEX, sysexCallback); + Firmata.attach(SYSTEM_RESET, systemResetCallback); + + Firmata.begin(57600); + systemResetCallback(); // reset to default config +} + +/*============================================================================== + * LOOP() + *============================================================================*/ +void loop() +{ + byte pin, analogPin; + + /* DIGITALREAD - as fast as possible, check for changes and output them to the + * FTDI buffer using Serial.print() */ + checkDigitalInputs(); + + /* SERIALREAD - processing incoming messagse as soon as possible, while still + * checking digital inputs. */ + while (Firmata.available()) + Firmata.processInput(); + + /* SEND FTDI WRITE BUFFER - make sure that the FTDI buffer doesn't go over + * 60 bytes. use a timer to sending an event character every 4 ms to + * trigger the buffer to dump. */ + + currentMillis = millis(); + if (currentMillis - previousMillis > samplingInterval) { + previousMillis += samplingInterval; + /* ANALOGREAD - do all analogReads() at the configured sampling interval */ + for (pin = 0; pin < TOTAL_PINS; pin++) { + if (IS_PIN_ANALOG(pin) && pinConfig[pin] == ANALOG) { + analogPin = PIN_TO_ANALOG(pin); + if (analogInputsToReport & (1 << analogPin)) { + Firmata.sendAnalog(analogPin, analogRead(analogPin)); + } + } + } + // report i2c data for all device with read continuous mode enabled + if (queryIndex > -1) { + for (byte i = 0; i < queryIndex + 1; i++) { + readAndReportData(query[i].addr, query[i].reg, query[i].bytes); + } + } + } +}