From 8f428f51b4b62d1f07c88cace7bb127e436271a5 Mon Sep 17 00:00:00 2001 From: Alexander Kauerz Date: Thu, 9 Feb 2012 22:57:52 +0100 Subject: cmake hinzu --- arduino-cmake/.gitignore | 1 + arduino-cmake/CMakeLists.txt | 19 + arduino-cmake/README.rst | 772 ++++++++++++++++ .../cmake/modules/ArduinoProcessing.cmake | 103 +++ arduino-cmake/cmake/modules/FindArduino.cmake | 978 +++++++++++++++++++++ arduino-cmake/cmake/modules/Platform/Arduino.cmake | 0 .../cmake/modules/Platform/ArduinoPaths.cmake | 21 + arduino-cmake/cmake/toolchains/Arduino.cmake | 74 ++ arduino-cmake/configure | 249 ++++++ arduino-cmake/configure.bat | 95 ++ arduino-cmake/example/CMakeLists.txt | 24 + arduino-cmake/example/wire_master_reader.cpp | 32 + 12 files changed, 2368 insertions(+) create mode 100644 arduino-cmake/.gitignore create mode 100644 arduino-cmake/CMakeLists.txt create mode 100644 arduino-cmake/README.rst create mode 100644 arduino-cmake/cmake/modules/ArduinoProcessing.cmake create mode 100644 arduino-cmake/cmake/modules/FindArduino.cmake create mode 100644 arduino-cmake/cmake/modules/Platform/Arduino.cmake create mode 100644 arduino-cmake/cmake/modules/Platform/ArduinoPaths.cmake create mode 100644 arduino-cmake/cmake/toolchains/Arduino.cmake create mode 100755 arduino-cmake/configure create mode 100644 arduino-cmake/configure.bat create mode 100644 arduino-cmake/example/CMakeLists.txt create mode 100644 arduino-cmake/example/wire_master_reader.cpp diff --git a/arduino-cmake/.gitignore b/arduino-cmake/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/arduino-cmake/.gitignore @@ -0,0 +1 @@ +build diff --git a/arduino-cmake/CMakeLists.txt b/arduino-cmake/CMakeLists.txt new file mode 100644 index 0000000..ba40b58 --- /dev/null +++ b/arduino-cmake/CMakeLists.txt @@ -0,0 +1,19 @@ +#=============================================================================# +# Author: QueezyTheGreat # +# Date: 26.04.2011 # +# # +# Description: Arduino CMake example # +# # +#=============================================================================# +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) # CMake module search path +set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/toolchains/Arduino.cmake) # Arduino Toolchain + + +cmake_minimum_required(VERSION 2.8) +#====================================================================# +# Setup Project # +#====================================================================# +project(ArduinoExample C CXX) +find_package(Arduino 1.0 REQUIRED) + +add_subdirectory(example) # Add example directory to build diff --git a/arduino-cmake/README.rst b/arduino-cmake/README.rst new file mode 100644 index 0000000..163106e --- /dev/null +++ b/arduino-cmake/README.rst @@ -0,0 +1,772 @@ +============= +Arduino CMake +============= + +Arduino is a great development platform, which is easy to use. It has everything a beginner should need. The *Arduino IDE* simplifies a lot of things for the standard user, but if you are a professional programmer the IDE can feel simplistic and restrictive. + +One major drawback of the *Arduino IDE* is that you cannot do anything without it, which for me is a **complete buzz kill**. Thats why I created an alternative build system for the Arduino using CMake. + +CMake is great corss-platform build system that works on practically any operating system. With it you are not constrained to a single build system. CMake lets you generated the build system that fits your needs, using the tools you like. It can generate any type of build system, from simple Makefiles, to complete projects for Eclipse, Visual Studio, XCode, etc. + +The **Arduino CMake** build system integrates tightly with the *Arduino SDK*. Version **1.0** of the *Arduino SDK* is required. + +So if you like to do things from the command line (using make), or to build you're firmware where you're in control, or if you would like to use an IDE such as Eclipse, KDevelop, XCode, CodeBlocks or something similar, then **Arduino CMake** is the system for you. + +Features +-------- + +* Integrates with *Arduino SDK* +* Supports all Arduino boards. +* Supports Arduino type libraries +* Automatic detection of Arduino libraries. +* Generates firmware images. +* Generates libraries. +* Upload support. +* Programmer support (with bootloader upload). +* Supports multiple build system types (Makefiles, Eclipse, KDevelop, CodeBlocks, XCode, etc). +* Cross-platform: Windows, Linux, Mac +* Extensible build system, thanks to CMake + + +Feedback +-------- + +**Arduino CMake** is hosted on GitHUB and is available at: + +https://github.com/queezythegreat/arduino-cmake + +Did you find a bug or would like a specific feature, please report it at: + +https://github.com/queezythegreat/arduino-cmake/issues + +If you would like to hack on this project, don't hesitate to fork it on GitHub. +I will be glad to integrate you'r changes if you send me a ``Pull Request``. + + +Requirements +------------ + +* Base requirements: + + - ``CMake`` - http://www.cmake.org/cmake/resources/software.html + - ``Arduino SDK`` - http://www.arduino.cc/en/Main/Software + +* Linux requirements: + + - ``gcc-avr`` - AVR GNU GCC compiler + - ``binutils-avr`` - AVR binary tools + - ``avr-libc`` - AVR C library + - ``avrdude`` - Firmware uploader + + +Contributors +------------ + +I would like to thank the following people for contributing to **Arduino CMake**: + +* Marc Plano-Lesay (`Kernald`_) +* James Goppert (`jgoppert`_) +* Matt Tyler (`matt-tyler`_) + +.. _Kernald: https://github.com/Kernald +.. _jgoppert: https://github.com/jgoppert +.. _matt-tyler: https://github.com/matt-tyler + + +TODO +---- + +* Sketch conversion (PDE files) +* Test more complex configurations and error handling + +Contents +-------- + +1. `Getting Started`_ +2. `Using Arduino CMake`_ + + 1. `Creating firmware images`_ + 2. `Creating libraries`_ + 3. `Arduino Libraries`_ + 4. `Compiler and Linker Flags`_ + 5. `Programmers`_ + +3. `Linux Environment Setup`_ + + 1. `Serial Namming`_ + 2. `Serial Terminal`_ + +4. `Mac OS X Environment Setup`_ + + 1. `Serial Namming`_ + 2. `Serial Terminal`_ + +5. `Windows Environment Setup`_ + + 1. `CMake Generators`_ + 2. `Serial Namming`_ + 3. `Serial Terminal`_ + +6. `Eclipse Environment`_ +7. `Troubleshooting`_ + + 1. `undefined reference to `__cxa_pure_virtual'`_ + 2. `Arduino Mega 2560 image does not work`_ + 3. `Library not detected automatically`_ + +8. `Resources`_ + + + + + + +Getting Started +--------------- + + +The following instructions are for **\*nix** type systems, specifically this is a Linux example. + +In short you can get up and running using the following commands:: + + mkdir build + cd build + cmake .. + make + make upload # to upload all firmware images [optional] + make wire_reader-serial # to get a serial terminal to wire_serial [optional] + +For a more detailed explanation, please read on... + +1. Toolchain file + + In order to build firmware for the Arduino you have to specify a toolchain file to enable cross-compilation. There are two ways of specifying the file, either at the command line or from within the *CMakeLists.txt* configuration files. The bundled example uses the second approach like so:: + + set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/toolchains/Arduino.cmake) + + Please note that this must be before the ``project(...)`` command. + + If you would like to specify it from the command line, heres how:: + + cmake -DCMAKE_TOOLCHAIN_FILE=../path/to/toolchain/file.cmake PATH_TO_SOURCE_DIR + +2. Creating a build directory + + The second order of business is creating a build directory. CMake has a great feature called out-of-source builds, what this means is the building is done in a completely separate directory, than where the sources are. The benefits of this is you don't have any clutter in you source directory and you won't accidentally commit something in, that is auto-generated. + + So lets create that build directory:: + + mkdir build + cd build + +3. Creating the build system + + Now lets create the build system that will create our firmware:: + + cmake .. + + To specify the build system type, use the ``-G`` option, for example:: + + cmake -G"Eclipse CDT4 - Unix Makefiles" .. + + If you rather use a GUI, use:: + + cmake-gui .. + +4. Building + + Next we will build everything:: + + make + +5. Uploading + + Once everything built correctly we can upload. Depending on your Arduino you will have to update the serial port used for uploading the firmware. To change the port please edit the following variable in *CMakeLists.txt*:: + + set(${FIRMWARE_NAME}_PORT /path/to/device) + + Ok lets do a upload of all firmware images:: + + make upload + +6. Serial output + + If you have some serial output, you can launch a serial terminal from the build system. The command used for executing the serial terminal is user configurable by the following setting:: + + set(${FIRMWARE_NAME}_SERIAL serial command goes here) + + In order to get access to the serial port use the following in your command:: + + @INPUT_PORT@ + + That constant will get replaced with the actual serial port used (see uploading). In the case of our example configuration we can get the serial terminal by executing the following:: + + make wire_reader-serial + + + + + + + + + + +Using Arduino CMake +------------------- + +The first step in generating Arduino firmware is including the **Arduino CMake** module package. This easily done with:: + + find_package(Arduino) + +To have a specific minimal version of the *Arduino SDK*, you can specify the version like so:: + + find_package(Arduino 1.0) + +That will require an *Arduino SDK* version **1.0** or newer. To ensure that the SDK is detected you can add the **REQUIRED** keyword:: + + + find_package(Arduino 1.0 REQUIRED) + + +Creating firmware images +~~~~~~~~~~~~~~~~~~~~~~~~ + +Once you have the **Arduino CMake** package loaded you can start defining firmware images. + +To create Arduino firmware in CMake you use the ``generate_arduino_firmware`` command. This function only accepts a single argument, the target name. To configure the target you need to specify a list of variables of the following format before the command:: + + ${TARGET_NAME}${OPTION_SUFFIX} + +Where ``${TARGET_NAME}`` is the name of you target and ``${OPTIONS_SUFFIX}`` is one of the following option suffixes:: + + _SRCS # Target source files + _HDRS # Target Headers files (for project based build systems) + _SKETCHES # Target sketch files + _LIBS # Libraries to linked against target (sets up dependency tracking) + _BOARD # Board name (such as uno, mega2560, ...) + _PORT # Serial port, for upload and serial targets [OPTIONAL] + _SERIAL # Serial command for serial target [OPTIONAL] + _NO_AUTOLIBS # Disables Arduino library detection (default On) + _AFLAGS # Overide global avrdude flags for target + _PROGRAMMER # Programmer name, enables programmer burning (including bootloader). + + +So to create a target (firmware image) called ``blink``, composed of ``blink.h`` and ``blink.cpp`` source files for the *Arduino Uno*, you write the following:: + + set(blink_SRCS blink.cpp) + set(blink_HDRS blink.h) + set(blink_BOARD uno) + + generate_arduino_firmware(blink) + +Upload Firmware +_______________ + +To enable firmware upload functionality, you need to add the ``_PORT`` settings:: + + set(blink_PORT /dev/ttyUSB0) + +Once defined there will be two targets available for uploading, ``${TARGET_NAME}-upload`` and a global ``upload`` target (which will depend on all other upload targets defined in the build): + +* ``blink-upload`` - will upload just the ``blink`` firmware +* ``upload`` - upload all firmware images registered for uploading + +Serial Terminal +_______________ +To enable serial terminal, add the ``_SERIAL`` setting (``@INPUT_PORT@`` will be replaced with the ``blink_PORT`` setting):: + + set(blink_PORT picocom @INPUT_PORT@ -b 9600 -l) + +This will create a target named ``${TARGET_NAME}-serial`` (in this example: blink-serial). + + + + +Creating libraries +~~~~~~~~~~~~~~~~~~ + +Creating libraries is very similar to defining a firmware image, except we use the ``generate_arduino_library`` command. The syntax of the settings is the same except we have a different list of settings:: + + _SRCS # Library Sources + _HDRS # Library Headers + _LIBS # Libraries to linked in (sets up dependency tracking) + _BOARD # Board name (such as uno, mega2560, ...) + _NO_AUTOLIBS # Disables Arduino library detection + +Lets define a simple library called ``blink_lib``, with two sources files for the *Arduino Uno*:: + + + set(blink_lib_SRCS blink_lib.cpp) + set(blink_lib_HDRS blink_lib.h) + set(blink_lib_BOARD uno) + + generate_arduino_firmware(blink_lib) + +Once that library is defined we can use it in our other firmware images... Lets add ``blink_lib`` to the ``blink`` firmware:: + + set(blink_SRCS blink.cpp) + set(blink_HDRS blink.h) + set(blink_LIBS blink_lib) + set(blink_BOARD uno) + + generate_arduino_firmware(blink) + +CMake has automatic dependency tracking, so when you build the ``blink`` target, ``blink_lib`` will automatically get built, in the right order. + + + + + +Arduino Libraries +~~~~~~~~~~~~~~~~~ + +Libraries are one of the more powerful features which the Arduino offers to users. Instead of rewriting code, people bundle their code in libraries and share them with others. +The structure of these libraries is very simple, which makes them easy to create. + +An Arduino library is **any directory which contains a header named after the directory**, simple. +Any source files contained within that directory is part of the library. Here is a example of library a called ExampleLib:: + + ExampleLib/ + |-- ExampleLib.h + |-- ExampleLib.cpp + `-- OtherLibSource.cpp + +Now because the power of Arduino lies within those user created libraries, support for them is built right into **Arduino CMake**. The **Arduino SDK** comes with a large number of default libraries, adding new libraries is simple. + +To incorporate a library into your firmware, you can do one of three things: + +1. Place the library next to the default Arduino libraries (located at **${ARDUINO_SDK}/libraries**) +2. Place the library next to the firmware configuration file (same directory as the **CMakeLists.txt**) +3. Place the library in a separate folder and tell **Arduino CMake** the path to that directory. + + To tell CMake where to search for libraries use the `link_directories` command. The command has to be used before defining any firmware or libraries requiring those libraries. + + For example:: + + link_directories(${CMAKE_CURRENT_SOURCE_DIR}/libraries) + link_directories(/home/username/arduino_libraries) + + +If a library contains nested sources, a special option must be defined to enable recursion. For example to enable recursion for the Arduino Wire library use:: + + set(Wire_RECURSE True) + +The option name should be **${LIBRARY_NAME}_RECURSE**, where in this case **LIBRARY_NAME** is equal to *Wire*. + + + +Compiler and Linker Flags +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default compiler and linker flags should be fine for most projects. If you required specific compiler/linker flags, use the following options to change them: + +* **ARDUINO_C_FLAGS** - C compiler flags +* **ARDUINO_CXX_FLAGS** - C++ compiler flags +* **ARDUINO_LINKER_FLAGS** - Linker flags + + +Set these option either before the `project()` like so:: + + set(ARDUINO_C_FLAGS "-ffunction-sections -fdata-sections") + set(ARDUINO_CXX_FLAGS "${ARDUINO_C_FLAGS} -fno-exceptions") + set(ARDUINO_LINKER_FLAGS "-Wl,--gc-sections") + project(ArduinoExample C CXX) + +or when configuring the project:: + + cmake -D"ARDUINO_C_FLAGS=-ffunction-sections -fdata-sections" ../path/to/sources/ + + +Programmers +~~~~~~~~~~~ + +**Arduino CMake** fully supports programmers, for burning firmware and bootloader images directly onto the Arduino. +If you have a programmer that is supported by the *Arduino SDK*, everything should work out of the box. +As of version 1.0 of the *Arduino SDK*, the following programmers are supported: + +* **avrisp** - AVR ISP +* **avrispmkii** - AVRISP mkII +* **usbtinyisp** - USBtinyISP +* **parallel** - Parallel Programmer +* **arduinoisp** - Arduino as ISP + +The programmers.txt file located in `${ARDUINO_SDK}/hardware/arduino/` lists all supported programmers by the *Arduino SDK*. + +In order to enable programmer support, you have to define the following setting:: + + set(${TARGET_NAME}_PROGRAMMER programmer_id) + +where `programmer_id` is the name of the programmer supported by the *Arduino SDK*. + +Once you have enabled programmer support, two new targets are available in the build system: + +* **${TARGET_NAME}-burn** - burns the firmware image via the programmer +* **${TARGET_NAME}-burn-bootloader** - burns the original **Arduino bootloader** image via the programmer + +If you need to restore the original **Arduino bootloader** onto your Arduino, so that you can use the traditional way of uploading firmware images via the bootloader, use **${TARGET_NAME}-burn-bootloader** to restore it. + + + +Linux Environment Setup +----------------------- + +Running the *Arduino SDK* on Linux is a little bit more involved, because not everything is bundled with the SDK. The AVR GCC toolchain is not distributed alongside the Arduino SDK, so it has to be installed seperately. + +To get **Arduino CMake** up and running follow these steps: + +1. Install the following packages using your package manager: + + * ``gcc-avr`` - AVR GNU GCC compiler + * ``binutils-avr`` - AVR binary tools + * ``avr-libc`` - AVR C library + * ``avrdude`` - Firmware uploader + +2. Install the *Arduino SDK*. + + Depending on your distribution, the *Arduino SDK* may or may not be available. + + If it is available please install it using your packages manager otherwise do: + + 1. Download the `Arduino SDK`_ + 2. Extract it into ``/usr/share`` + + NOTE: Arduino version **1.0** or newer is required! + +3. Install CMake: + + * Using the package manager or + * Using the `CMake installer`_ + + NOTE: CMake version 2.8 or newer is required! + + + +Serial Naming +~~~~~~~~~~~~~ + +On Linux the Arduino serial device is named as follows (where **X** is the device number):: + + /dev/ttyUSBX + /dev/ttyACMX + +Where ``/dev/ttyACMX`` is for the new **Uno** and **Mega** Arduino's, while ``/dev/ttyUSBX`` is for the old ones. + +CMake configuration example:: + + set(${FIRMWARE_NAME}_PORT /dev/ttyUSB0) + + +Serial Terminal +~~~~~~~~~~~~~~~ + +On Linux a wide range on serial terminal are availabe. Here is a list of a couple: + +* ``minicom`` +* ``picocom`` +* ``gtkterm`` +* ``screen`` + + + + + + + + + + + +Mac OS X Environment Setup +------------------------- + +The *Arduino SDK*, as on Windows, is self contained and has everything needed for building. To get started do the following: + +1. Install the *Arduino SDK* + + 1. Download `Arduino SDK`_ + 2. Copy ``Arduino`` into ``Applications`` + 3. Install ``FTDIUSBSerialDrviver*`` (for FTDI USB Serial) + +2. Install CMake + + 1. Download `CMake`_ + 2. Install ``cmake-*.pkg`` + + NOTE: Make sure to click on **`Install Command Line Links`** + +Serial Naming +~~~~~~~~~~~~~ + +When specifying the serial port name on Mac OS X, use the following names (where XXX is a unique ID):: + + /dev/tty.usbmodemXXX + /dev/tty.usbserialXXX + +Where ``tty.usbmodemXXX`` is for new **Uno** and **Mega** Arduino's, while ``tty.usbserialXXX`` are the older ones. + +CMake configuration example:: + + set(${FIRMWARE_NAME}_PORT /dev/tty.usbmodem1d11) + +Serial Terminal +~~~~~~~~~~~~~~~ + +On Mac the easiest way to get a Serial Terminal is to use the ``screen`` terminal emulator. To start a ``screen`` serial session:: + + screen /dev/tty.usbmodemXXX + +Where ``/dev/tty.usbmodemXXX`` is the terminal device. To exit press ``C-a C-\``. + +CMake configuration example:: + + set(${FIRMWARE_NAME}_SERIAL screen @INPUT_PORT@) + + + + + + + + + + + +Windows Environment Setup +------------------------- + +On Windows the *Arduino SDK* is self contained and has everything needed for building. To setup the environment do the following: + +1. Place the `Arduino SDK`_ either + + * into **Program Files**, or + * onto the **System Path** + + NOTE: Don't change the default *Arduino SDK* directory name, otherwise auto detection will no work properly! + +2. Add to the **System Path**: ``${ARDUINO_SDK_PATH}/hardware/tools/avr/utils/bin`` +3. Install `CMake 2.8`_ + + NOTE: Make sure you check the option to add CMake to the **System Path**. + + +CMake Generators +~~~~~~~~~~~~~~~~ + +Once installed, you can start using CMake the usual way, just make sure to chose either a **MSYS Makefiles** or **Unix Makefiles** type generator:: + + MSYS Makefiles = Generates MSYS makefiles. + Unix Makefiles = Generates standard UNIX makefiles. + CodeBlocks - Unix Makefiles = Generates CodeBlocks project files. + Eclipse CDT4 - Unix Makefiles + = Generates Eclipse CDT 4.0 project files. + +If you want to use a **MinGW Makefiles** type generator, you must generate the build system the following way: + +1. Remove ``${ARDUINO_SDK_PATH}/hardware/tools/avr/utils/bin`` from the **System Path** +2. Generate the build system using CMake with the following option set (either through the GUI or from the command line):: + + CMAKE_MAKE_PROGRAM=${ARDIUNO_SDK_PATH}/hardware/tools/avr/utils/bin/make.exe + +3. Then build the normal way + +The reason for doing this is the MinGW generator cannot have the ``sh.exe`` binary on the **System Path** during generation, otherwise you get an error. + +Serial Naming +~~~~~~~~~~~~~ + +When specifying the serial port name on Windows, use the following names:: + + com1 com2 ... comN + +CMake configuration example:: + + set(${FIRMWARE_NAME}_PORT com3) + +Serial Terminal +~~~~~~~~~~~~~~~ + +Putty is a great multi-protocol terminal, which supports SSH, Telnet, Serial, and many more... The latest development snapshot supports command line options for launching a serial terminal, for example:: + + putty -serial COM3 -sercfg 9600,8,n,1,X + +CMake configuration example (assuming putty is on the **System Path**):: + + set(${FIRMWARE_NAME}_SERIAL putty -serial @INPUT_PORT@) + +Putty - http://tartarus.org/~simon/putty-snapshots/x86/putty-installer.exe + + + + + + + + + + +Eclipse Environment +------------------- + +Eclipse is a great IDE which has a lot of functionality and is much more powerful than the *Arduino IDE*. In order to use Eclipse you will need the following: + +1. Eclipse +2. Eclipse CDT extension (for C/C++ development) + +On most Linux distribution you can install Eclipse + CDT using your package manager, otherwise you can download the `Eclipse IDE for C/C++ Developers`_ bundle. + +Once you have Eclipse, here is how to generate a project using CMake: + +1. Create a build directory that is next to your source directory, like this:: + + build_directory/ + source_directory/ + +2. Run CMake with the `Eclipse CDT4 - Unix Makefiles` generator, inside the build directory:: + + cd build_directory/ + cmake -G"Eclipse CDT4 - Unix Makefiles" ../source_directory + +3. Open Eclipse and import the project from the build directory. + + 1. **File > Import** + 2. Select `Existing Project into Workspace`, and click **Next** + 3. Select *Browse*, and select the build directoy. + 4. Select the project in the **Projects:** list + 5. Click **Finish** + + + +.. _Eclipse IDE for C/C++ Developers: http://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/heliossr2 + + + + + + + + + + + +Troubleshooting +--------------- + +The following section will outline some solutions to common problems that you may encounter. + +undefined reference to `__cxa_pure_virtual' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When linking you'r firmware image you may encounter this error on some systems. An easy fix is to add the following to your firmware source code:: + + extern "C" void __cxa_pure_virtual(void); + void __cxa_pure_virtual(void) { while(1); } + + +The contents of the ``__cxa_pure_virtual`` function can be any error handling code; this function will be called whenever a pure virtual function is called. + +* `What is the purpose of `cxa_pure_virtual``_ + +.. _What is the purpose of `cxa_pure_virtual`: http://stackoverflow.com/questions/920500/what-is-the-purpose-of-cxa-pure-virtual + +Arduino Mega 2560 image does not work +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are working on Linux, and have ``avr-gcc`` >= 4.5 you might have a unpatched version gcc which has the C++ constructor bug. This bug affects the **Atmega2560** when using classes which causes the Arduino firmware to crash. + +If you encounter this problem either downgrade ``avr-gcc`` to **4.3** or rebuild gcc with the following patch:: + + --- gcc-4.5.1.orig/gcc/config/avr/libgcc.S 2009-05-23 17:16:07 +1000 + +++ gcc-4.5.1/gcc/config/avr/libgcc.S 2010-08-12 09:38:05 +1000 + @@ -802,7 +802,9 @@ + mov_h r31, r29 + mov_l r30, r28 + out __RAMPZ__, r20 + + push r20 + XCALL __tablejump_elpm__ + + pop r20 + .L__do_global_ctors_start: + cpi r28, lo8(__ctors_start) + cpc r29, r17 + @@ -843,7 +845,9 @@ + mov_h r31, r29 + mov_l r30, r28 + out __RAMPZ__, r20 + + push r20 + XCALL __tablejump_elpm__ + + pop r20 + .L__do_global_dtors_start: + cpi r28, lo8(__dtors_end) + cpc r29, r17 + +* `AVR GCC Bug 45263 Report`_ +* `The global constructor bug in avr-gcc`_ + +.. _AVR GCC Bug 45263 Report: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45263 +.. _The global constructor bug in avr-gcc: http://andybrown.me.uk/ws/2010/10/24/the-major-global-constructor-bug-in-avr-gcc/ + + + +Library not detected automatically +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a Arduino library does not get detected automatically, it usually means CMake cannot find it (obvious). + +One common reason why the library is not detected, is because the directory name of the library does not match the header. +If I'm including a library header like so:: + + #include "my_library.h" + +Based on this include, **Arduino CMake** is expecting to find a library that has a directory name **my_libray**. +If the directory name does not match the header, it won't be consider a Arduino Library (see `Arduino Libraries`_). + + +When a library being used is located in a non-standard location (not in the **Arduino SDK** or next to the firmware), then that directory must be registered. +To register a non-standard directory containing Arduino libraries, use the following:: + + link_directories(path_to_directory_containing_libraries) + +Remember to **use this command before defining any firmware**, depending on libraries located in that directory. + + + + +Resources +--------- + +Here are some resources you might find useful in getting started. + +1. CMake: + + * `Offical CMake Tutorial`_ + * `CMake Tutorial`_ + * `CMake Reference`_ + +.. _Offical CMake Tutorial: http://www.cmake.org/cmake/help/cmake_tutorial.html +.. _CMake Tutorial: http://mathnathan.com/2010/07/11/getting-started-with-cmake/ +.. _CMake Reference: http://www.cmake.org/cmake/help/cmake-2-8-docs.html + +2. Arduino: + + * `Getting Started`_ - Introduction to Arduino + * `Playground`_ - User contributed documentation and help + * `Arduino Forums`_ - Official forums + * `Arduino Reference`_ - Official reference manual + +.. _Getting Started: http://www.arduino.cc/en/Guide/HomePage +.. _Playground: http://www.arduino.cc/playground/ +.. _Arduino Reference: http://www.arduino.cc/en/Reference/HomePage +.. _Arduino Forums: http://www.arduino.cc/forum/ + + + + + + + + +.. _CMake 2.8: http://www.cmake.org/cmake/resources/software.html +.. _CMake: http://www.cmake.org/cmake/resources/software.html +.. _CMake Installer: http://www.cmake.org/cmake/resources/software.html +.. _Arduino SDK: http://www.arduino.cc/en/Main/Software + diff --git a/arduino-cmake/cmake/modules/ArduinoProcessing.cmake b/arduino-cmake/cmake/modules/ArduinoProcessing.cmake new file mode 100644 index 0000000..c7a2407 --- /dev/null +++ b/arduino-cmake/cmake/modules/ArduinoProcessing.cmake @@ -0,0 +1,103 @@ +# 1. Concatenate all PDE files +# 2. Write #include "WProgram.h" +# 3. Write prototypes +# 4. Write original sources +# +# +# Prefix Writer +# 1. Scrub comments +# 2. Optionally subsitute Unicode +# 3. Find imports +# 4. Find prototypes +# +# Find prototypes +# 1. Strip comments, quotes, preprocessor directives +# 2. Collapse braches +# 3. Regex + + +set(SINGLE_QUOTES_REGEX "('.')") +set(DOUBLE_QUOTES_REGEX "(\"([^\"\\\\]|\\\\.)*\")") +set(SINGLE_COMMENT_REGEX "([ ]*//[^\n]*)") +set(MULTI_COMMENT_REGEX "(/[*][^/]*[*]/)") +set(PREPROC_REGEX "([ ]*#(\\\\[\n]|[^\n])*)") + +#"[\w\[\]\*]+\s+[&\[\]\*\w\s]+\([&,\[\]\*\w\s]*\)(?=\s*\{)" +set(PROTOTPYE_REGEX "([a-zA-Z0-9]+[ ]*)*[a-zA-Z0-9]+[ ]*\([^{]*\)[ ]*{") + +function(READ_SKETCHES VAR_NAME ) + set(SKETCH_SOURCE) + foreach(SKETCH ${ARGN}) + if(EXISTS ${SKETCH}) + message(STATUS "${SKETCH}") + file(READ ${SKETCH} SKETCH_CONTENTS) + set(SKETCH_SOURCE "${SKETCH_SOURCE}\n${SKETCH_CONTENTS}") + else() + message(FATAL_ERROR "Sketch file does not exist: ${SKETCH}") + endif() + endforeach() + set(${VAR_NAME} "${SKETCH_SOURCE}" PARENT_SCOPE) +endfunction() + +function(STRIP_SOURCES VAR_NAME SOURCES) + string(REGEX REPLACE "${SINGLE_QUOTES_REGEX}|${DOUBLE_QUOTES_REGEX}|${SINGLE_COMMENT_REGEX}|${MULTI_COMMENT_REGEX}|${PREPROC_REGEX}" + "" + SOURCES + "${SOURCES}") + set(${VAR_NAME} "${SOURCES}" PARENT_SCOPE) +endfunction() + +function(COLLAPSE_BRACES VAR_NAME SOURCES) + set(PARSED_SOURCES) + string(LENGTH "${SOURCES}" SOURCES_LENGTH) + math(EXPR SOURCES_LENGTH "${SOURCES_LENGTH}-1") + + set(NESTING 0) + set(START 0) + foreach(INDEX RANGE ${SOURCES_LENGTH}) + string(SUBSTRING "${SOURCES}" ${INDEX} 1 CURRENT_CHAR) + #message("${CURRENT_CHAR}") + if(CURRENT_CHAR STREQUAL "{") + if(NESTING EQUAL 0) + math(EXPR SUBLENGTH "${INDEX}-${START} +1") + string(SUBSTRING "${SOURCES}" ${START} ${SUBLENGTH} CURRENT_CHUNK) + set(PARSED_SOURCES "${PARSED_SOURCES}${CURRENT_CHUNK}") + #message("INDEX: ${INDEX} START: ${START} LENGTH: ${SUBLENGTH}") + endif() + math(EXPR NESTING "${NESTING}+1") + elseif(CURRENT_CHAR STREQUAL "}") + math(EXPR NESTING "${NESTING}-1") + if(NESTING EQUAL 0) + set(START ${INDEX}) + endif() + endif() + endforeach() + + math(EXPR SUBLENGTH "${SOURCES_LENGTH}-${START} +1") + string(SUBSTRING "${SOURCES}" ${START} ${SUBLENGTH} CURRENT_CHUNK) + set(PARSED_SOURCES "${PARSED_SOURCES}${CURRENT_CHUNK}") + + set(${VAR_NAME} "${PARSED_SOURCES}" PARENT_SCOPE) +endfunction() + +function(extract_prototypes VAR_NAME SOURCES) + string(REGEX MATCHALL "${PROTOTPYE_REGEX}" + SOURCES + "${SOURCES}") + set(${VAR_NAME} "${SOURCES}" PARENT_SCOPE) +endfunction() + +read_sketches(SKETCH_SOURCE ${FILES}) +strip_sources(SKETCH_SOURCE "${SKETCH_SOURCE}") +collapse_braces(SKETCH_SOURCE "${SKETCH_SOURCE}") +extract_prototypes(SKETCH_SOURCE "${SKETCH_SOURCE}") + + + + +message("===============") +foreach(ENTRY ${SKETCH_SOURCE}) + message("START]]]${ENTRY}[[[END") +endforeach() +message("===============") +#message("${SKETCH_SOURCE}") diff --git a/arduino-cmake/cmake/modules/FindArduino.cmake b/arduino-cmake/cmake/modules/FindArduino.cmake new file mode 100644 index 0000000..5873735 --- /dev/null +++ b/arduino-cmake/cmake/modules/FindArduino.cmake @@ -0,0 +1,978 @@ +# - Generate firmware and libraries for Arduino Devices +# generate_arduino_firmware(TARGET_NAME) +# TARGET_NAME - Name of target +# Creates a Arduino firmware target. +# +# The target options can be configured by setting options of +# the following format: +# ${TARGET_NAME}${SUFFIX} +# The following suffixes are availabe: +# _SRCS # Sources +# _HDRS # Headers +# _SKETCHES # Arduino sketch files +# _LIBS # Libraries to linked in +# _BOARD # Board name (such as uno, mega2560, ...) +# _PORT # Serial port, for upload and serial targets [OPTIONAL] +# _AFLAGS # Override global Avrdude flags for target +# _SERIAL # Serial command for serial target [OPTIONAL] +# _NO_AUTOLIBS # Disables Arduino library detection +# Here is a short example for a target named test: +# set(test_SRCS test.cpp) +# set(test_HDRS test.h) +# set(test_BOARD uno) +# +# generate_arduino_firmware(test) +# +# +# generate_arduino_library(TARGET_NAME) +# TARGET_NAME - Name of target +# Creates a Arduino firmware target. +# +# The target options can be configured by setting options of +# the following format: +# ${TARGET_NAME}${SUFFIX} +# The following suffixes are availabe: +# +# _SRCS # Sources +# _HDRS # Headers +# _LIBS # Libraries to linked in +# _BOARD # Board name (such as uno, mega2560, ...) +# _NO_AUTOLIBS # Disables Arduino library detection +# +# Here is a short example for a target named test: +# set(test_SRCS test.cpp) +# set(test_HDRS test.h) +# set(test_BOARD uno) +# +# generate_arduino_library(test) + +file(GLOB SDK_PATHS /usr/share/arduino*) + +find_path(ARDUINO_SDK_PATH + NAMES lib/version.txt hardware libraries + PATH_SUFFIXES share/arduino + HINTS ${SDK_PATHS} + DOC "Arduino Development Kit path.") + +# load_board_settings() +# +# Load the Arduino SDK board settings from the boards.txt file. +# +function(LOAD_BOARD_SETTINGS) + load_arduino_style_settings(ARDUINO_BOARDS "${ARDUINO_BOARDS_PATH}") +endfunction() + +function(LOAD_PROGRAMMERS_SETTINGS) + load_arduino_style_settings(ARDUINO_PROGRAMMERS "${ARDUINO_PROGRAMMERS_PATH}") +endfunction() + +# print_board_list() +# +# Print list of detected Arduino Boards. +function(PRINT_BOARD_LIST) + message(STATUS "Supported Arduino Boards:") + print_list(ARDUINO_BOARDS) + message(STATUS "") +endfunction() + +# print_programmer_list() +# +# Print list of detected Programmers. +function(PRINT_PROGRAMMER_LIST) + message(STATUS "Supported Programmers:") + print_list(ARDUINO_PROGRAMMERS) + message(STATUS "") +endfunction() + +# print_programmer_settings(PROGRAMMER) +# +# PROGRAMMER - programmer id +# +# Print the detected Programmer settings. +# +function(PRINT_PROGRAMMER_SETTINGS PROGRAMMER) + if(${PROGRAMMER}.SETTINGS) + message(STATUS "Programmer ${PROGRAMMER} Settings:") + print_settings(${PROGRAMMER}) + endif() +endfunction() + +# print_board_settings(ARDUINO_BOARD) +# +# ARDUINO_BOARD - Board id +# +# Print the detected Arduino board settings. +# +function(PRINT_BOARD_SETTINGS ARDUINO_BOARD) + if(${ARDUINO_BOARD}.SETTINGS) + message(STATUS "Arduino ${ARDUINO_BOARD} Board:") + print_settings(${ARDUINO_BOARD}) + endif() +endfunction() + + + +# generate_arduino_library(TARGET_NAME) +# +# see documentation at top +function(GENERATE_ARDUINO_LIBRARY TARGET_NAME) + load_generator_settings(${TARGET_NAME} INPUT _SRCS # Sources + _HDRS # Headers + _LIBS # Libraries to linked in + _BOARD) # Board name (such as uno, mega2560, ...) + set(INPUT_AUTOLIBS True) + if(DEFINED ${TARGET_NAME}_NO_AUTOLIBS AND ${TARGET_NAME}_NO_AUTOLIBS) + set(INPUT_AUTOLIBS False) + endif() + + message(STATUS "Generating ${TARGET_NAME}") + + set(ALL_LIBS) + set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) + + setup_arduino_compiler(${INPUT_BOARD}) + setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + if(INPUT_AUTOLIBS) + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}") + endif() + + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + + add_library(${TARGET_NAME} ${ALL_SRCS}) + target_link_libraries(${TARGET_NAME} ${ALL_LIBS}) +endfunction() + +# generate_arduino_firmware(TARGET_NAME) +# +# see documentation at top +function(GENERATE_ARDUINO_FIRMWARE TARGET_NAME) + load_generator_settings(${TARGET_NAME} INPUT _SRCS # Sources + _HDRS # Headers + _LIBS # Libraries to linked in + _BOARD # Board name (such as uno, mega2560, ...) + _PORT # Serial port, for upload and serial targets + _AFLAGS # Override global Avrdude flags for target + _SKETCHES # Arduino sketch files + _SERIAL) # Serial command for serial target + + set(INPUT_AUTOLIBS True) + if(DEFINED ${TARGET_NAME}_NO_AUTOLIBS AND ${TARGET_NAME}_NO_AUTOLIBS) + set(INPUT_AUTOLIBS False) + endif() + + message(STATUS "Generating ${TARGET_NAME}") + + set(ALL_LIBS) + set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) + + setup_arduino_compiler(${INPUT_BOARD}) + setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + #setup_arduino_sketch(SKETCH_SRCS ${INPUT_SKETCHES}) + + if(INPUT_AUTOLIBS) + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}") + endif() + + + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + + setup_arduino_target(${TARGET_NAME} "${ALL_SRCS}" "${ALL_LIBS}") + + if(INPUT_PORT) + setup_arduino_upload(${INPUT_BOARD} ${TARGET_NAME} ${INPUT_PORT}) + endif() + + if(INPUT_SERIAL) + setup_serial_target(${TARGET_NAME} "${INPUT_SERIAL}") + endif() +endfunction() + + +# load_generator_settings(TARGET_NAME PREFIX [SUFFIX_1 SUFFIX_2 .. SUFFIX_N]) +# +# TARGET_NAME - The base name of the user settings +# PREFIX - The prefix name used for generator settings +# SUFFIX_XX - List of suffixes to load +# +# Loads a list of user settings into the generators scope. User settings have +# the following syntax: +# +# ${BASE_NAME}${SUFFIX} +# +# The BASE_NAME is the target name and the suffix is a specific generator settings. +# +# For every user setting found a generator setting is created of the follwoing fromat: +# +# ${PREFIX}${SUFFIX} +# +# The purpose of loading the settings into the generator is to not modify user settings +# and to have a generic naming of the settings within the generator. +# +function(LOAD_GENERATOR_SETTINGS TARGET_NAME PREFIX) + foreach(GEN_SUFFIX ${ARGN}) + if(${TARGET_NAME}${GEN_SUFFIX}) + set(${PREFIX}${GEN_SUFFIX} ${${TARGET_NAME}${GEN_SUFFIX}} PARENT_SCOPE) + endif() + endforeach() +endfunction() + +# setup_arduino_compiler(BOARD_ID) +# +# BOARD_ID - The board id name +# +# Configures the the build settings for the specified Arduino Board. +# +macro(setup_arduino_compiler BOARD_ID) + set(BOARD_CORE ${${BOARD_ID}.build.core}) + set(PIN_HEADER ${${BOARD_ID}.build.variant}) + if(BOARD_CORE) + if(ARDUINO_SDK_VERSION MATCHES "([0-9]+)[.]([0-9]+)") + string(REPLACE "." "" ARDUINO_VERSION_DEFINE "${ARDUINO_SDK_VERSION}") # Normalize version (remove all periods) + set(ARDUINO_VERSION_DEFINE "${CMAKE_MATCH_1}") + if(CMAKE_MATCH_2 GREATER 10) + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}${CMAKE_MATCH_2}") + else() + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}0${CMAKE_MATCH_2}") + endif() + else() + set(ARDUINO_VERSION_DEFINE "00${ARDUINO_SDK_VERSION}") + endif() + set(BOARD_CORE_PATH ${ARDUINO_CORES_PATH}/${BOARD_CORE}) + include_directories(${ARDUINO_VARIANTS_PATH}/${PIN_HEADER}) + include_directories(${BOARD_CORE_PATH}) + include_directories(${ARDUINO_LIBRARIES_PATH}) + add_definitions(-DF_CPU=${${BOARD_ID}.build.f_cpu} + -DARDUINO=${ARDUINO_VERSION_DEFINE} + -mmcu=${${BOARD_ID}.build.mcu} + ) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -mmcu=${${BOARD_ID}.build.mcu}" PARENT_SCOPE) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -mmcu=${${BOARD_ID}.build.mcu}" PARENT_SCOPE) + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -mmcu=${${BOARD_ID}.build.mcu}" PARENT_SCOPE) + else() + message(FATAL_ERROR "Invalid Arduino board ID (${BOARD_ID}), aborting.") + endif() +endmacro() + +# setup_arduino_core(VAR_NAME BOARD_ID) +# +# VAR_NAME - Variable name that will hold the generated library name +# BOARD_ID - Arduino board id +# +# Creates the Arduino Core library for the specified board, +# each board gets it's own version of the library. +# +function(setup_arduino_core VAR_NAME BOARD_ID) + set(CORE_LIB_NAME ${BOARD_ID}_CORE) + set(BOARD_CORE ${${BOARD_ID}.build.core}) + if(BOARD_CORE AND NOT TARGET ${CORE_LIB_NAME}) + set(BOARD_CORE_PATH ${ARDUINO_CORES_PATH}/${BOARD_CORE}) + find_sources(CORE_SRCS ${BOARD_CORE_PATH} True) + # Debian/Ubuntu fix + list(REMOVE_ITEM CORE_SRCS "${BOARD_CORE_PATH}/main.cxx") + add_library(${CORE_LIB_NAME} ${CORE_SRCS}) + set(${VAR_NAME} ${CORE_LIB_NAME} PARENT_SCOPE) + endif() +endfunction() + +# find_arduino_libraries(VAR_NAME SRCS) +# +# VAR_NAME - Variable name which will hold the results +# SRCS - Sources that will be analized +# +# returns a list of paths to libraries found. +# +# Finds all Arduino type libraries included in sources. Available libraries +# are ${ARDUINO_SDK_PATH}/libraries and ${CMAKE_CURRENT_SOURCE_DIR}. +# +# A Arduino library is a folder that has the same name as the include header. +# For example, if we have a include "#include " then the following +# directory structure is considered a Arduino library: +# +# LibraryName/ +# |- LibraryName.h +# `- LibraryName.c +# +# If such a directory is found then all sources within that directory are considred +# to be part of that Arduino library. +# +function(find_arduino_libraries VAR_NAME SRCS) + set(ARDUINO_LIBS ) + foreach(SRC ${SRCS}) + file(STRINGS ${SRC} SRC_CONTENTS) + foreach(SRC_LINE ${SRC_CONTENTS}) + if("${SRC_LINE}" MATCHES "^ *#include *[<\"](.*)[>\"]") + get_filename_component(INCLUDE_NAME ${CMAKE_MATCH_1} NAME_WE) + get_property(LIBRARY_SEARCH_PATH + DIRECTORY # Property Scope + PROPERTY LINK_DIRECTORIES) + foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries) + if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}) + list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) + break() + endif() + endforeach() + endif() + endforeach() + endforeach() + if(ARDUINO_LIBS) + list(REMOVE_DUPLICATES ARDUINO_LIBS) + endif() + set(${VAR_NAME} ${ARDUINO_LIBS} PARENT_SCOPE) +endfunction() + +# setup_arduino_library(VAR_NAME BOARD_ID LIB_PATH) +# +# VAR_NAME - Vairable wich will hold the generated library names +# BOARD_ID - Board name +# LIB_PATH - path of the library +# +# Creates an Arduino library, with all it's library dependencies. +# +# ${LIB_NAME}_RECURSE controls if the library will recurse +# when looking for source files. +# + +# For known libraries can list recurse here +set(Wire_RECURSE True) +set(Ethernet_RECURSE True) +function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH) + set(LIB_TARGETS) + + get_filename_component(LIB_NAME ${LIB_PATH} NAME) + set(TARGET_LIB_NAME ${BOARD_ID}_${LIB_NAME}) + if(NOT TARGET ${TARGET_LIB_NAME}) + string(REGEX REPLACE ".*/" "" LIB_SHORT_NAME ${LIB_NAME}) + + # Detect if recursion is needed + if (NOT DEFINED ${LIB_SHORT_NAME}_RECURSE) + set(${LIB_SHORT_NAME}_RECURSE False) + endif() + + find_sources(LIB_SRCS ${LIB_PATH} ${${LIB_SHORT_NAME}_RECURSE}) + if(LIB_SRCS) + + message(STATUS "Generating Arduino ${LIB_NAME} library") + include_directories(${LIB_PATH} ${LIB_PATH}/utility) + add_library(${TARGET_LIB_NAME} STATIC ${LIB_SRCS}) + + find_arduino_libraries(LIB_DEPS "${LIB_SRCS}") + foreach(LIB_DEP ${LIB_DEPS}) + setup_arduino_library(DEP_LIB_SRCS ${BOARD_ID} ${LIB_DEP}) + list(APPEND LIB_TARGETS ${DEP_LIB_SRCS}) + endforeach() + + target_link_libraries(${TARGET_LIB_NAME} ${BOARD_ID}_CORE ${LIB_TARGETS}) + list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) + endif() + else() + # Target already exists, skiping creating + include_directories(${LIB_PATH} ${LIB_PATH}/utility) + list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) + endif() + if(LIB_TARGETS) + list(REMOVE_DUPLICATES LIB_TARGETS) + endif() + set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) +endfunction() + +# setup_arduino_libraries(VAR_NAME BOARD_ID SRCS) +# +# VAR_NAME - Vairable wich will hold the generated library names +# BOARD_ID - Board ID +# SRCS - source files +# +# Finds and creates all dependency libraries based on sources. +# +function(setup_arduino_libraries VAR_NAME BOARD_ID SRCS) + set(LIB_TARGETS) + find_arduino_libraries(TARGET_LIBS "${SRCS}") + foreach(TARGET_LIB ${TARGET_LIBS}) + setup_arduino_library(LIB_DEPS ${BOARD_ID} ${TARGET_LIB}) # Create static library instead of returning sources + list(APPEND LIB_TARGETS ${LIB_DEPS}) + endforeach() + set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) +endfunction() + + +# setup_arduino_target(TARGET_NAME ALL_SRCS ALL_LIBS) +# +# TARGET_NAME - Target name +# ALL_SRCS - All sources +# ALL_LIBS - All libraries +# +# Creates an Arduino firmware target. +# +function(setup_arduino_target TARGET_NAME ALL_SRCS ALL_LIBS) + add_executable(${TARGET_NAME} ${ALL_SRCS}) + target_link_libraries(${TARGET_NAME} ${ALL_LIBS}) + set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".elf") + + set(TARGET_PATH ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} + ARGS ${ARDUINO_OBJCOPY_EEP_FLAGS} + ${TARGET_PATH}.elf + ${TARGET_PATH}.eep + VERBATIM) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} + ARGS ${ARDUINO_OBJCOPY_HEX_FLAGS} + ${TARGET_PATH}.elf + ${TARGET_PATH}.hex + VERBATIM) +endfunction() + +# setup_arduino_upload(BOARD_ID TARGET_NAME PORT) +# +# BOARD_ID - Arduino board id +# TARGET_NAME - Target name +# PORT - Serial port for upload +# +# Create an upload target (${TARGET_NAME}-upload) for the specified Arduino target. +# +function(setup_arduino_upload BOARD_ID TARGET_NAME PORT) +# setup_arduino_bootloader_upload() + setup_arduino_bootloader_upload(${TARGET_NAME} ${BOARD_ID} ${PORT}) + + # Add programmer support if defined + if(${TARGET_NAME}_PROGRAMMER AND ${${TARGET_NAME}_PROGRAMMER}.protocol) + setup_arduino_programmer_burn(${TARGET_NAME} ${BOARD_ID} ${${TARGET_NAME}_PROGRAMMER} ${PORT}) + setup_arduino_bootloader_burn(${TARGET_NAME} ${BOARD_ID} ${${TARGET_NAME}_PROGRAMMER} ${PORT}) + endif() +endfunction() + + +# setup_arduino_bootloader_upload(TARGET_NAME BOARD_ID PORT) +# +# TARGET_NAME - target name +# BOARD_ID - board id +# PORT - serial port +# +# Set up target for upload firmware via the bootloader. +# +# The target for uploading the firmware is ${TARGET_NAME}-upload . +# +function(setup_arduino_bootloader_upload TARGET_NAME BOARD_ID PORT) + set(UPLOAD_TARGET ${TARGET_NAME}-upload) + set(AVRDUDE_ARGS) + + setup_arduino_bootloader_args(${BOARD_ID} ${TARGET_NAME} ${PORT} AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude bootloader args, aborting!") + return() + endif() + + list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_NAME}.hex") + add_custom_target(${UPLOAD_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + DEPENDS ${TARGET_NAME}) +endfunction() + +# setup_arduino_programmer_burn(TARGET_NAME BOARD_ID PROGRAMMER) +# +# TARGET_NAME - name of target to burn +# BOARD_ID - board id +# PROGRAMMER - programmer id +# +# Sets up target for burning firmware via a programmer. +# +# The target for burning the firmware is ${TARGET_NAME}-burn . +# +function(setup_arduino_programmer_burn TARGET_NAME BOARD_ID PROGRAMMER) + set(PROGRAMMER_TARGET ${TARGET_NAME}-burn) + + set(AVRDUDE_ARGS) + + setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude programmer args, aborting!") + return() + endif() + + list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_NAME}.hex") + + add_custom_target(${PROGRAMMER_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + DEPENDS ${TARGET_NAME}) +endfunction() + +# setup_arduino_bootloader_burn(TARGET_NAME BOARD_ID PROGRAMMER) +# +# TARGET_NAME - name of target to burn +# BOARD_ID - board id +# PROGRAMMER - programmer id +# +# Create a target for burning a bootloader via a programmer. +# +# The target for burning the bootloader is ${TARGET_NAME}-burn-bootloader +# +function(setup_arduino_bootloader_burn TARGET_NAME BOARD_ID PROGRAMMER PORT) + set(BOOTLOADER_TARGET ${TARGET_NAME}-burn-bootloader) + + set(AVRDUDE_ARGS) + + setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} AVRDUDE_ARGS) + + if(NOT AVRDUDE_ARGS) + message("Could not generate default avrdude programmer args, aborting!") + return() + endif() + + if(NOT ${BOARD_ID}.bootloader.unlock_bits) + message("Missing ${BOARD_ID}.bootloader.unlock_bits, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + if(NOT ${BOARD_ID}.bootloader.high_fuses) + message("Missing ${BOARD_ID}.bootloader.high_fuses, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + if(NOT ${BOARD_ID}.bootloader.low_fuses) + message("Missing ${BOARD_ID}.bootloader.low_fuses, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + if(NOT ${BOARD_ID}.bootloader.path) + message("Missing ${BOARD_ID}.bootloader.path, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + if(NOT ${BOARD_ID}.bootloader.file) + message("Missing ${BOARD_ID}.bootloader.file, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + + if(NOT EXISTS "${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}.bootloader.file}") + message("${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}.bootloader.file}") + message("Missing bootloader image, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + return() + endif() + + # Erase the chip + list(APPEND AVRDUDE_ARGS "-e") + + # Set unlock bits and fuses (because chip is going to be erased) + list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.unlock_bits}:m") + if(${BOARD_ID}.bootloader.extended_fuses) + list(APPEND AVRDUDE_ARGS "-Uefuse:w:${${BOARD_ID}.bootloader.extended_fuses}:m") + endif() + list(APPEND AVRDUDE_ARGS "-Uhfuse:w:${${BOARD_ID}.bootloader.high_fuses}:m") + list(APPEND AVRDUDE_ARGS "-Ulfuse:w:${${BOARD_ID}.bootloader.low_fuses}:m") + + # Set bootloader image + list(APPEND AVRDUDE_ARGS "-Uflash:w:${${BOARD_ID}.bootloader.file}:i") + + # Set lockbits + list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.lock_bits}:m") + + # Create burn bootloader target + add_custom_target(${BOOTLOADER_TARGET} + ${ARDUINO_AVRDUDE_PROGRAM} + ${AVRDUDE_ARGS} + WORKING_DIRECTORY ${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path} + DEPENDS ${TARGET_NAME}) +endfunction() + +# setup_arduino_programmer_args(PROGRAMMER OUTPUT_VAR) +# +# PROGRAMMER - programmer id +# TARGET_NAME - target name +# OUTPUT_VAR - name of output variable for result +# +# Sets up default avrdude settings for burning firmware via a programmer. +function(setup_arduino_programmer_args BOARD_ID PROGRAMMER TARGET_NAME PORT OUTPUT_VAR) + set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) + + set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) + if(DEFINED ${TARGET_NAME}_AFLAGS) + set(AVRDUDE_FLAGS ${${TARGET_NAME}_AFLAGS}) + endif() + + list(APPEND AVRDUDE_ARGS "-C${ARDUINO_AVRDUDE_CONFIG_PATH}") + + #TODO: Check mandatory settings before continuing + if(NOT ${PROGRAMMER}.protocol) + message(FATAL_ERROR "Missing ${PROGRAMMER}.protocol, aborting!") + endif() + + list(APPEND AVRDUDE_ARGS "-c${${PROGRAMMER}.protocol}") # Set programmer + + if(${PROGRAMMER}.communication STREQUAL "usb") + list(APPEND AVRDUDE_ARGS "-Pusb") # Set USB as port + elseif(${PROGRAMMER}.communication STREQUAL "serial") + list(APPEND AVRDUDE_ARGS "-P${PORT}") # Set port + if(${PROGRAMMER}.speed) + list(APPEND AVRDUDE_ARGS "-b${${PROGRAMMER}.speed}") # Set baud rate + endif() + endif() + + if(${PROGRAMMER}.force) + list(APPEND AVRDUDE_ARGS "-F") # Set force + endif() + + if(${PROGRAMMER}.delay) + list(APPEND AVRDUDE_ARGS "-i${${PROGRAMMER}.delay}") # Set delay + endif() + + list(APPEND AVRDUDE_ARGS "-p${${BOARD_ID}.build.mcu}") # MCU Type + + list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) + + set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) +endfunction() + +# setup_arduino_bootloader_args(BOARD_ID TARGET_NAME PORT OUTPUT_VAR) +# +# BOARD_ID - board id +# TARGET_NAME - target name +# PORT - serial port +# OUTPUT_VAR - name of output variable for result +# +# Sets up default avrdude settings for uploading firmware via the bootloader. +function(setup_arduino_bootloader_args BOARD_ID TARGET_NAME PORT OUTPUT_VAR) + set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) + + set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) + if(DEFINED ${TARGET_NAME}_AFLAGS) + set(AVRDUDE_FLAGS ${${TARGET_NAME}_AFLAGS}) + endif() + + list(APPEND AVRDUDE_ARGS "-C${ARDUINO_AVRDUDE_CONFIG_PATH}") # avrdude config + + list(APPEND AVRDUDE_ARGS "-p${${BOARD_ID}.build.mcu}") # MCU Type + + # Programmer + if(${BOARD_ID}.upload.protocol STREQUAL "stk500") + list(APPEND AVRDUDE_ARGS "-cstk500v1") + else() + list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}.upload.protocol}") + endif() + + list(APPEND AVRDUDE_ARGS "-b${${BOARD_ID}.upload.speed}") # Baud rate + + list(APPEND AVRDUDE_ARGS "-P${PORT}") # Serial port + + list(APPEND AVRDUDE_ARGS "-D") # Dont erase + + list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) + + set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) +endfunction() + +# find_sources(VAR_NAME LIB_PATH RECURSE) +# +# VAR_NAME - Variable name that will hold the detected sources +# LIB_PATH - The base path +# RECURSE - Whether or not to recurse +# +# Finds all C/C++ sources located at the specified path. +# +function(find_sources VAR_NAME LIB_PATH RECURSE) + set(FILE_SEARCH_LIST + ${LIB_PATH}/*.cpp + ${LIB_PATH}/*.c + ${LIB_PATH}/*.cc + ${LIB_PATH}/*.cxx + ${LIB_PATH}/*.h + ${LIB_PATH}/*.hh + ${LIB_PATH}/*.hxx) + + if(RECURSE) + file(GLOB_RECURSE LIB_FILES ${FILE_SEARCH_LIST}) + else() + file(GLOB LIB_FILES ${FILE_SEARCH_LIST}) + endif() + + if(LIB_FILES) + set(${VAR_NAME} ${LIB_FILES} PARENT_SCOPE) + endif() +endfunction() + +# setup_serial_target(TARGET_NAME CMD) +# +# TARGET_NAME - Target name +# CMD - Serial terminal command +# +# Creates a target (${TARGET_NAME}-serial) for launching the serial termnial. +# +function(setup_serial_target TARGET_NAME CMD) + string(CONFIGURE "${CMD}" FULL_CMD @ONLY) + add_custom_target(${TARGET_NAME}-serial + ${FULL_CMD}) +endfunction() + + +# detect_arduino_version(VAR_NAME) +# +# VAR_NAME - Variable name where the detected version will be saved +# +# Detects the Arduino SDK Version based on the revisions.txt file. +# +function(detect_arduino_version VAR_NAME) + if(ARDUINO_VERSION_PATH) + file(READ ${ARDUINO_VERSION_PATH} ARD_VERSION) + if("${ARD_VERSION}" MATCHES " *[0]+([0-9]+)") + set(${VAR_NAME} ${CMAKE_MATCH_1} PARENT_SCOPE) + elseif("${ARD_VERSION}" MATCHES "[ ]*([0-9]+[.][0-9]+)") + set(${VAR_NAME} ${CMAKE_MATCH_1} PARENT_SCOPE) + endif() + endif() +endfunction() + + +function(convert_arduino_sketch VAR_NAME SRCS) +endfunction() + +# load_arduino_style_settings(SETTINGS_LIST SETTINGS_PATH) +# +# SETTINGS_LIST - Variable name of settings list +# SETTINGS_PATH - File path of settings file to load. +# +# Load a Arduino style settings file into the cache. +# +# Examples of this type of settings file is the boards.txt and +# programmers.txt files located in ${ARDUINO_SDK}/hardware/arduino. +# +# Settings have to following format: +# +# entry.setting[.subsetting] = value +# +# where [.subsetting] is optional +# +# For example, the following settings: +# +# uno.name=Arduino Uno +# uno.upload.protocol=stk500 +# uno.upload.maximum_size=32256 +# uno.build.mcu=atmega328p +# uno.build.core=arduino +# +# will generate the follwoing equivalent CMake variables: +# +# set(uno.name "Arduino Uno") +# set(uno.upload.protocol "stk500") +# set(uno.upload.maximum_size "32256") +# set(uno.build.mcu "atmega328p") +# set(uno.build.core "arduino") +# +# set(uno.SETTINGS name upload build) # List of settings for uno +# set(uno.upload.SUBSETTINGS protocol maximum_size) # List of sub-settings for uno.upload +# set(uno.build.SUBSETTINGS mcu core) # List of sub-settings for uno.build +# +# The ${ENTRY_NAME}.SETTINGS variable lists all settings for the entry, while +# ${ENTRY_NAME}.SUBSETTINGS variables lists all settings for a sub-setting of +# a entry setting pair. +# +# These variables are generated in order to be able to programatically traverse +# all settings (for a example see print_board_settings() function). +# +function(LOAD_ARDUINO_STYLE_SETTINGS SETTINGS_LIST SETTINGS_PATH) + + if(NOT ${SETTINGS_LIST} AND EXISTS ${SETTINGS_PATH}) + file(STRINGS ${SETTINGS_PATH} FILE_ENTRIES) # Settings file split into lines + + foreach(FILE_ENTRY ${FILE_ENTRIES}) + if("${FILE_ENTRY}" MATCHES "^[^#]+=.*") + string(REGEX MATCH "^[^=]+" SETTING_NAME ${FILE_ENTRY}) + string(REGEX MATCH "[^=]+$" SETTING_VALUE ${FILE_ENTRY}) + string(REPLACE "." ";" ENTRY_NAME_TOKENS ${SETTING_NAME}) + string(STRIP "${SETTING_VALUE}" SETTING_VALUE) + + list(LENGTH ENTRY_NAME_TOKENS ENTRY_NAME_TOKENS_LEN) + + + # Add entry to settings list if it does not exist + list(GET ENTRY_NAME_TOKENS 0 ENTRY_NAME) + list(FIND ${SETTINGS_LIST} ${ENTRY_NAME} ENTRY_NAME_INDEX) + if(ENTRY_NAME_INDEX LESS 0) + # Add entry to main list + list(APPEND ${SETTINGS_LIST} ${ENTRY_NAME}) + endif() + + # Add entry setting to entry settings list if it does not exist + set(ENTRY_SETTING_LIST ${ENTRY_NAME}.SETTINGS) + list(GET ENTRY_NAME_TOKENS 1 ENTRY_SETTING) + list(FIND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING} ENTRY_SETTING_INDEX) + if(ENTRY_SETTING_INDEX LESS 0) + # Add setting to entry + list(APPEND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING}) + set(${ENTRY_SETTING_LIST} ${${ENTRY_SETTING_LIST}} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board settings list") + endif() + + set(FULL_SETTING_NAME ${ENTRY_NAME}.${ENTRY_SETTING}) + + # Add entry sub-setting to entry sub-settings list if it does not exists + if(ENTRY_NAME_TOKENS_LEN GREATER 2) + set(ENTRY_SUBSETTING_LIST ${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) + list(GET ENTRY_NAME_TOKENS 2 ENTRY_SUBSETTING) + list(FIND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING} ENTRY_SUBSETTING_INDEX) + if(ENTRY_SUBSETTING_INDEX LESS 0) + list(APPEND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING}) + set(${ENTRY_SUBSETTING_LIST} ${${ENTRY_SUBSETTING_LIST}} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board sub-settings list") + endif() + set(FULL_SETTING_NAME ${FULL_SETTING_NAME}.${ENTRY_SUBSETTING}) + endif() + + # Save setting value + set(${FULL_SETTING_NAME} ${SETTING_VALUE} + CACHE INTERNAL "Arduino ${ENTRY_NAME} Board setting") + + + endif() + endforeach() + set(${SETTINGS_LIST} ${${SETTINGS_LIST}} + CACHE STRING "List of detected Arduino Board configurations") + mark_as_advanced(${SETTINGS_LIST}) + endif() +endfunction() + +# print_settings(ENTRY_NAME) +# +# ENTRY_NAME - name of entry +# +# Print the entry settings (see load_arduino_syle_settings()). +# +function(PRINT_SETTINGS ENTRY_NAME) + if(${ENTRY_NAME}.SETTINGS) + + foreach(ENTRY_SETTING ${${ENTRY_NAME}.SETTINGS}) + if(${ENTRY_NAME}.${ENTRY_SETTING}) + message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}}") + endif() + if(${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) + foreach(ENTRY_SUBSETTING ${${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS}) + if(${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}) + message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}}") + endif() + endforeach() + endif() + message(STATUS "") + endforeach() + endif() +endfunction() + +# print_list(SETTINGS_LIST) +# +# SETTINGS_LIST - Variables name of settings list +# +# Print list settings and names (see load_arduino_syle_settings()). +function(PRINT_LIST SETTINGS_LIST) + if(${SETTINGS_LIST}) + set(MAX_LENGTH 0) + foreach(ENTRY_NAME ${${SETTINGS_LIST}}) + string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) + if(CURRENT_LENGTH GREATER MAX_LENGTH) + set(MAX_LENGTH ${CURRENT_LENGTH}) + endif() + endforeach() + foreach(ENTRY_NAME ${${SETTINGS_LIST}}) + string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) + math(EXPR PADDING_LENGTH "${MAX_LENGTH}-${CURRENT_LENGTH}") + set(PADDING "") + foreach(X RANGE ${PADDING_LENGTH}) + set(PADDING "${PADDING} ") + endforeach() + message(STATUS " ${PADDING}${ENTRY_NAME}: ${${ENTRY_NAME}.name}") + endforeach() + endif() +endfunction() + + +# Setting up Arduino enviroment settings +if(NOT ARDUINO_FOUND) + find_file(ARDUINO_CORES_PATH + NAMES cores + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino) + + find_file(ARDUINO_VARIANTS_PATH + NAMES variants + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino) + + find_file(ARDUINO_BOOTLOADERS_PATH + NAMES bootloaders + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino) + + find_file(ARDUINO_LIBRARIES_PATH + NAMES libraries + PATHS ${ARDUINO_SDK_PATH}) + + find_file(ARDUINO_BOARDS_PATH + NAMES boards.txt + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino) + + find_file(ARDUINO_PROGRAMMERS_PATH + NAMES programmers.txt + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/arduino) + + find_file(ARDUINO_REVISIONS_PATH + NAMES revisions.txt + PATHS ${ARDUINO_SDK_PATH}) + + find_file(ARDUINO_VERSION_PATH + NAMES lib/version.txt + PATHS ${ARDUINO_SDK_PATH}) + + find_program(ARDUINO_AVRDUDE_PROGRAM + NAMES avrdude + PATHS ${ARDUINO_SDK_PATH} + PATH_SUFFIXES hardware/tools) + + find_program(ARDUINO_AVRDUDE_CONFIG_PATH + NAMES avrdude.conf + PATHS ${ARDUINO_SDK_PATH} /etc/avrdude + PATH_SUFFIXES hardware/tools + hardware/tools/avr/etc) + + set(ARDUINO_OBJCOPY_EEP_FLAGS -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 + CACHE STRING "") + set(ARDUINO_OBJCOPY_HEX_FLAGS -O ihex -R .eeprom + CACHE STRING "") + set(ARDUINO_AVRDUDE_FLAGS -V + CACHE STRING "Arvdude global flag list.") + + if(ARDUINO_SDK_PATH) + detect_arduino_version(ARDUINO_SDK_VERSION) + set(ARDUINO_SDK_VERSION ${ARDUINO_SDK_VERSION} CACHE STRING "Arduino SDK Version") + endif(ARDUINO_SDK_PATH) + + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(Arduino + REQUIRED_VARS ARDUINO_SDK_PATH + ARDUINO_SDK_VERSION + VERSION_VAR ARDUINO_SDK_VERSION) + + + mark_as_advanced(ARDUINO_CORES_PATH + ARDUINO_VARIANTS_PATH + ARDUINO_BOOTLOADERS_PATH + ARDUINO_SDK_VERSION + ARDUINO_LIBRARIES_PATH + ARDUINO_BOARDS_PATH + ARDUINO_PROGRAMMERS_PATH + ARDUINO_REVISIONS_PATH + ARDUINO_VERSION_PATH + ARDUINO_AVRDUDE_FLAGS + ARDUINO_AVRDUDE_PROGRAM + ARDUINO_AVRDUDE_CONFIG_PATH + ARDUINO_OBJCOPY_EEP_FLAGS + ARDUINO_OBJCOPY_HEX_FLAGS) + + load_board_settings() + load_programmers_settings() + + print_board_list() + print_programmer_list() + + set(ARDUINO_FOUND True CACHE INTERNAL "Arduino Found") +endif() + diff --git a/arduino-cmake/cmake/modules/Platform/Arduino.cmake b/arduino-cmake/cmake/modules/Platform/Arduino.cmake new file mode 100644 index 0000000..e69de29 diff --git a/arduino-cmake/cmake/modules/Platform/ArduinoPaths.cmake b/arduino-cmake/cmake/modules/Platform/ArduinoPaths.cmake new file mode 100644 index 0000000..2737209 --- /dev/null +++ b/arduino-cmake/cmake/modules/Platform/ArduinoPaths.cmake @@ -0,0 +1,21 @@ +if(UNIX) + include(Platform/UnixPaths) + if(APPLE) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ~/Applications + /Applications + /Developer/Applications + /sw # Fink + /opt/local) # MacPorts + endif() +elseif(WIN32) + include(Platform/WindowsPaths) +endif() + +if(ARDUINO_SDK_PATH) + if(WIN32) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/bin) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/utils/bin) + elseif(APPLE) + list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/bin) + endif() +endif() diff --git a/arduino-cmake/cmake/toolchains/Arduino.cmake b/arduino-cmake/cmake/toolchains/Arduino.cmake new file mode 100644 index 0000000..75a6758 --- /dev/null +++ b/arduino-cmake/cmake/toolchains/Arduino.cmake @@ -0,0 +1,74 @@ +set(CMAKE_SYSTEM_NAME Arduino) + +set(CMAKE_C_COMPILER avr-gcc) +set(CMAKE_CXX_COMPILER avr-g++) + +#=============================================================================# +# C Flags # +#=============================================================================# +if (NOT DEFINED ARDUINO_C_FLAGS) + set(ARDUINO_C_FLAGS "-ffunction-sections -fdata-sections") +endif() +set(CMAKE_C_FLAGS "-g -Os ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_DEBUG "-g ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELEASE "-0s -DNDEBUG -w ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "-0s -g -w ${ARDUINO_C_FLAGS}" CACHE STRING "") + +#=============================================================================# +# C++ Flags # +#=============================================================================# +if (NOT DEFINED ARDUINO_CXX_FLAGS) + set(ARDUINO_CXX_FLAGS "${ARDUINO_C_FLAGS} -fno-exceptions") +endif() +set(CMAKE_CXX_FLAGS "-g -Os ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_DEBUG "-g ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELEASE "-0s -DNDEBUG ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-0s -g ${ARDUINO_CXX_FLAGS}" CACHE STRING "") + +#=============================================================================# +# Executable Linker Flags # +#=============================================================================# +if (NOT DEFINED ARDUINO_LINKER_FLAGS) + set(ARDUINO_LINKER_FLAGS "-Wl,--gc-sections") +endif() +set(CMAKE_EXE_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") +set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") + +#=============================================================================# +# Shared Lbrary Linker Flags # +#=============================================================================# +set(CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "" CACHE STRING "") +set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "" CACHE STRING "") + +set(CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "" CACHE STRING "") +set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "" CACHE STRING "") + + + + +set(ARDUINO_PATHS) +foreach(VERSION 22 1) + list(APPEND ARDUINO_PATHS arduino-00${VERSION}) +endforeach() + +#list(APPEND ARDUINO_PATHS arduino) + +find_path(ARDUINO_SDK_PATH + NAMES lib/version.txt + PATH_SUFFIXES share/arduino + Arduino.app/Contents/Resources/Java/ + ${ARDUINO_PATHS} + DOC "Arduino Development Kit path.") + +include(Platform/ArduinoPaths) diff --git a/arduino-cmake/configure b/arduino-cmake/configure new file mode 100755 index 0000000..ca7c4c3 --- /dev/null +++ b/arduino-cmake/configure @@ -0,0 +1,249 @@ +#!/usr/bin/env bash + +#==============================================================================# +# # +# Author : QueezyTheGreat # +# Description: Build configuration script # +# # +# Makes sure that we don't execute cmake or ccmake in the source # +# directory(we like prestine sources) # +# # +# If we execute this script in the sources directory, a build directory # +# will be created from where the actual build configuration will be executed. # +# # +# If we aren't in the source directory everything works normally. # +# # +# By default cmake is used to configure the build system, but you can also # +# chose from the ncurses version (ccmake) and the GUI version (cmake-gui). # +# # +#==============================================================================# + + +# Find executable path +function path_locate { + local EXECUTABLE_NAME + local PATH_OUTPUT_VARIABLE_NAME + local EXECUTABLE_PATH + + # Check if we have required arguments + if [ "${#}" -lt 2 ]; then + echo "Insuficient amount of arguments..." + echo "locate_path EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + + EXECUTABLE_NAME="$1" + PATH_OUTPUT_VAR="$2" + + if [ "${EXECUTABLE_NAME}X" = "X" ]; then + echo "Missing executable name" + echo "locate_path EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + if [ "${PATH_OUTPUT_VAR}X" = "X" ]; then + echo "Missing path output variable name" + echo "locate_path EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + + # Try to find full path + EXECUTABLE_PATH="$(type -p ${EXECUTABLE_NAME})" + + # Setting executable path + eval "${PATH_OUTPUT_VAR}"=${EXECUTABLE_PATH} +} + +# Find executable path, exit if not found +function require { + local EXECUTABLE_NAME + local PATH_OUTPUT_VARIABLE_NAME + local EXECUTABLE_PATH + + # Check if we have required arguments + if [ "${#}" -lt 2 ]; then + echo "Insuficient amount of arguments..." + echo "require EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + + EXECUTABLE_NAME="$1" + PATH_OUTPUT_VAR="$2" + + if [ "${EXECUTABLE_NAME}X" = "X" ]; then + echo "Missing executable name" + echo "require EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + if [ "${PATH_OUTPUT_VAR}X" = "X" ]; then + echo "Missing path output variable name" + echo "require EXECUTABLE_NAME PATH_OUTPUT_VARIABLE_NAME" + exit 1 + fi + + # Try to find full path + EXECUTABLE_PATH="$(type -p ${EXECUTABLE_NAME})" + + if [ "${EXECUTABLE_PATH}X" = "X" ]; then + # No path was found.... failing + echo "${EXECUTABLE_NAME} is not available" + echo "Aborting..." + + exit -1 + fi + + if [ ! -x "${EXECUTABLE_PATH}" ]; then + echo "${EXECUTABLE_NAME} is not executable" + echo "Aborting..." + + exit -1 + fi + + # Setting executable path + eval "${PATH_OUTPUT_VAR}"=${EXECUTABLE_PATH} +} + + +# Executable names +CMAKE_NAME="cmake" +CCMAKE_NAME="ccmake" +CMAKEGUI_NAME="cmake-gui" + +# Find executable paths +require ${CMAKE_NAME} CMAKE_PATH +path_locate ${CCMAKE_NAME} CCMAKE_PATH +path_locate ${CMAKEGUI_NAME} CMAKEGUI_PATH + +# Warning file +WARNING_PATH="${HOME}/.configure_warning" + +# Detect where we are and where the sources are +CONFIG_BASE_PATH=$(cd "$(dirname "$0")"; pwd) +CURRENT_PATH=$(pwd) + +IN_BASE="$(echo ${CURRENT_PATH}| grep ${CONFIG_BASE_PATH})" +IN_BUILD="$(echo ${CURRENT_PATH}| grep ${CONFIG_BASE_PATH}/build)" + +# Set the default cmake executable +# to be used +CMAKE_EXECUTABLE="${CMAKE_PATH}" + +# Check for command line arguments +case $1 in + "-h") + echo "$0 [-h|-x|-c] [cmake_args...]" + echo + echo " -h Display this help message" + echo " -x Run GUI version of CMake" + echo " -c Run Curses version of CMake" + echo + echo " cmake_args CMake arguments that will be passed" + echo " to the chosen CMake binary, by default" + echo " cmake is used (if -x or -c not used)" + echo + + exit 1 + ;; + "-x") + if [ ! -e "${CMAKEGUI_PATH}" ]; then + echo "${CMAKEGUI_NAME} is not available" + echo "Aborting...'" + + exit -1 + fi + + # Setting executable to cmake-gui + CMAKE_EXECUTABLE="${CMAKEGUI_PATH}" + + # Shift argument list, getting rid of script name + # and first command line argument + shift + ;; + "-c") + if [ ! -e "${CCMAKE_PATH}" ]; then + echo "${CCMAKE_NAME} is not available" + echo "Aborting...'" + + exit -1 + + fi + + # Setting executable to ccmake + CMAKE_EXECUTABLE="${CCMAKE_PATH}" + + # Shift argument list, getting rid of script name + # and first command line argument + shift + ;; +esac + + +echo +echo Project Sources: ${CONFIG_BASE_PATH} +echo CMake Executable: ${CMAKE_EXECUTABLE} +echo + + +# Check if we are in source directory +if [ "${IN_BASE}X" != "X" ]; then + # We are within the source directory + if [ "${IN_BUILD}X" != "X" ]; then + # We are in the build directory + echo 'Building within build directory' + # Running chosen cmake executable + ${CMAKE_EXECUTABLE} ${*} ${CONFIG_BASE_PATH} + else + # We are in the source directory + # but not within the build directory + if [ ! -f "${WARNING_PATH}" ]; then + echo + echo + echo "Running CMake within the source directory is HIGHLY discouraged." + echo "You should either build the project outside the source directory" + echo "or create a directory called build within the root of the project" + echo + echo + echo "This warning will only apear once..." + echo + echo + echo + echo -n "Continuing in 15" + for COUNT in 14 13 12 11 10 9 8 7 6 5 4 3 2 1; do + sleep 1 + echo -n "..${COUNT}" + done + echo + + # Removing waring + touch "${WARNING_PATH}" + fi + + if [ ! -d "${CONFIG_BASE_PATH}/build" ]; then + echo "Creating build directory: ${CONFIG_BASE_PATH}/build" + mkdir "${CONFIG_BASE_PATH}/build" + fi + + # Changing to build directory + echo "Changing to build directory: ${CONFIG_BASE_PATH}/build" + cd "${CONFIG_BASE_PATH}/build" + + # Running chosen cmake executable in new build directory + ${CMAKE_EXECUTABLE} ${*} ${CONFIG_BASE_PATH} + + fi +else + # We are outside of the source directory + # Running chosen cmake executable + ${CMAKE_EXECUTABLE} ${*} ${CONFIG_BASE_PATH} +fi + +if [ "${?}" -eq 0 ]; then + echo + echo "To build project: make" + echo "To install project: make install" + echo "Generate packages: make package" + echo + + exit 0 +else + exit 1 +fi diff --git a/arduino-cmake/configure.bat b/arduino-cmake/configure.bat new file mode 100644 index 0000000..580635d --- /dev/null +++ b/arduino-cmake/configure.bat @@ -0,0 +1,95 @@ +::===========================================================================:: +:: Author: QueezyTheGreat :: +:: Description: Small wrapper around cmake and cmake-gui for :: +:: easy build system configuration and generation. :: +::===========================================================================:: +@echo off + +set CURRENT_PATH=%CD% + +set CONFIGURE_PATH=%~dp0% +set CONFIGURE_MODE=%1 +set CONFIGURE_ARGS=%* + +set BUILD_PATh=build + +set CMAKE_NAME=cmake.exe +set CMAKEGUI_NAME=cmake-gui.exe + + +:: Parse arguments +if /i [%CONFIGURE_MODE%] EQU [-h] goto :print_help +if /i [%CONFIGURE_MODE%] EQU [--help] goto :print_help +if /i [%CONFIGURE_MODE%] EQU [/?] goto :print_help + + +:: Check dependencies +for %%X in (%CMAKE_NAME% %CMAKEGUI_NAME%) do ( + set FOUND=%%~$PATH:X + if not defined FOUND ( + echo %%X missing on the path, aborting! + echo. + echo Please ensure that CMake is available on the system path. + echo. + pause + goto :EXIT + ) +) + +:: Generate/Configure build +call :init_build +call :setup_build + + +::===========================================================================:: +:: :: +::===========================================================================:: +goto :EXIT + + +:: Initialize build path +:init_build + if "%CURRENT_PATH%\" EQU "%CONFIGURE_PATH%" ( + :: In sources, create build directory + set "BUILD_PATH=%CONFIGURE_PATH%%BUILD_PATH%" + + :: Create build directory + if not exist "%BUILD_PATH%" ( + mkdir "%BUILD_PATH%" + ) + ) else ( + :: Out of sources, do nothing + set BUILD_PATH=%CD% + ) + goto :RETURN + +:: Configure/Generate build system +:setup_build + cd "%BUILD_PATH%" + if /i [%CONFIGURE_MODE%] EQU [-c] ( + :: Command Line version (cmake) + echo cmake %CONFIGURE_ARGS:~3% "%CONFIGURE_PATH%" + %CMAKE_NAME% %CONFIGURE_ARGS:~3% "%CONFIGURE_PATH%" + ) else ( + :: GUI version (cmake-gui) + start %CMAKEGUI_NAME% "%CONFIGURE_PATH%" + ) + cd "%CURRENT_PATH%" + goto :RETURN + +:: Display help message +:print_help + echo configure [-h ^| -c OPTS] + echo -h Display this message + echo -c Command line version of CMake + echo. + echo OPTS Options to pass to CMake command line + echo. + echo Small wrapper around cmake and cmake-gui for + echo easy build system configuration and generation. + echo. + echo For GUI and command line use. + goto :EXIT + +:RETURN +:EXIT diff --git a/arduino-cmake/example/CMakeLists.txt b/arduino-cmake/example/CMakeLists.txt new file mode 100644 index 0000000..3c89c12 --- /dev/null +++ b/arduino-cmake/example/CMakeLists.txt @@ -0,0 +1,24 @@ +#=============================================================================# +# Author: QueezyTheGreat # +# Date: 26.04.2011 # +# # +# Description: wire_master_reader firmware exmaple # +# # +#=============================================================================# + + +#====================================================================# +# Settings # +#====================================================================# +set(FIRMWARE_NAME wire_reader) + +set(${FIRMWARE_NAME}_BOARD uno) # Arduino Target board +set(${FIRMWARE_NAME}_SRCS wire_master_reader.cpp) # Firmware sources + +set(${FIRMWARE_NAME}_PORT /dev/ttyACM0) # Serial upload port + + +#====================================================================# +# Target generation # +#====================================================================# +generate_arduino_firmware(${FIRMWARE_NAME}) diff --git a/arduino-cmake/example/wire_master_reader.cpp b/arduino-cmake/example/wire_master_reader.cpp new file mode 100644 index 0000000..9c755db --- /dev/null +++ b/arduino-cmake/example/wire_master_reader.cpp @@ -0,0 +1,32 @@ +// Wire Master Reader +// by Nicholas Zambetti + +// Demonstrates use of the Wire library +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender" example for use with this + +// Created 29 March 2006 + +// This example code is in the public domain. + +#include +#include + +void setup() +{ + Wire.begin(); // join i2c bus (address optional for master) + Serial.begin(9600); // start serial for output +} + +void loop() +{ + Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 + + while(Wire.available()) // slave may send less than requested + { + char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + + delay(500); +} -- cgit v1.2.3