diff --git a/.gitignore b/.gitignore index 378eac2..3128818 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ -build +build/ +.idea/ + +*.DS_Store \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 755e3d2..4f349ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,12 @@ # Description: Arduino CMake example # # # #=============================================================================# + +# this line is needed only if you use boards with selectable cpu (like mega, pro etc) +# and this line should go before call to "cmake/ArduinoToolchain.cmake" +# this is durty hack and should be fixed somewhen, because it should go to +# particular cmake subdirectory + set(CMAKE_TOOLCHAIN_FILE cmake/ArduinoToolchain.cmake) # Arduino Toolchain @@ -12,9 +18,15 @@ cmake_minimum_required(VERSION 2.8) #====================================================================# # Setup Project # #====================================================================# -project(ArduinoExample C CXX) +project(ArduinoExample) + +#print_board_list() +#print_programmer_list() -print_board_list() -print_programmer_list() +# add libraries to project +link_directories(${ARDUINO_SDK}/libraries) -add_subdirectory(example) #add the example directory into build +# add the project directory into build +add_subdirectory(example) +#add_subdirectory(example_esp32) +#add_subdirectory(example_ap) diff --git a/README.md b/README.md new file mode 100644 index 0000000..9806524 --- /dev/null +++ b/README.md @@ -0,0 +1,174 @@ +Arduino Cmake Example Project +=============================== + +This is the Cmake project settings for the Arduino platform. +You can use this project as an example to develop C++ programs +in JetBrains CLion IDE for Arduino and using toolchain from +Arduino IDE 1.6+. + +This project correctly works and tested in Windows with MinGW, +but it should work in linux and mac with standard cmake/make pakages. + +Original cmake project is licensed with +Mozilla Public License, v. 2.0 http://mozilla.org/MPL/2.0/ + +Readme from the original project is moved to /README.original.rst. +You can find all the authors and contributors there. + +Usefull links +------------------------------- +Original project URI: https://github.com/queezythegreat/arduino-cmake + +Current project is it's fork with patches from pull requests +https://github.com/queezythegreat/arduino-cmake/pulls +and with my patches that fixes some major and minor bugs +as long as adds other new features. + +Some examples are taken from this article http://habrahabr.ru/post/247017/ + +Differencies between this project and original one +------------------------------- +1. Added patch "Adding support for SDK 1.5" + https://github.com/queezythegreat/arduino-cmake/pull/104 + Added support for Arduino IDE 1.5-1.6+. + +2. Added patch "fixed bug in find_file method" + https://github.com/queezythegreat/arduino-cmake/pull/109 + Now cmake project does not search for arduino toolchain + files in standard windows paths. + +3. Added patch "Fix CMP0038 warnings on CMake >= 3.0" + https://github.com/queezythegreat/arduino-cmake/pull/143 + Removed warnings. + +4. Fixed windows paths to avr-size command. Now we can see the size of the compiled arduino program. + +5. Fixed parsing of the boards.txt settings that are used for compilation of the boards (that differs from arduino mega). + +6. All compilation settings are taken from original Arduino IDE. + But i dont think i've done it the best way so you can try do better if you want. + +7. Removed any differences between all build flavors (debug, release, etc). This is descructive difference between this fork + and original project, that is why you should not try to merge this fork into original project. + I make it because i dont have enough experience in finding the best compile options for these different build types. + So now it uses original Arduino IDE options. + +8. Original Readme is saved in README.original.rst + +Installing CLion + Arduino IDE + MinGW +----------------------------------- +1. Install MinGW (needed for CLion, includes make, g++, cpp) + +This is needed only for windows. In different OS'es you should skip this and continue to +the next - "2. Install Arduino IDE". + +1.1. Installing MinGW + http://sourceforge.net/projects/mingw/files/Installer/ + Tested on version mingw-get-0.6.2-mingw32-beta-20131004-1 + +1.2. Run MinGW Installation Manager + +1.3. Choose packages from "Basic Setup" + - mingw-developer-toolkit + - mingw32-base + - mingw32-gcc-g++ + - msys-base +and push "Apply Changes" + +2. Install Arduino IDE 1.6 (needed for building the project, includes avr toolchain) + http://www.arduino.cc/en/Main/OldSoftwareReleases + Tested on version 1.6.3 + +3. Install and setup JetBrains CLion 1.0 + +3.1. Install JetBrains CLion 1.0 + https://www.jetbrains.com/clion/ + Test on version 1.0 + +3.2. Run CLion + +3.3. Setup toolchain + Menu settings "File" -> "Settings" + Choose "Build, Execudion, Deployment" -> "Toolchain" + Setup + - Env: MinGW "c:\mingw" + - cmake: "bundled cmake" + +MinGW option only exists in windows. + +All is done, you can open project in CLion. + +How to move you existing project from Arduino IDE +----------------------------------- + +For example, you have your own project named Robot with the following files +- /Robot.ino +- /Chassis.cpp +- /Chassis.h +that already works in Arduino IDE, and you want to move it to CLion IDE. + +1. Make new project with name arduino-cmake-robot +Clone this repository: + git clone {THIS_REPO_URI} arduino-cmake-robot + +We do not need origin any more, we will use our own project repository. +Remove origin: + git remote rm origin + +2. Copy our existing project files Robot +Make folder /robot in the root of new project. +Copy files into this folder. Now we have 3 new files in new project + - /robot/Robot.ino + - /robot/Chassis.cpp + - /robot/Chassis.h + +3. Rename Robot.ino into robot.cpp +Now our new files and folders structure is like the following: + - /robot/robot.cpp + - /robot/Chassis.cpp + - /robot/Chassis.h + +4. Add standard Arduino library +Add the following line before the very first line of the /robot/robot.cpp file + #include "Arduino.h" + +5. Make file with cmake build settings +Copy /example/CMakeLists.txt into /robot/CMakeLists.txt + +6. Setup CMakeLists.txt for "robot" project (/robot/CMakeLists.txt) +Set up the name of the project + set(PROJECT_NAME robot) + +Set up the target platform. +Example 1. For Arduino Pro (Arduino Pro Mini) it should look like this + set(${PROJECT_NAME}_BOARD pro) +Example 2. For Arduino UNO + set(${PROJECT_NAME}_BOARD uno) + +Set up the name of the file, that was previously with INO extension + set(${PROJECT_NAME}_SRCS robot.cpp) +Set up target COM port, which is connect to the board + set(${PROJECT_NAME}_PORT COM3) + +7. Set up root folder CMakeLists.txt (/CMakeLists.txt) +Choose correct CPU option for the board. +This name is located in the file + C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt +This is windows path. For other OS'es it will look similar to +"hardware\arduino\avr\boards.txt". + +Example 1. For Arduino Pro 16Mhz 5V ATmega 328 +we can file the line "pro.menu.cpu.16MHzatmega328=ATmega328 (5V, 16 MHz)" +and than take correct CPU ID "16MHzatmega328", but not the value "ATmega328 (5V, 16 MHz)" + set(ARDUINO_CPU 16MHzatmega328) +Example 2. For Arduino UNO where is no need to define anything, just comment out the CPU ID line, +because Arduino UNO does not have different CPU options + # (commented) set(ARDUINO_CPU 16MHzatmega328) + +Add project folder, change "example" to "robot" + # (commented) add_subdirectory(example) + add_subdirectory(robot) + +8. Open project in CLion IDE and choose build option "robot" (for compilation only) +or "robot_upload" (for compilation and upload). +Build project (CTRL+F9). After that project starts to build and upload to the Arduino board. diff --git a/README.rst b/README.original.rst similarity index 99% rename from README.rst rename to README.original.rst index 4675f03..18aeb8a 100644 --- a/README.rst +++ b/README.original.rst @@ -744,6 +744,10 @@ The following options control how **Arduino CMake** is configured: +---------------------------------+-----------------------------------------------------+ | **ARDUINO_DEFAULT_BOARD** | Default Arduino Board ID, when not specified. | +---------------------------------+-----------------------------------------------------+ +| **ARDUINO_CPU** | Selected CPU from Arduino 1.5 menu boards. For mega | +| | board, for example, you have to set atmega2560 | +| | before including ARDUINO ToolChain | ++---------------------------------+-----------------------------------------------------+ | **ARDUINO_DEFAULT_PORT** | Default Arduino port, when not specified. | +---------------------------------+-----------------------------------------------------+ | **ARDUINO_DEFAULT_SERIAL** | Default Arduino Serial command, when not specified. | diff --git a/README.ru.md b/README.ru.md new file mode 100644 index 0000000..1c6f06e --- /dev/null +++ b/README.ru.md @@ -0,0 +1,178 @@ +Arduino Cmake Example Project +=============================== + +English readme: /README.english.txt + +Здесь находится проект с примером настроек cmake для работы с arduino. +Корректно загружается и работает в CLion, используя toolchain +из Arduino IDE 1.6+. + +Протестированные настройки работают на Windows и MinGW, но всё так же +должно работать на linux и mac со стандартными пакетами cmake/make. + +Оригинальный код проекта распространяется под лицензией +Mozilla Public License, v. 2.0 http://mozilla.org/MPL/2.0/ + +Список авторов и контрибьюторов оригинального проекта +описан в /README.original.rst + +Полезные ссылки +------------------------------- +Оригинальный проект находится по адресу +https://github.com/queezythegreat/arduino-cmake + +В текущем же репозитории находится его копия с наложенными патчами, +взятыми из pull requests отсюда +https://github.com/queezythegreat/arduino-cmake/pulls +и написанными мной патчами, закрывающими ряд багов, +и добавляющими ряд фич. + +Некоторые примеры настроек проекта для CLion взяты из статьи +http://habrahabr.ru/post/247017/ + +Изменения по сравнению с оригиналом +------------------------------- +1. Наложен патч "Adding support for SDK 1.5" + https://github.com/queezythegreat/arduino-cmake/pull/104 + Добавлена поддержка Arduino 1.5-1.6. + +2. Наложен патч "fixed bug in find_file method" + https://github.com/queezythegreat/arduino-cmake/pull/109 + Стандартные пути окружения windows не учитываются при поиске Arduino IDE. + +3. Наложен патч "Fix CMP0038 warnings on CMake >= 3.0" + https://github.com/queezythegreat/arduino-cmake/pull/143 + +4. Исправлены пути windows для того, чтобы avr-size писал размер + скомпиллированного бинарника при сборке. + +5. Исправлены пути, по которым ищутся настройки в boards.txt для остальных + плат кроме mega, так как заливка скетча работала только с mega, так как + неверно определялся программатор. + +6. Все опции сборки взяты по максимому из оригинальной IDE, и скорее всего + сделано не оптимально и требует более детального анализа. + +7. Убрал различия между всеми видами сборки, и это деструктивное изменение, + которое не нужно мёрджить с основным проектом. Я так сделал потому-что + не стал разбираться как лучше всего выбрать опции и для каких режимов (debug, release). + +8. Оригинальный Readme сохранён в README.original.rst + +Установка CLion + Arduino IDE + MinGW +----------------------------------- +1. Установить MinGW (нужно для CLion, добавляет make, g++, cpp) + +Этот пункт нужен только для установки на windows. Под другим OS его нужно пропустить +и переходить к следующему пункту - "2. Установка Arduino IDE". + +1.1. Установить MinGW + http://sourceforge.net/projects/mingw/files/Installer/ + Тестировалось на версии mingw-get-0.6.2-mingw32-beta-20131004-1 + +1.2. Запустить MinGW Installation Manager + +1.3. Выбрать пакеты из "Basic Setup" + - mingw-developer-toolkit + - mingw32-base + - mingw32-gcc-g++ + - msys-base +и нажать "Apply Changes" + +2. Установить Arduino IDE 1.6 (нужен для сборки проекта, включает avr toolchain) + http://www.arduino.cc/en/Main/OldSoftwareReleases + Тестировалось на версии 1.6.3 + +3. Установить и настроить JetBrains CLion 1.0 + +3.1. Установить JetBrains CLion 1.0 + https://www.jetbrains.com/clion/ + Тестировалось на версии 1.0 + +3.2. Запустить CLion + +3.3. Настроить toolchain + Меню настроек "File" -> "Settings" + Выбрать "Build, Execudion, Deployment" -> "Toolchain" + Дальше сконфигурировать + - Env: MinGW "c:\mingw" + - cmake: "bundled cmake" + +Пункт MinGW доступен только в windows, поэтому для других OS меню с настройками +будет проще, и скорее всего сдесь вообще ничего не придётся менять, и всё будет +работать из коробки. + +После этого cmake должен правильно собирать проект. +Всё, что для этого потребуется - это открыть проект в CLion. + +Портирование вашего проекта из Arduino IDE +----------------------------------- +Предположим, у вас есть свой проект, с названием Robot и файлами +- /Robot.ino +- /Chassis.cpp +- /Chassis.h +который уже работает в Arduino IDE, и вы хотите его перенести в CLion. + +1. Создаём новый проект с названием arduino-cmake-robot + git clone {THIS_REPO} arduino-cmake-robot +Нам больше не потребуется связь с оригинальным проектом, +мы в дальнейшем будем работать со своим репозиторием. + git remote rm origin + +2. Копируем файлы проекта Robot +Создаём папку /robot в корне нового проекта. +Копируем файлы в эту папку, теперь у нас три новых файла в новом проекте + - /robot/Robot.ino + - /robot/Chassis.cpp + - /robot/Chassis.h + +3. Переименовываем Robot.ino в robot.cpp +Теперь у нас старые файлы в новом проекте с такими названиями + - /robot/robot.cpp + - /robot/Chassis.cpp + - /robot/Chassis.h + +4. Подключаем стандартную библиотеку Arduino +Добавляем в /robot/robot.cpp первой строчкой + #include "Arduino.h" + +5. Создаём файл с настройками сборки проекта +Копируем /example/CMakeLists.txt в /robot/CMakeLists.txt + +6. Настраиваем CMakeLists.txt проекта robot (/robot/CMakeLists.txt) +Указываем название проекта + set(PROJECT_NAME robot) + +Указываем название платформы, под которую собираем. +Пример 1. Для примера это Arduino Pro (Arduino Pro Mini) + set(${PROJECT_NAME}_BOARD pro) +Пример 2. Для Arduino UNO это бы выглядело так + set(${PROJECT_NAME}_BOARD uno) + +Указываем название файла, который раньше был с расширением INO + set(${PROJECT_NAME}_SRCS robot.cpp) +Указываем нужный COM порт, к которому подключается плата + set(${PROJECT_NAME}_PORT COM3) + +7. Настраиваем корневой CMakeLists.txt (/CMakeLists.txt) +Выбираем правильный вариант процессора для платы +Это название берётся из файла + C:\Program Files (x86)\Arduino\hardware\arduino\avr\boards.txt +Этот путь для windows, а для других платформ будет другой путь, +но похожий на "hardware\arduino\avr\boards.txt". + +Пример 1. Для Arduino Pro 16Mhz 5V ATmega 328 +нужно смотреть строчку "pro.menu.cpu.16MHzatmega328=ATmega328 (5V, 16 MHz)" +и брать соответствующий идентификатор "16MHzatmega328", а не название "ATmega328 (5V, 16 MHz)" + set(ARDUINO_CPU 16MHzatmega328) +Пример 2. Для Arduino UNO нужно ничего не указывать, просто закомментировать строчку, +потому что для UNO нет выбора процессоров + # (закомментировали) set(ARDUINO_CPU 16MHzatmega328) + +Подключаем нужную папку, меняем example на robot + # (закомментировали) add_subdirectory(example) + add_subdirectory(robot) + +8. Открываем проект в CLion и выбираем опцию сборки robot (для компилляции) +или robot_upload (для компилляции и закрузки). +Собираем проект (CTRL+F9). Проект загружается на плату. diff --git a/cmake/ArduinoToolchain.cmake b/cmake/ArduinoToolchain.cmake index f320898..8fd0393 100644 --- a/cmake/ArduinoToolchain.cmake +++ b/cmake/ArduinoToolchain.cmake @@ -8,8 +8,12 @@ #=============================================================================# set(CMAKE_SYSTEM_NAME Arduino) -set(CMAKE_C_COMPILER avr-gcc) -set(CMAKE_CXX_COMPILER avr-g++) +if (NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER avr-gcc) +endif() +if (NOT DEFINED CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER avr-g++) +endif() # Add current directory to CMake Module path automatically if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/Platform/Arduino.cmake) @@ -36,6 +40,10 @@ endif() #=============================================================================# # Detect Arduino SDK # #=============================================================================# +if(NOT DEFINED ARDUINO_SDK_PATH AND DEFINED ENV{ARDUINO_SDK_PATH}) + set(ARDUINO_SDK_PATH $ENV{ARDUINO_SDK_PATH}) +endif() + if(NOT ARDUINO_SDK_PATH) set(ARDUINO_PATHS) @@ -70,6 +78,7 @@ find_path(ARDUINO_SDK_PATH NAMES lib/version.txt PATH_SUFFIXES share/arduino Arduino.app/Contents/Resources/Java/ + Arduino.app/Contents/Java/ ${ARDUINO_PATHS} HINTS ${SDK_PATH_HINTS} DOC "Arduino SDK path.") diff --git a/cmake/Platform/Arduino.cmake b/cmake/Platform/Arduino.cmake index 042a3c1..478a34f 100644 --- a/cmake/Platform/Arduino.cmake +++ b/cmake/Platform/Arduino.cmake @@ -22,7 +22,7 @@ # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] # SKETCH # Arduino sketch [must have SRCS or SKETCH] # SRCS # Sources [must have SRCS or SKETCH] -# HDRS # Headers +# HDRS # Headers # LIBS # Libraries to link # ARDLIBS # Arduino libraries to link (Wire, Servo, SPI, etc) # PORT # Serial port (enables upload support) @@ -33,10 +33,10 @@ # MANUAL # (Advanced) Only use AVR Libc/Includes # # Here is a short example for a target named test: -# +# # generate_arduino_firmware( # NAME test -# SRCS test.cpp +# SRCS test.cpp # test2.cpp # HDRS test.h test2.h # BOARD uno) @@ -71,7 +71,7 @@ # name # The name of the firmware target [REQUIRED] # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] # SRCS # Sources [REQUIRED] -# HDRS # Headers +# HDRS # Headers # LIBS # Libraries to link # PORT # Serial port (enables upload support) # SERIAL # Serial command for serial target @@ -79,10 +79,10 @@ # AFLAGS # Avrdude flags for target # # Here is a short example for a target named test: -# +# # generate_avr_firmware( # NAME test -# SRCS test.cpp +# SRCS test.cpp # test2.cpp # HDRS test.h test2.h # BOARD uno) @@ -113,16 +113,16 @@ # name # The name of the firmware target [REQUIRED] # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] # SRCS # Sources [REQUIRED] -# HDRS # Headers +# HDRS # Headers # LIBS # Libraries to link # NO_AUTOLIBS # Disables Arduino library detection # MANUAL # (Advanced) Only use AVR Libc/Includes # # Here is a short example for a target named test: -# +# # generate_arduino_library( # NAME test -# SRCS test.cpp +# SRCS test.cpp # test2.cpp # HDRS test.h test2.h # BOARD uno) @@ -152,14 +152,14 @@ # name # The name of the firmware target [REQUIRED] # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] # SRCS # Sources [REQUIRED] -# HDRS # Headers +# HDRS # Headers # LIBS # Libraries to link # # Here is a short example for a target named test: -# +# # generate_avr_library( # NAME test -# SRCS test.cpp +# SRCS test.cpp # test2.cpp # HDRS test.h test2.h # BOARD uno) @@ -245,7 +245,7 @@ # |-- variants/ # |-- boards.txt # `-- programmers.txt -# +# # The board.txt describes the target boards and bootloaders. While # programmers.txt the programmer defintions. # @@ -285,13 +285,13 @@ cmake_minimum_required(VERSION 2.8.5) include(CMakeParseArguments) - +find_package(PythonInterp REQUIRED) #=============================================================================# -# User Functions +# User Functions #=============================================================================# #=============================================================================# @@ -373,12 +373,15 @@ function(GENERATE_ARDUINO_LIBRARY INPUT_NAME) set(INPUT_MANUAL FALSE) endif() required_variables(VARS INPUT_SRCS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") - + set(ALL_LIBS) set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) if(NOT INPUT_MANUAL) setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + set(BOARD_CORE ${${BOARD_ID}.build.core}) + set(BOARD_CORE_PATH ${${BOARD_CORE}.path}) + include_directories( ${BOARD_CORE_PATH}) endif() find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "") @@ -415,13 +418,13 @@ function(GENERATE_AVR_LIBRARY INPUT_NAME) "BOARD" # One Value Keywords "SRCS;HDRS;LIBS" # Multi Value Keywords ${ARGN}) - + if(NOT INPUT_BOARD) set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) - endif() - + endif() + required_variables(VARS INPUT_SRCS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") - + if(INPUT_HDRS) set( INPUT_HDRS "SRCS ${INPUT_HDRS}" ) endif() @@ -437,14 +440,14 @@ function(GENERATE_AVR_LIBRARY INPUT_NAME) endif() - generate_arduino_library( ${INPUT_NAME} + generate_arduino_library( ${INPUT_NAME} NO_AUTOLIBS MANUAL BOARD ${INPUT_BOARD} SRCS ${INPUT_SRCS} ${INPUT_HDRS} ${INPUT_LIBS} ) - + endfunction() #=============================================================================# @@ -455,8 +458,8 @@ function(GENERATE_ARDUINO_FIRMWARE INPUT_NAME) message(STATUS "Generating ${INPUT_NAME}") parse_generator_arguments(${INPUT_NAME} INPUT "NO_AUTOLIBS;MANUAL" # Options - "BOARD;PORT;SKETCH;PROGRAMMER" # One Value Keywords - "SERIAL;SRCS;HDRS;LIBS;ARDLIBS;AFLAGS" # Multi Value Keywords + "BOARD;PORT;SKETCH;PROGRAMMER;CPU" # One Value Keywords + "SERIAL;SRCS;HDRS;LIBS;ARDLIBS;ARDLIBS_PATH;AFLAGS" # Multi Value Keywords ${ARGN}) if(NOT INPUT_BOARD) @@ -468,22 +471,50 @@ function(GENERATE_ARDUINO_FIRMWARE INPUT_NAME) if(NOT INPUT_SERIAL) set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) endif() - if(NOT INPUT_PROGRAMMER) - set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) + if(NOT DEFINED INPUT_PROGRAMMER) + if(DEFINED ${INPUT_BOARD}.upload.tool) + set(INPUT_PROGRAMMER ${${INPUT_BOARD}.upload.tool}) + else() + set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) + endif() endif() if(NOT INPUT_MANUAL) set(INPUT_MANUAL FALSE) endif() required_variables(VARS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") + if(INPUT_CPU) + set(ARDUINO_CPUMENU ".menu.cpu.${INPUT_CPU}") + endif(INPUT_CPU) + + set(PLATFORM ${${INPUT_BOARD}.PLATFORM}) + + set(ALL_LIBS) set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) set(LIB_DEP_INCLUDES) + # set predefined variable values + + set(${INPUT_NAME}.build.path ${CMAKE_CURRENT_BINARY_DIR} CACHE INTERNAL "") + set(${INPUT_NAME}.build.project_name ${INPUT_NAME} CACHE INTERNAL "") + + string(TOUPPER "${PLATFORM}" PLATFORM_UPPER) + set(${INPUT_BOARD}.build.arch "${PLATFORM_UPPER}" CACHE INTERNAL "") + + if(NOT INPUT_MANUAL) setup_arduino_core(CORE_LIB ${INPUT_BOARD}) + + set(BOARD_CORE ${${INPUT_BOARD}.build.core}) + set(BOARD_CORE_PATH ${${BOARD_CORE}.path}) + include_directories( ${BOARD_CORE_PATH}) endif() - + + # Set include dir for variant + set(BOARD_VARIANT ${${INPUT_BOARD}.build.variant}) + include_directories( ${${BOARD_VARIANT}.path}) + if(NOT "${INPUT_SKETCH}" STREQUAL "") get_filename_component(INPUT_SKETCH "${INPUT_SKETCH}" ABSOLUTE) setup_arduino_sketch(${INPUT_NAME} ${INPUT_SKETCH} ALL_SRCS) @@ -497,28 +528,27 @@ function(GENERATE_ARDUINO_FIRMWARE INPUT_NAME) required_variables(VARS ALL_SRCS MSG "must define SRCS or SKETCH for target ${INPUT_NAME}") - find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "${INPUT_ARDLIBS}") + find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "${INPUT_ARDLIBS}" "${INPUT_ARDLIBS_PATH}") foreach(LIB_DEP ${TARGET_LIBS}) arduino_debug_msg("Arduino Library: ${LIB_DEP}") - set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${LIB_DEP}\"") + set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${LIB_DEP}\" -I\"${LIB_DEP}/src\"") endforeach() if(NOT INPUT_NO_AUTOLIBS) - setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${INPUT_ARDLIBS}" "${LIB_DEP_INCLUDES}" "") + setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${INPUT_ARDLIBS}" "${LIB_DEP_INCLUDES}" "" "${INPUT_ARDLIBS_PATH}") foreach(LIB_INCLUDES ${ALL_LIBS_INCLUDES}) arduino_debug_msg("Arduino Library Includes: ${LIB_INCLUDES}") set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} ${LIB_INCLUDES}") endforeach() endif() - - list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) + list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) setup_arduino_target(${INPUT_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "" "${INPUT_MANUAL}") if(INPUT_PORT) setup_arduino_upload(${INPUT_BOARD} ${INPUT_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "${INPUT_AFLAGS}") endif() - + if(INPUT_SERIAL) setup_serial_target(${INPUT_NAME} "${INPUT_SERIAL}" "${INPUT_PORT}") endif() @@ -537,7 +567,7 @@ function(GENERATE_AVR_FIRMWARE INPUT_NAME) "BOARD;PORT;PROGRAMMER" # One Value Keywords "SERIAL;SRCS;HDRS;LIBS;AFLAGS" # Multi Value Keywords ${ARGN}) - + if(NOT INPUT_BOARD) set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) endif() @@ -550,7 +580,7 @@ function(GENERATE_AVR_FIRMWARE INPUT_NAME) if(NOT INPUT_PROGRAMMER) set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) endif() - + required_variables(VARS INPUT_BOARD INPUT_SRCS MSG "must define for target ${INPUT_NAME}") if(INPUT_HDRS) @@ -563,7 +593,7 @@ function(GENERATE_AVR_FIRMWARE INPUT_NAME) list(INSERT INPUT_AFLAGS 0 "AFLAGS") endif() - generate_arduino_firmware( ${INPUT_NAME} + generate_arduino_firmware( ${INPUT_NAME} NO_AUTOLIBS MANUAL BOARD ${INPUT_BOARD} @@ -574,7 +604,7 @@ function(GENERATE_AVR_FIRMWARE INPUT_NAME) ${INPUT_HDRS} ${INPUT_LIBS} ${INPUT_AFLAGS} ) - + endfunction() #=============================================================================# @@ -626,13 +656,13 @@ function(GENERATE_ARDUINO_EXAMPLE INPUT_NAME) setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "" "${LIB_DEP_INCLUDES}" "") list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) - + setup_arduino_target(${INPUT_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "" FALSE) if(INPUT_PORT) setup_arduino_upload(${INPUT_BOARD} ${INPUT_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "${INPUT_AFLAGS}") endif() - + if(INPUT_SERIAL) setup_serial_target(${INPUT_NAME} "${INPUT_SERIAL}" "${INPUT_PORT}") endif() @@ -644,47 +674,96 @@ endfunction() #=============================================================================# function(REGISTER_HARDWARE_PLATFORM PLATFORM_PATH) string(REGEX REPLACE "/$" "" PLATFORM_PATH ${PLATFORM_PATH}) - GET_FILENAME_COMPONENT(PLATFORM ${PLATFORM_PATH} NAME) + if(ARDUINO_SDK_VERSION VERSION_LESS 1.5) + SET(PLATFORM "AVR") + else() + GET_FILENAME_COMPONENT(PLATFORM ${PLATFORM_PATH} NAME) + string(TOUPPER ${PLATFORM} PLATFORM) + endif() if(PLATFORM) - string(TOUPPER ${PLATFORM} PLATFORM) list(FIND ARDUINO_PLATFORMS ${PLATFORM} platform_exists) if (platform_exists EQUAL -1) set(${PLATFORM}_PLATFORM_PATH ${PLATFORM_PATH} CACHE INTERNAL "The path to ${PLATFORM}") set(ARDUINO_PLATFORMS ${ARDUINO_PLATFORMS} ${PLATFORM} CACHE INTERNAL "A list of registered platforms") + + # Set some predefined variable values as defined in + # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification + + set(${PLATFORM}.runtime.platform.path ${PLATFORM_PATH} + CACHE INTERNAL "${PLATFORM} platform path") + + if(ARDUINO_SDK_VERSION VERSION_LESS 1.5) + set(${PLATFORM}.runtime.hardware.path ${PLATFORM_PATH} + CACHE INTERNAL "${PLATFORM} hardware path") + else() + GET_FILENAME_COMPONENT(HARDWARE_PATH ${PLATFORM_PATH} DIRECTORY) + set(${PLATFORM}.runtime.hardware.path ${HARDWARE_PATH} + CACHE INTERNAL "${PLATFORM} hardware path") + endif() + + + find_file(${PLATFORM}_CORES_PATH NAMES cores PATHS ${PLATFORM_PATH} - DOC "Path to directory containing the Arduino core sources.") + DOC "Path to directory containing the Arduino core sources." + NO_SYSTEM_ENVIRONMENT_PATH) find_file(${PLATFORM}_VARIANTS_PATH NAMES variants PATHS ${PLATFORM_PATH} - DOC "Path to directory containing the Arduino variant sources.") + DOC "Path to directory containing the Arduino variant sources." + NO_SYSTEM_ENVIRONMENT_PATH) find_file(${PLATFORM}_BOOTLOADERS_PATH NAMES bootloaders PATHS ${PLATFORM_PATH} - DOC "Path to directory containing the Arduino bootloader images and sources.") + DOC "Path to directory containing the Arduino bootloader images and sources." + NO_SYSTEM_ENVIRONMENT_PATH) + + find_file(${PLATFORM}_LIBRARIES_PATH + NAMES libraries + PATHS ${PLATFORM_PATH} + DOC "Path to directory containing the Arduino hardware libraries sources." + NO_SYSTEM_ENVIRONMENT_PATH) find_file(${PLATFORM}_PROGRAMMERS_PATH NAMES programmers.txt PATHS ${PLATFORM_PATH} - DOC "Path to Arduino programmers definition file.") + DOC "Path to Arduino programmers definition file." + NO_SYSTEM_ENVIRONMENT_PATH) find_file(${PLATFORM}_BOARDS_PATH NAMES boards.txt PATHS ${PLATFORM_PATH} - DOC "Path to Arduino boards definition file.") + DOC "Path to Arduino boards definition file." + NO_SYSTEM_ENVIRONMENT_PATH) + + find_file(${PLATFORM}_PLATFORM_PATH + NAMES platform.txt + PATHS ${PLATFORM_PATH} + DOC "Path to Arduino platform definition file." + NO_SYSTEM_ENVIRONMENT_PATH) if(${PLATFORM}_BOARDS_PATH) - load_arduino_style_settings(${PLATFORM}_BOARDS "${PLATFORM_PATH}/boards.txt") + load_arduino_style_settings(${PLATFORM}_BOARDS "${PLATFORM_PATH}/boards.txt" "") + + # store the platform to which the board belongs + foreach(board IN LISTS ${PLATFORM}_BOARDS) + set(${board}.PLATFORM ${PLATFORM} CACHE INTERNAL "") + endforeach() + endif() if(${PLATFORM}_PROGRAMMERS_PATH) - load_arduino_style_settings(${PLATFORM}_PROGRAMMERS "${ARDUINO_PROGRAMMERS_PATH}") + load_arduino_style_settings(${PLATFORM}_PROGRAMMERS "${PLATFORM_PATH}/programmers.txt" "") + endif() + + if(${PLATFORM}_PLATFORM_PATH) + load_arduino_style_settings(${PLATFORM}_PLATFORM "${PLATFORM_PATH}/platform.txt" ${PLATFORM}) endif() if(${PLATFORM}_VARIANTS_PATH) @@ -708,15 +787,40 @@ function(REGISTER_HARDWARE_PLATFORM PLATFORM_PATH) endif() endforeach() endif() + endif() endif() endfunction() #=============================================================================# -# Internal Functions +# Internal Functions #=============================================================================# + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# subdirlist(RESULT DIR) +# +# RESULT - Variable name of list containing all the sub directories +# DIR - Parent directory where to iterate over +# +# Gets a list of all the direct subdirectories of the given directory +# see https://stackoverflow.com/a/7788165/869402 +# +#=============================================================================# +MACRO(SUBDIRLIST result curdir) + FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) + SET(dirlist "") + FOREACH(child ${children}) + IF(IS_DIRECTORY ${curdir}/${child}) + LIST(APPEND dirlist ${child}) + ENDIF() + ENDFOREACH() + SET(${result} ${dirlist}) +ENDMACRO() + #=============================================================================# # [PRIVATE/INTERNAL] # @@ -772,62 +876,65 @@ endfunction() #=============================================================================# # [PRIVATE/INTERNAL] # -# get_arduino_flags(COMPILE_FLAGS LINK_FLAGS BOARD_ID MANUAL) +# get_recipe_flags(COMPILE_CMD_VAR COMPILE_FLAGS_VAR BOARD_ID RECIPE_TYPE) # -# COMPILE_FLAGS_VAR -Variable holding compiler flags -# LINK_FLAGS_VAR - Variable holding linker flags +# COMPILE_CMD_VAR - Command for the given recipe (i.e. the first part of the string) +# COMPILE_FLAGS_VAR - compile flags for the recipe # BOARD_ID - The board id name -# MANUAL - (Advanced) Only use AVR Libc/Includes +# RECIPE_TYPE - name of the recipe, e.g. [recipe.c.o, recipe.cpp.o, recipe.ar, recipe.objcopy.eep, ...] # -# Configures the the build settings for the specified Arduino Board. +# Gets the recipe configuration for the given recipe type # #=============================================================================# -function(get_arduino_flags COMPILE_FLAGS_VAR LINK_FLAGS_VAR BOARD_ID MANUAL) - - set(BOARD_CORE ${${BOARD_ID}.build.core}) - 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 "") - if(CMAKE_MATCH_1 GREATER 0) - set(ARDUINO_VERSION_DEFINE "${CMAKE_MATCH_1}") - endif() - 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() +function(get_recipe_flags COMPILE_CMD_VAR COMPILE_FLAGS_VAR BOARD_ID RECIPE_TYPE) + + set(PLATFORM ${${BOARD_ID}.PLATFORM}) + + set(RECIPE_VAR_NAME "${PLATFORM}.${RECIPE_TYPE}.pattern") + + if(NOT DEFINED ${RECIPE_VAR_NAME}) + MESSAGE(FATAL_ERROR "Value for ${RECIPE_VAR_NAME} not defined") + endif() + + set(RECIPE_PATTERN ${${RECIPE_VAR_NAME}}) + + # Split recipe into command part (first part in quotes or up to first space) and flags part + if("${RECIPE_PATTERN}" MATCHES "^\"([^\"]+)\"(.*)\$|^([^ ]+) (.*)\$") + if(CMAKE_MATCH_1) + SET(RECPIE_CMD ${CMAKE_MATCH_1}) + SET(RECPIE_FLAGS ${CMAKE_MATCH_2}) else() - message("Invalid Arduino SDK Version (${ARDUINO_SDK_VERSION})") + SET(RECPIE_CMD ${CMAKE_MATCH_3}) + SET(RECPIE_FLAGS ${CMAKE_MATCH_4}) endif() - # output - set(COMPILE_FLAGS "-DF_CPU=${${BOARD_ID}.build.f_cpu} -DARDUINO=${ARDUINO_VERSION_DEFINE} -mmcu=${${BOARD_ID}.build.mcu}") - if(DEFINED ${BOARD_ID}.build.vid) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -DUSB_VID=${${BOARD_ID}.build.vid}") - endif() - if(DEFINED ${BOARD_ID}.build.pid) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -DUSB_PID=${${BOARD_ID}.build.pid}") - endif() - if(NOT MANUAL) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -I\"${${BOARD_CORE}.path}\" -I\"${ARDUINO_LIBRARIES_PATH}\"") - endif() - set(LINK_FLAGS "-mmcu=${${BOARD_ID}.build.mcu}") - if(ARDUINO_SDK_VERSION VERSION_GREATER 1.0 OR ARDUINO_SDK_VERSION VERSION_EQUAL 1.0) - if(NOT MANUAL) - set(PIN_HEADER ${${${BOARD_ID}.build.variant}.path}) - if(PIN_HEADER) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -I\"${PIN_HEADER}\"") - endif() + # remove the files variables (this is a list of commonly used endings. It may be necessary to extend them + string(REPLACE "{includes} \"{source_file}\" -o \"{object_file}\"" "" RECPIE_FLAGS ${RECPIE_FLAGS}) + string(REPLACE "-o \"{build.path}/{build.project_name}.elf\" {object_files} \"{build.path}/{archive_file}\"" "" RECPIE_FLAGS ${RECPIE_FLAGS}) + string(REPLACE "\"{build.path}/arduino.ar\" \"{object_file}\"" "" RECPIE_FLAGS ${RECPIE_FLAGS}) + + # esp32 specific + string(REPLACE "\"{build.path}/arduino.ar\" \"{object_file}\"" "" RECPIE_FLAGS ${RECPIE_FLAGS}) + string(REPLACE "{object_files} \"{build.path}/arduino.ar\"" "" RECPIE_FLAGS ${RECPIE_FLAGS}) + + + if("${RECPIE_FLAGS}" MATCHES ".*{build.path}/{build.project_name}.*") + if(NOT DEFINED TARGET_PATH) + MESSAGE(FATAL_ERROR "TARGET_PATH must be defined to replace '{build.path}/{build.project_name}'") endif() + string(REPLACE "{build.path}/{build.project_name}" "${TARGET_PATH}" RECPIE_FLAGS ${RECPIE_FLAGS}) endif() - # output - set(${COMPILE_FLAGS_VAR} "${COMPILE_FLAGS}" PARENT_SCOPE) - set(${LINK_FLAGS_VAR} "${LINK_FLAGS}" PARENT_SCOPE) + string(STRIP "${RECPIE_FLAGS}" RECPIE_FLAGS) + + get_variable_value_filled(RECIPE_CMD_FULL "${RECPIE_CMD}" ${BOARD_ID} ${RECIPE_VAR_NAME}) + SET(${COMPILE_CMD_VAR} ${RECIPE_CMD_FULL} PARENT_SCOPE) + + get_variable_value_filled(RECIPE_FLAGS_FULL "${RECPIE_FLAGS}" ${BOARD_ID} ${RECIPE_VAR_NAME}) + SET(${COMPILE_FLAGS_VAR} ${RECIPE_FLAGS_FULL} PARENT_SCOPE) else() - message(FATAL_ERROR "Invalid Arduino board ID (${BOARD_ID}), aborting.") + MESSAGE(FATAL_ERROR "Recipe pattern for '${RECIPE_VAR_NAME}' in unexpected format ") endif() endfunction() @@ -853,7 +960,19 @@ function(setup_arduino_core VAR_NAME BOARD_ID) # Debian/Ubuntu fix list(REMOVE_ITEM CORE_SRCS "${BOARD_CORE_PATH}/main.cxx") add_library(${CORE_LIB_NAME} ${CORE_SRCS}) - get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} FALSE) + + get_recipe_flags(ARDUINO_COMPILE_CMD ARDUINO_COMPILE_FLAGS ${BOARD_ID} "recipe.cpp.o") + + if(NOT "${CMAKE_CXX_COMPILER}" STREQUAL "${ARDUINO_COMPILE_CMD}") + MESSAGE(WARNING "Your compiler needs to be manually set to\nCMAKE_CXX_COMPILER=\"${ARDUINO_COMPILE_CMD}\"") + endif() + + get_recipe_flags(ARDUINO_LINK_CMD ARDUINO_LINK_FLAGS ${BOARD_ID} "recipe.ar") + + if(NOT "${CMAKE_AR}" STREQUAL "${ARDUINO_LINK_CMD}") + MESSAGE(WARNING "Your archiver needs to be manually set. You then also need to update the CMAKE_RANLIB to point to the correct one.\nCMAKE_AR=\"${ARDUINO_LINK_CMD}\"") + endif() + set_target_properties(${CORE_LIB_NAME} PROPERTIES COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS}" LINK_FLAGS "${ARDUINO_LINK_FLAGS}") @@ -870,13 +989,15 @@ endfunction() # VAR_NAME - Variable name which will hold the results # SRCS - Sources that will be analized # ARDLIBS - Arduino libraries identified by name (e.g., Wire, SPI, Servo) +# PATH_OVERRIDE - Optional override search path for library to have unique path for libs with the same name. +# e.g. Arduino provides its WiFi lib, as well as ESP32 # # 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}. # -# Also adds Arduino libraries specifically names in ALIBS. We add ".h" to the +# Also adds Arduino libraries specifically names in ALIBS. We add ".h" to the # names and then process them just like the Arduino libraries found in the sources. # # A Arduino library is a folder that has the same name as the include header. @@ -891,7 +1012,9 @@ endfunction() # to be part of that Arduino library. # #=============================================================================# -function(find_arduino_libraries VAR_NAME SRCS ARDLIBS) +function(find_arduino_libraries VAR_NAME SRCS ARDLIBS PATH_OVERRIDE) + get_property(include_dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) + set(ARDUINO_LIBS ) foreach(SRC ${SRCS}) @@ -914,19 +1037,31 @@ function(find_arduino_libraries VAR_NAME SRCS ARDLIBS) list(APPEND SRC_CONTENTS "#include <${LIBNAME}.h>") endforeach() + if(PATH_OVERRIDE) + set(LIB_SEARCH_PATHS ${PATH_OVERRIDE}) + else() + set(LIB_SEARCH_PATHS ${include_dirs} ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${${ARDUINO_PLATFORM}_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries ${ARDUINO_EXTRA_LIBRARIES_PATH}) + endif() + + get_property(LIBRARY_SEARCH_PATH + DIRECTORY # Property Scope + PROPERTY LINK_DIRECTORIES) + foreach(SRC_LINE ${SRC_CONTENTS}) - if("${SRC_LINE}" MATCHES "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"]") + if("#${SRC_LINE}#" MATCHES "^#[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"]#") 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 ${ARDUINO_EXTRA_LIBRARIES_PATH}) + foreach(LIB_SEARCH_PATH ${LIB_SEARCH_PATHS}) if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}) list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) break() endif() - if(EXISTS ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1}) - list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}) + if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/src/${CMAKE_MATCH_1}) + list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) + break() + endif() + get_source_file_property(_header_generated ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1} GENERATED) + if((EXISTS ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1}) OR ${_header_generated}) + list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) break() endif() endforeach() @@ -962,12 +1097,27 @@ endfunction() set(Wire_RECURSE True) set(Ethernet_RECURSE True) set(SD_RECURSE True) -function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS) +set(Servo_RECURSE True) +set(SPI_RECURSE True) +set(SoftwareSerial_RECURSE True) +set(EEPROM_RECURSE True) +set(LiquidCrystal_RECURSE True) +set(TFT_RECURSE True) +set(WiFi_RECURSE True) +set(Robot_Control_RECURSE True) +function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS PATH_OVERRIDE) set(LIB_TARGETS) set(LIB_INCLUDES) get_filename_component(LIB_NAME ${LIB_PATH} NAME) set(TARGET_LIB_NAME ${BOARD_ID}_${LIB_NAME}) + + + if(NOT EXECUTABLE_OUTPUT_PATH) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + endif() + set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_LIB_NAME}) + if(NOT TARGET ${TARGET_LIB_NAME}) string(REGEX REPLACE ".*/" "" LIB_SHORT_NAME ${LIB_NAME}) @@ -978,18 +1128,55 @@ function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLA find_sources(LIB_SRCS ${LIB_PATH} ${${LIB_SHORT_NAME}_RECURSE}) if(LIB_SRCS) - + message(STATUS "Generating ${TARGET_LIB_NAME} for library ${LIB_NAME}") arduino_debug_msg("Generating Arduino ${LIB_NAME} library") add_library(${TARGET_LIB_NAME} STATIC ${LIB_SRCS}) + include_directories(${LIB_PATH}) + include_directories(${LIB_PATH}/src) + include_directories(${LIB_PATH}/utility) - get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} FALSE) - find_arduino_libraries(LIB_DEPS "${LIB_SRCS}" "") + get_recipe_flags(ARDUINO_COMPILE_CMD ARDUINO_COMPILE_FLAGS ${BOARD_ID} "recipe.cpp.o") + if(NOT DEFINED ARDUINO_COMPILE_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.cpp.o'") + endif() + + if(NOT "${CMAKE_CXX_COMPILER}" STREQUAL "${ARDUINO_COMPILE_CMD}") + MESSAGE(WARNING "Your compiler needs to be manually set to\nCMAKE_CXX_COMPILER=\"${ARDUINO_COMPILE_CMD}\"") + endif() + + get_recipe_flags(ARDUINO_LINK_CMD ARDUINO_LINK_FLAGS ${BOARD_ID} "recipe.c.combine") + if(NOT DEFINED ARDUINO_LINK_FLAGS) + MESSAGE(WARNING "Could not get 'recipe.c.combine'") + endif() + + + string(REPLACE "\"{build.path}/{archive_file}\"" "" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) + string(REPLACE "{object_files}" "" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) + string(REPLACE "{build.path}" "${EXECUTABLE_OUTPUT_PATH}" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) + + set_target_properties(${TARGET_NAME} PROPERTIES + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS}" + LINK_FLAGS "${ARDUINO_LINK_FLAGS}" + ARCHIVE_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + LIBRARY_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + ) + + find_arduino_libraries(LIB_DEPS "${LIB_SRCS}" "" "${PATH_OVERRIDE}") foreach(LIB_DEP ${LIB_DEPS}) - setup_arduino_library(DEP_LIB_SRCS ${BOARD_ID} ${LIB_DEP} "${COMPILE_FLAGS}" "${LINK_FLAGS}") - list(APPEND LIB_TARGETS ${DEP_LIB_SRCS}) - list(APPEND LIB_INCLUDES ${DEP_LIB_SRCS_INCLUDES}) + if(NOT DEP_LIB_SRCS STREQUAL TARGET_LIB_NAME AND DEP_LIB_SRCS) + message(STATUS "Found library ${LIB_NAME} needs ${DEP_LIB_SRCS}") + endif() + + setup_arduino_library(DEP_LIB_SRCS ${BOARD_ID} ${LIB_DEP} "${COMPILE_FLAGS}" "${LINK_FLAGS}" "${PATH_OVERRIDE}") + # Do not link to this library. DEP_LIB_SRCS will always be only one entry + # if we are looking at the same library. + if(NOT DEP_LIB_SRCS STREQUAL TARGET_LIB_NAME) + list(APPEND LIB_TARGETS ${DEP_LIB_SRCS}) + list(APPEND LIB_INCLUDES ${DEP_LIB_SRCS_INCLUDES}) + endif() endforeach() if (LIB_INCLUDES) @@ -997,11 +1184,11 @@ function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLA endif() set_target_properties(${TARGET_LIB_NAME} PROPERTIES - COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${LIB_INCLUDES} -I\"${LIB_PATH}\" -I\"${LIB_PATH}/utility\" ${COMPILE_FLAGS}" + COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${LIB_INCLUDES} -I\"${LIB_PATH}\" -I\"${LIB_PATH}/src\" -I\"${LIB_PATH}/utility\" ${COMPILE_FLAGS}" LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") - list(APPEND LIB_INCLUDES "-I\"${LIB_PATH}\" -I\"${LIB_PATH}/utility\"") + list(APPEND LIB_INCLUDES "-I\"${LIB_PATH}\" -I\"${LIB_PATH}/src\" -I\"${LIB_PATH}/utility\"") - target_link_libraries(${TARGET_LIB_NAME} ${BOARD_ID}_CORE ${LIB_TARGETS}) + target_link_libraries(${TARGET_LIB_NAME} ${BOARD_ID}_CORE) list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) endif() @@ -1030,14 +1217,14 @@ endfunction() # Finds and creates all dependency libraries based on sources. # #=============================================================================# -function(setup_arduino_libraries VAR_NAME BOARD_ID SRCS ARDLIBS COMPILE_FLAGS LINK_FLAGS) +function(setup_arduino_libraries VAR_NAME BOARD_ID SRCS ARDLIBS COMPILE_FLAGS LINK_FLAGS PATH_OVERRIDE) set(LIB_TARGETS) set(LIB_INCLUDES) - find_arduino_libraries(TARGET_LIBS "${SRCS}" ARDLIBS) + find_arduino_libraries(TARGET_LIBS "${SRCS}" "${ARDLIBS}" "${PATH_OVERRIDE}") foreach(TARGET_LIB ${TARGET_LIBS}) # Create static library instead of returning sources - setup_arduino_library(LIB_DEPS ${BOARD_ID} ${TARGET_LIB} "${COMPILE_FLAGS}" "${LINK_FLAGS}") + setup_arduino_library(LIB_DEPS ${BOARD_ID} ${TARGET_LIB} "${COMPILE_FLAGS}" "${LINK_FLAGS}" "${PATH_OVERRIDE}") list(APPEND LIB_TARGETS ${LIB_DEPS}) list(APPEND LIB_INCLUDES ${LIB_DEPS_INCLUDES}) endforeach() @@ -1065,81 +1252,117 @@ endfunction() #=============================================================================# function(setup_arduino_target TARGET_NAME BOARD_ID ALL_SRCS ALL_LIBS COMPILE_FLAGS LINK_FLAGS MANUAL) + + set(PLATFORM ${${BOARD_ID}.PLATFORM}) + add_executable(${TARGET_NAME} ${ALL_SRCS}) set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".elf") - get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} ${MANUAL}) + if(NOT EXECUTABLE_OUTPUT_PATH) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + endif() + set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) + + get_recipe_flags(ARDUINO_COMPILE_CMD ARDUINO_COMPILE_FLAGS ${BOARD_ID} "recipe.cpp.o") + if(NOT DEFINED ARDUINO_COMPILE_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.cpp.o'") + endif() + + if(NOT "${CMAKE_CXX_COMPILER}" STREQUAL "${ARDUINO_COMPILE_CMD}") + MESSAGE(FATAL_ERROR "Your compiler needs to be manually set to\nCMAKE_CXX_COMPILER=\"${ARDUINO_COMPILE_CMD}\"") + endif() + + get_recipe_flags(ARDUINO_LINK_CMD ARDUINO_LINK_FLAGS ${BOARD_ID} "recipe.c.combine") + if(NOT DEFINED ARDUINO_LINK_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.c.combine'") + endif() + + + string(REPLACE "\"{build.path}/{archive_file}\"" "" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) + string(REPLACE "{object_files}" "" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) + string(REPLACE "{build.path}" "${EXECUTABLE_OUTPUT_PATH}" ARDUINO_LINK_FLAGS ${ARDUINO_LINK_FLAGS}) set_target_properties(${TARGET_NAME} PROPERTIES COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS}" - LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") - target_link_libraries(${TARGET_NAME} ${ALL_LIBS} "-lc -lm") + LINK_FLAGS "${ARDUINO_LINK_FLAGS}" + ARCHIVE_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + LIBRARY_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}" + ) + target_link_libraries(${TARGET_NAME} ${ALL_LIBS}) - if(NOT EXECUTABLE_OUTPUT_PATH) - set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + + # Convert firmware image to EEP format + get_recipe_flags(ARDUINO_OBJCOPY_EEP_CMD ARDUINO_OBJCOPY_EEP_FLAGS ${BOARD_ID} "recipe.objcopy.eep") + if(NOT DEFINED ARDUINO_OBJCOPY_EEP_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.objcopy.eep'") endif() - set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) + + if ("${ARDUINO_OBJCOPY_EEP_CMD}" MATCHES "^python \"(.*)\"$") + set(ARDUINO_OBJCOPY_EEP_CMD ${CMAKE_MATCH_1}) + endif() + + string(REPLACE "\"" "" ARDUINO_OBJCOPY_EEP_FLAGS ${ARDUINO_OBJCOPY_EEP_FLAGS}) + string(REPLACE " " ";" ARDUINO_OBJCOPY_EEP_FLAGS ${ARDUINO_OBJCOPY_EEP_FLAGS}) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_OBJCOPY} + COMMAND ${ARDUINO_OBJCOPY_EEP_CMD} ARGS ${ARDUINO_OBJCOPY_EEP_FLAGS} - ${TARGET_PATH}.elf - ${TARGET_PATH}.eep COMMENT "Generating EEP image" VERBATIM) # Convert firmware image to ASCII HEX format + get_recipe_flags(ARDUINO_OBJCOPY_HEX_CMD ARDUINO_OBJCOPY_HEX_FLAGS ${BOARD_ID} "recipe.objcopy.hex") + if(NOT DEFINED ARDUINO_OBJCOPY_HEX_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.objcopy.hex'") + endif() + if ("${ARDUINO_OBJCOPY_HEX_CMD}" MATCHES "^python \"(.*)\"$") + set(ARDUINO_OBJCOPY_HEX_CMD ${CMAKE_MATCH_1}) + endif() + string(REPLACE "\"" "" ARDUINO_OBJCOPY_HEX_FLAGS ${ARDUINO_OBJCOPY_HEX_FLAGS}) + string(REPLACE " " ";" ARDUINO_OBJCOPY_HEX_FLAGS ${ARDUINO_OBJCOPY_HEX_FLAGS}) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_OBJCOPY} + COMMAND ${ARDUINO_OBJCOPY_HEX_CMD} ARGS ${ARDUINO_OBJCOPY_HEX_FLAGS} - ${TARGET_PATH}.elf - ${TARGET_PATH}.hex COMMENT "Generating HEX image" VERBATIM) # Display target size - add_custom_command(TARGET ${TARGET_NAME} POST_BUILD - COMMAND ${CMAKE_COMMAND} - ARGS -DFIRMWARE_IMAGE=${TARGET_PATH}.elf - -DMCU=${${BOARD_ID}.build.mcu} - -DEEPROM_IMAGE=${TARGET_PATH}.eep - -P ${ARDUINO_SIZE_SCRIPT} - COMMENT "Calculating image size" - VERBATIM) + get_recipe_flags(ARDUINO_SIZE_CMD ARDUINO_SIZE_FLAGS ${BOARD_ID} "recipe.size") + if(NOT DEFINED ARDUINO_SIZE_FLAGS) + MESSAGE(FATAL_ERROR "Could not get 'recipe.size'") + endif() + + get_variable_filled(REGEX_SIZE "recipe.size.regex" ${BOARD_ID}) + get_variable_filled(REGEX_SIZE_DATA "recipe.size.regex.data" ${BOARD_ID}) + get_variable_filled(REGEX_SIZE_EEPROM "recipe.size.regex.eeprom" ${BOARD_ID}) + get_variable_filled(MAX_SIZE "upload.maximum_size" ${BOARD_ID}) + get_variable_filled(MAX_SIZE_DATA "upload.maximum_data_size" ${BOARD_ID}) + get_variable_filled(MAX_SIZE_FLASH "build.flash_size" ${BOARD_ID}) # Create ${TARGET_NAME}-size target add_custom_target(${TARGET_NAME}-size - COMMAND ${CMAKE_COMMAND} - -DFIRMWARE_IMAGE=${TARGET_PATH}.elf - -DMCU=${${BOARD_ID}.build.mcu} - -DEEPROM_IMAGE=${TARGET_PATH}.eep - -P ${ARDUINO_SIZE_SCRIPT} - DEPENDS ${TARGET_NAME} - COMMENT "Calculating ${TARGET_NAME} image size") + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/Platform/size_script.py + "-c" "\"${ARDUINO_SIZE_CMD}\"" + "-p" "\"${ARDUINO_SIZE_FLAGS}\"" + "-r" "\"${REGEX_SIZE}\"" + "-rd" "\"${REGEX_SIZE_DATA}\"" + "-re" "\"${REGEX_SIZE_EEPROM}\"" + "-s" "\"${MAX_SIZE}\"" + "-sd" "\"${MAX_SIZE_DATA}\"" + "-sf" "\"${MAX_SIZE_FLASH}\"") -endfunction() - -#=============================================================================# -# [PRIVATE/INTERNAL] -# -# setup_arduino_upload(BOARD_ID TARGET_NAME PORT) -# -# BOARD_ID - Arduino board id -# TARGET_NAME - Target name -# PORT - Serial port for upload -# PROGRAMMER_ID - Programmer ID -# AVRDUDE_FLAGS - avrdude flags -# -# Create an upload target (${TARGET_NAME}-upload) for the specified Arduino target. -# -#=============================================================================# -function(setup_arduino_upload BOARD_ID TARGET_NAME PORT PROGRAMMER_ID AVRDUDE_FLAGS) - setup_arduino_bootloader_upload(${TARGET_NAME} ${BOARD_ID} ${PORT} "${AVRDUDE_FLAGS}") - - # Add programmer support if defined - if(PROGRAMMER_ID AND ${PROGRAMMER_ID}.protocol) - setup_arduino_programmer_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") - setup_arduino_bootloader_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") - endif() + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/cmake/Platform/size_script.py + "-c" "${ARDUINO_SIZE_CMD}" + "-p" "${ARDUINO_SIZE_FLAGS}" + "-r" "${REGEX_SIZE}" + "-rd" "${REGEX_SIZE_DATA}" + "-re" "${REGEX_SIZE_EEPROM}" + "-s" "${MAX_SIZE}" + "-sd" "${MAX_SIZE_DATA}" + "-sf" "${MAX_SIZE_FLASH}" + COMMENT "Calculating image size" + VERBATIM) endfunction() @@ -1150,36 +1373,36 @@ endfunction() # # TARGET_NAME - target name # BOARD_ID - board id +# PROGRAMMER_ID - the programmer # PORT - serial port -# AVRDUDE_FLAGS - avrdude flags (override) # # 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 AVRDUDE_FLAGS) +function(setup_arduino_bootloader_upload TARGET_NAME BOARD_ID PROGRAMMER_ID PORT) set(UPLOAD_TARGET ${TARGET_NAME}-upload) - set(AVRDUDE_ARGS) - - setup_arduino_bootloader_args(${BOARD_ID} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) - - if(NOT AVRDUDE_ARGS) - message("Could not generate default avrdude bootloader args, aborting!") - return() - endif() if(NOT EXECUTABLE_OUTPUT_PATH) - set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) endif() set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) - list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_PATH}.hex") - list(APPEND AVRDUDE_ARGS "-Ueeprom:w:${TARGET_PATH}.eep:i") + get_recipe_flags(ARDUINO_UPLOAD_CMD ARDUINO_UPLOAD_FLAGS ${BOARD_ID} "tools.${PROGRAMMER_ID}.upload") + + string(REPLACE "{build.path}/{build.project_name}" "${TARGET_NAME}" ARDUINO_UPLOAD_FLAGS ${ARDUINO_UPLOAD_FLAGS}) + string(REPLACE "{serial.port}" "${PORT}" ARDUINO_UPLOAD_FLAGS ${ARDUINO_UPLOAD_FLAGS}) + + if(NOT ARDUINO_UPLOAD_FLAGS) + message(FATAL_ERROR "Could not generate bootloader args, aborting!") + endif() + + string(REPLACE " " ";" ARDUINO_UPLOAD_FLAGS ${ARDUINO_UPLOAD_FLAGS}) add_custom_target(${UPLOAD_TARGET} - ${ARDUINO_AVRDUDE_PROGRAM} - ${AVRDUDE_ARGS} - DEPENDS ${TARGET_NAME}) + ${ARDUINO_UPLOAD_CMD} + ${ARDUINO_UPLOAD_FLAGS} + DEPENDS ${TARGET_NAME}) # Global upload target if(NOT TARGET upload) @@ -1189,6 +1412,32 @@ function(setup_arduino_bootloader_upload TARGET_NAME BOARD_ID PORT AVRDUDE_FLAGS add_dependencies(upload ${UPLOAD_TARGET}) endfunction() +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# setup_arduino_upload(BOARD_ID TARGET_NAME PORT) +# +# BOARD_ID - Arduino board id +# TARGET_NAME - Target name +# PORT - Serial port for upload +# PROGRAMMER_ID - Programmer ID +# AVRDUDE_FLAGS - avrdude flags +# +# Create an upload target (${TARGET_NAME}-upload) for the specified Arduino target. +# +#=============================================================================# +function(setup_arduino_upload BOARD_ID TARGET_NAME PORT PROGRAMMER_ID AVRDUDE_FLAGS) + + setup_arduino_bootloader_upload(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT}) + + # Add programmer support if defined + if(PROGRAMMER_ID AND ${BOARD_ID}.upload.protocol) + setup_arduino_programmer_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") + setup_arduino_bootloader_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") + endif() +endfunction() + + #=============================================================================# # [PRIVATE/INTERNAL] # @@ -1198,43 +1447,42 @@ endfunction() # BOARD_ID - board id # PROGRAMMER - programmer id # PORT - serial port -# AVRDUDE_FLAGS - avrdude flags (override) -# +# # 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 PORT AVRDUDE_FLAGS) +function(setup_arduino_programmer_burn TARGET_NAME BOARD_ID PROGRAMMER PORT) set(PROGRAMMER_TARGET ${TARGET_NAME}-burn) - set(AVRDUDE_ARGS) - - setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) - - if(NOT AVRDUDE_ARGS) - message("Could not generate default avrdude programmer args, aborting!") - return() - endif() - if(NOT EXECUTABLE_OUTPUT_PATH) - set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) endif() set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) - list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_PATH}.hex") + get_recipe_flags(ARDUINO_PROGRAM_CMD ARDUINO_PROGRAM_FLAGS ${BOARD_ID} "tools.${PROGRAMMER_ID}.program") + if(NOT ARDUINO_PROGRAM_FLAGS) + message(FATAL_ERROR "Could not generate programmer args, aborting!") + endif() + + string(REPLACE "{build.path}/{build.project_name}" "${TARGET_NAME}" ARDUINO_PROGRAM_FLAGS ${ARDUINO_PROGRAM_FLAGS}) + string(REPLACE "{program.extra_params}" "" ARDUINO_PROGRAM_FLAGS ${ARDUINO_PROGRAM_FLAGS}) + string(REPLACE "{protocol}" "${${BOARD_ID}.upload.protocol}" ARDUINO_PROGRAM_FLAGS ${ARDUINO_PROGRAM_FLAGS}) + string(REPLACE " " ";" ARDUINO_PROGRAM_FLAGS ${ARDUINO_PROGRAM_FLAGS}) add_custom_target(${PROGRAMMER_TARGET} - ${ARDUINO_AVRDUDE_PROGRAM} - ${AVRDUDE_ARGS} - DEPENDS ${TARGET_NAME}) + ${ARDUINO_PROGRAM_CMD} + ${ARDUINO_PROGRAM_FLAGS} + DEPENDS ${TARGET_NAME}) + endfunction() #=============================================================================# # [PRIVATE/INTERNAL] # # setup_arduino_bootloader_burn(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) -# +# # TARGET_NAME - name of target to burn # BOARD_ID - board id # PROGRAMMER - programmer id @@ -1247,108 +1495,80 @@ endfunction() # #=============================================================================# function(setup_arduino_bootloader_burn TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) - set(BOOTLOADER_TARGET ${TARGET_NAME}-burn-bootloader) - - set(AVRDUDE_ARGS) - setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) + set(PLATFORM ${${BOARD_ID}.PLATFORM}) - if(NOT AVRDUDE_ARGS) - message("Could not generate default avrdude programmer args, aborting!") - return() - endif() + setup_arduino_bootloader_erase("${TARGET_NAME}" "${BOARD_ID}" "${PROGRAMMER}" "${PORT}" "${AVRDUDE_FLAGS}") - foreach( ITEM unlock_bits high_fuses low_fuses path file) - if(NOT ${BOARD_ID}.bootloader.${ITEM}) - message("Missing ${BOARD_ID}.bootloader.${ITEM}, not creating bootloader burn target ${BOOTLOADER_TARGET}.") - return() - endif() - endforeach() + set(BOOTLOADER_TARGET ${TARGET_NAME}-burn-bootloader) - 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() + if(NOT EXECUTABLE_OUTPUT_PATH) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) endif() + set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) - # 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") + get_recipe_flags(ARDUINO_BOOTLOADER_CMD ARDUINO_BOOTLOADER_FLAGS ${BOARD_ID} "tools.${PROGRAMMER_ID}.bootloader") + if(NOT ARDUINO_BOOTLOADER_FLAGS) + message(FATAL_ERROR "Could not generate bootloader args, aborting!") endif() - list(APPEND AVRDUDE_ARGS - "-Uhfuse:w:${${BOARD_ID}.bootloader.high_fuses}:m" - "-Ulfuse:w:${${BOARD_ID}.bootloader.low_fuses}:m") - # Set bootloader image - list(APPEND AVRDUDE_ARGS "-Uflash:w:${${BOARD_ID}.bootloader.file}:i") + string(REPLACE "{build.path}/{build.project_name}" "${TARGET_NAME}" ARDUINO_BOOTLOADER_FLAGS ${ARDUINO_BOOTLOADER_FLAGS}) + string(REPLACE "{program.extra_params}" "" ARDUINO_BOOTLOADER_FLAGS ${ARDUINO_BOOTLOADER_FLAGS}) + string(REPLACE "{protocol}" "${${BOARD_ID}.upload.protocol}" ARDUINO_BOOTLOADER_FLAGS ${ARDUINO_BOOTLOADER_FLAGS}) + string(REPLACE " " ";" ARDUINO_BOOTLOADER_FLAGS ${ARDUINO_BOOTLOADER_FLAGS}) - # Set lockbits - list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.lock_bits}:m") + if(NOT EXISTS "${${PLATFORM}_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.file}") + message("${${PLATFORM}_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.file}") + message(FATAL_ERROR "Missing bootloader image, not creating bootloader burn target ${BOOTLOADER_TARGET}.") + endif() # 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}) + ${ARDUINO_BOOTLOADER_CMD} + ${ARDUINO_BOOTLOADER_FLAGS} + WORKING_DIRECTORY ${${PLATFORM}_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path} + DEPENDS ${TARGET_NAME}-erase-bootloader) endfunction() #=============================================================================# # [PRIVATE/INTERNAL] # -# setup_arduino_programmer_args(BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) +# setup_arduino_bootloader_erase(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) # +# TARGET_NAME - name of target to erase # BOARD_ID - board id # PROGRAMMER - programmer id -# TARGET_NAME - target name # PORT - serial port # AVRDUDE_FLAGS - avrdude flags (override) -# OUTPUT_VAR - name of output variable for result # -# Sets up default avrdude settings for burning firmware via a programmer. +# Create a target for erasing the bootloader via a programmer. +# +# The target for erasing the bootloader is ${TARGET_NAME}-erase-bootloader +# #=============================================================================# -function(setup_arduino_programmer_args BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) - set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) - - if(NOT AVRDUDE_FLAGS) - set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) - 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() +function(setup_arduino_bootloader_erase TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) + set(ERASE_TARGET ${TARGET_NAME}-erase-bootloader) - 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 + if(NOT EXECUTABLE_OUTPUT_PATH) + set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) endif() + set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) - if(${PROGRAMMER}.delay) - list(APPEND AVRDUDE_ARGS "-i${${PROGRAMMER}.delay}") # Set delay + get_recipe_flags(ARDUINO_ERASE_CMD ARDUINO_ERASE_FLAGS ${BOARD_ID} "tools.${PROGRAMMER_ID}.erase") + if(NOT ARDUINO_ERASE_FLAGS) + message(FATAL_ERROR "Could not generate ERASE args, aborting!") endif() - list(APPEND AVRDUDE_ARGS "-p${${BOARD_ID}.build.mcu}") # MCU Type + string(REPLACE "{build.path}/{build.project_name}" "${TARGET_NAME}" ARDUINO_ERASE_FLAGS ${ARDUINO_ERASE_FLAGS}) + string(REPLACE "{program.extra_params}" "" ARDUINO_ERASE_FLAGS ${ARDUINO_ERASE_FLAGS}) + string(REPLACE "{protocol}" "${${BOARD_ID}.upload.protocol}" ARDUINO_ERASE_FLAGS ${ARDUINO_ERASE_FLAGS}) + string(REPLACE " " ";" ARDUINO_ERASE_FLAGS ${ARDUINO_ERASE_FLAGS}) - list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) - - set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) + # Create burn ERASE target + add_custom_target(${ERASE_TARGET} + ${ARDUINO_ERASE_CMD} + ${ARDUINO_ERASE_FLAGS} + DEPENDS ${TARGET_NAME}) endfunction() #=============================================================================# @@ -1367,32 +1587,32 @@ endfunction() function(setup_arduino_bootloader_args BOARD_ID TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) - if(NOT AVRDUDE_FLAGS) - set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) - endif() - list(APPEND AVRDUDE_ARGS "-C${ARDUINO_AVRDUDE_CONFIG_PATH}" # avrdude config - "-p${${BOARD_ID}.build.mcu}" # MCU Type + "-p${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu}" # MCU Type ) # Programmer - if(NOT ${BOARD_ID}.upload.protocol OR ${BOARD_ID}.upload.protocol STREQUAL "stk500") - list(APPEND AVRDUDE_ARGS "-cstk500v1") + if(NOT ${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol OR ${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol STREQUAL "stk500") + if(NOT ${BOARD_ID}.upload.protocol OR ${BOARD_ID}.upload.protocol STREQUAL "stk500") + list(APPEND AVRDUDE_ARGS "-cstk500v1") + else() + list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}.upload.protocol}") + endif() else() - list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}.upload.protocol}") + list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol}") endif() set(UPLOAD_SPEED "19200") - if(${BOARD_ID}.upload.speed) - set(UPLOAD_SPEED ${${BOARD_ID}.upload.speed}) + if(${BOARD_ID}${ARDUINO_CPUMENU}.upload.speed) + set(UPLOAD_SPEED ${${BOARD_ID}${ARDUINO_CPUMENU}.upload.speed}) endif() list(APPEND AVRDUDE_ARGS "-b${UPLOAD_SPEED}" # Baud rate "-P${PORT}" # Serial port "-D" # Dont erase - ) + ) list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) @@ -1457,7 +1677,7 @@ endfunction() # # VAR_NAME - Variable name where the detected version will be saved # -# Detects the Arduino SDK Version based on the revisions.txt file. The +# Detects the Arduino SDK Version based on the lib/versions.txt file. The # following variables will be generated: # # ${VAR_NAME} -> the full version (major.minor.patch) @@ -1501,15 +1721,15 @@ endfunction() # 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 +# entry[.setting][.subsetting] = value # -# where [.subsetting] is optional +# where [.setting] and [.subsetting] is optional # # For example, the following settings: # @@ -1528,75 +1748,219 @@ endfunction() # 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. +# set(uno.upload.SETTINGS protocol maximum_size) # List of sub-settings for uno.upload +# set(uno.build.SETTINGS mcu core) # List of sub-settings for uno.build +# +# The ${ENTRY_NAME}.SETTINGS variable lists all settings for the entry # # 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) +function(LOAD_ARDUINO_STYLE_SETTINGS SETTINGS_LIST SETTINGS_PATH SETTINGS_PREFIX) 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() + file(STRINGS ${SETTINGS_PATH} FILE_ENTRIES) # Settings file split into lines - # 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() + foreach(FILE_ENTRY ${FILE_ENTRIES}) + if("${FILE_ENTRY}" MATCHES "^[^#]+=.*") - 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") + string(REGEX MATCH "^([^=]*)=(.*)$" SETTING_SPLIT ${FILE_ENTRY}) + if(NOT DEFINED CMAKE_MATCH_1 OR NOT DEFINED CMAKE_MATCH_2) + MESSAGE(WARNING "Invalid setting: ${FILE_ENTRY}") + continue() endif() - set(FULL_SETTING_NAME ${FULL_SETTING_NAME}.${ENTRY_SUBSETTING}) + + set(SETTING_NAME ${CMAKE_MATCH_1}) + set(SETTING_VALUE ${CMAKE_MATCH_2}) + 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() + + set(FULL_SETTING_NAME "${SETTINGS_PREFIX}") + + set(ENTRY_SETTING_LIST) + + foreach(subsetting ${ENTRY_NAME_TOKENS}) + + if (FULL_SETTING_NAME STREQUAL "") + set(FULL_SETTING_NAME "${subsetting}") + else() + set(FULL_SETTING_NAME ${FULL_SETTING_NAME}.${subsetting}) + endif() + + if(ENTRY_SETTING_LIST) + list(FIND ${ENTRY_SETTING_LIST} ${subsetting} ENTRY_SETTING_INDEX) + if(ENTRY_SETTING_INDEX LESS 0) + # Add setting to entry + list(APPEND ${ENTRY_SETTING_LIST} ${subsetting}) + set(${ENTRY_SETTING_LIST} ${${ENTRY_SETTING_LIST}} + CACHE INTERNAL "${PLATFORM} ${FULL_SETTING_NAME} Board settings list") + endif() + endif() + + set(ENTRY_SETTING_LIST ${FULL_SETTING_NAME}.SETTINGS) + + endforeach() + + # Save setting value + set(${FULL_SETTING_NAME} ${SETTING_VALUE} + CACHE INTERNAL "${PLATFORM} ${ENTRY_NAME} Board setting") + endif() + endforeach() + set(${SETTINGS_LIST} ${${SETTINGS_LIST}} + CACHE STRING "List of detected ${PLATFORM} Board configurations") + mark_as_advanced(${SETTINGS_LIST}) + endif() +endfunction() - # Save setting value - set(${FULL_SETTING_NAME} ${SETTING_VALUE} - CACHE INTERNAL "Arduino ${ENTRY_NAME} Board setting") - +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# GET_VARIABLE_VALUE_FILLED(SETTING_VALUE BOARD_ID) +# +# VARIABLE_RETURN - The name of the return variable +# SETTING_VALUE - the value of the variable with placeholders +# BOARD_ID - the id of the board to identify the correct placeholder replacements +# SETTING_NAME - optional setting name +# +# Replace placeholders in the variable value with the defined values from +# the cache. +# E.g. +# {runtime.tools.avrdude.path} +# will be replaced accordingly +#=============================================================================# +function(GET_VARIABLE_VALUE_FILLED VARIABLE_RETURN SETTING_VALUE BOARD_ID SETTING_NAME) + set(PLATFORM ${${BOARD_ID}.PLATFORM}) + set(${VARIABLE_RETURN} ${SETTING_VALUE} PARENT_SCOPE) + + if (NOT SETTING_VALUE STREQUAL "") + string(REGEX MATCHALL "{([^}]+)}" VARS_REPLACE ${SETTING_VALUE}) + LIST(LENGTH VARS_REPLACE MATCH_COUNT) + if(MATCH_COUNT GREATER 0) + FOREACH(i IN LISTS VARS_REPLACE) + string(REPLACE "}" "" i ${i}) + string(REPLACE "{" "" i ${i}) + + unset(VAR_VALUE) + unset(VAR_NAME) + + set(VARIABLES_TO_CHECK + "${BOARD_ID}${ARDUINO_CPUMENU}.${i}.${runtime.os}" + "${BOARD_ID}${ARDUINO_CPUMENU}.${i}" + "${BOARD_ID}.${i}.${runtime.os}" + "${BOARD_ID}.${i}" + "${PLATFORM}.${i}.${runtime.os}" + "${PLATFORM}.${i}" + "${i}.${runtime.os}" + "${i}" + ) + + foreach(VAR_CHECK ${VARIABLES_TO_CHECK}) + if (DEFINED ${VAR_CHECK}) + set(VAR_VALUE "${${VAR_CHECK}}") + set(VAR_NAME "${VAR_CHECK}") + break() + endif() + endforeach() + if(NOT DEFINED VAR_VALUE AND SETTING_NAME) + # check if the value is somewhere available along the path leading to this setting + # i.e. if the searched value is 'path' and the variable is called 'some.compiler.tool' check + # - some.compiler.path + # - some.path + if(SETTING_NAME MATCHES "^(.+)\\.[^\\.]+\$") + set(SETTING_NAME_BASE "${CMAKE_MATCH_1}") + while (SETTING_NAME_BASE MATCHES "^(.+)\\.[^\\.]+\$") + set(SETTING_NAME_BASE "${CMAKE_MATCH_1}") + set(CUR_VAR_NAME "${SETTING_NAME_BASE}.${i}") + if(DEFINED ${CUR_VAR_NAME}.${runtime.os}) + set(VAR_VALUE "${${CUR_VAR_NAME}.${runtime.os}}") + set(VAR_NAME "${CUR_VAR_NAME}.${runtime.os}") + break() + elseif(DEFINED ${CUR_VAR_NAME}) + set(VAR_VALUE "${${CUR_VAR_NAME}}") + set(VAR_NAME "${CUR_VAR_NAME}") + break() + endif() + endwhile () + endif() + endif() + + if(DEFINED VAR_VALUE) + #recursively replace + set(TMP_FILLED "${VAR_VALUE}") + get_variable_value_filled(TMP_FILLED "${VAR_VALUE}" ${BOARD_ID} ${VAR_NAME}) + string(REPLACE "{${i}}" "${TMP_FILLED}" SETTING_VALUE ${SETTING_VALUE}) + endif() + ENDFOREACH() + set(${VARIABLE_RETURN} ${SETTING_VALUE} PARENT_SCOPE) + endif() + endif() +endfunction() + +#=============================================================================# +# [PRIVATE/INTERNAL] +# +# GET_VARIABLE_FILLED(VARIABLE_NAME BOARD_ID) +# +# VARIABLE_RETURN - The name of the return variable +# VARIABLE_NAME - the variable from which the value should be returned +# BOARD_ID - the id of the board to identify the correct placeholder replacements +# +# Replace placeholders in the variable value with the defined values from +# the cache. +# E.g. +# GET_VARIABLE_FILLED(SOME_VAR "recipe.c.o.pattern" "${${PROJECT_NAME}_BOARD}") +# MESSAGE(STATUS "Var = ${SOME_VAR}") +#=============================================================================# +function(GET_VARIABLE_FILLED VARIABLE_RETURN VARIABLE_NAME BOARD_ID) + + set(PLATFORM ${${BOARD_ID}.PLATFORM}) + + unset(VAR_VALUE) + unset(VAR_NAME) + + set(VARIABLES_TO_CHECK + "${BOARD_ID}${ARDUINO_CPUMENU}.${VARIABLE_NAME}.${runtime.os}" + "${BOARD_ID}${ARDUINO_CPUMENU}.${VARIABLE_NAME}" + "${BOARD_ID}.${VARIABLE_NAME}.${runtime.os}" + "${BOARD_ID}.${VARIABLE_NAME}" + "${PLATFORM}.${VARIABLE_NAME}.${runtime.os}" + "${PLATFORM}.${VARIABLE_NAME}" + "${VARIABLE_NAME}.${runtime.os}" + "${VARIABLE_NAME}" + ) + + foreach(VAR_CHECK ${VARIABLES_TO_CHECK}) + if (DEFINED ${VAR_CHECK}) + set(VAR_VALUE "${${VAR_CHECK}}") + set(VAR_NAME "${VAR_CHECK}") + break() endif() endforeach() - set(${SETTINGS_LIST} ${${SETTINGS_LIST}} - CACHE STRING "List of detected Arduino Board configurations") - mark_as_advanced(${SETTINGS_LIST}) + + #if (NOT DEFINED SETTING_VALUE) + # MESSAGE(WARNING "Variable ${VARIABLE_NAME} is not set") + #endif() + + + if (NOT VAR_VALUE STREQUAL "") + set(VARIABLE_FILLED "") + get_variable_value_filled("VARIABLE_FILLED" "${VAR_VALUE}" "${BOARD_ID}" "${VAR_NAME}") + set(${VARIABLE_RETURN} ${VARIABLE_FILLED} PARENT_SCOPE) + else() + set(${VARIABLE_RETURN} ${SETTING_VALUE} PARENT_SCOPE) endif() endfunction() @@ -1612,17 +1976,10 @@ function(PRINT_SETTINGS ENTRY_NAME) if(${ENTRY_NAME}.SETTINGS) foreach(ENTRY_SETTING ${${ENTRY_NAME}.SETTINGS}) - if(${ENTRY_NAME}.${ENTRY_SETTING}) + if(DEFINED ${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 "") + print_settings("${ENTRY_NAME}.${ENTRY_SETTING}") endforeach() endif() endfunction() @@ -1675,7 +2032,8 @@ function(SETUP_ARDUINO_EXAMPLE TARGET_NAME LIBRARY_NAME EXAMPLE_NAME OUTPUT_VAR) 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) + foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${${ARDUINO_PLATFORM}_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries) + message(STATUS "Search ${LIBRARY_NAME} example directory in ${LIB_SEARCH_PATH}") if(EXISTS "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") set(EXAMPLE_SKETCH_PATH "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") break() @@ -1728,9 +2086,13 @@ function(SETUP_ARDUINO_SKETCH TARGET_NAME SKETCH_PATH OUTPUT_VAR) # Find all sketch files file(GLOB SKETCH_SOURCES ${SKETCH_PATH}/*.pde ${SKETCH_PATH}/*.ino) + set(ALL_SRCS ${SKETCH_SOURCES}) + list(REMOVE_ITEM SKETCH_SOURCES ${MAIN_SKETCH}) list(SORT SKETCH_SOURCES) - + + + generate_cpp_from_sketch("${MAIN_SKETCH}" "${SKETCH_SOURCES}" "${SKETCH_CPP}") # Regenerate build system if sketch changes @@ -1825,7 +2187,7 @@ function(GENERATE_CPP_FROM_SKETCH MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) # Write function prototypes file(APPEND ${SKETCH_CPP} "\n//=== START Forward: ${SKETCH_SOURCE_PATH}\n") - foreach(SKETCH_PROTOTYPE ${SKETCH_PROTOTYPES}) + foreach(SKETCH_PROTOTYPE ${SKETCH_PROTOTYPES}) string(REPLACE "\n" " " SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") string(REPLACE "{" "" SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") arduino_debug_msg("\tprototype: ${SKETCH_PROTOTYPE};") @@ -1839,7 +2201,7 @@ function(GENERATE_CPP_FROM_SKETCH MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) endforeach() file(APPEND ${SKETCH_CPP} "//=== END Forward: ${SKETCH_SOURCE_PATH}\n") endforeach() - + # Write Sketch CPP source get_num_lines("${SKETCH_HEAD}" HEAD_NUM_LINES) file(APPEND ${SKETCH_CPP} "#line ${HEAD_NUM_LINES} \"${MAIN_SKETCH_PATH}\"\n") @@ -1853,99 +2215,6 @@ function(GENERATE_CPP_FROM_SKETCH MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) endforeach() endfunction() -#=============================================================================# -# [PRIVATE/INTERNAL] -# -# setup_arduino_size_script(OUTPUT_VAR) -# -# OUTPUT_VAR - Output variable that will contain the script path -# -# Generates script used to display the firmware size. -#=============================================================================# -function(SETUP_ARDUINO_SIZE_SCRIPT OUTPUT_VAR) - set(ARDUINO_SIZE_SCRIPT_PATH ${CMAKE_BINARY_DIR}/CMakeFiles/FirmwareSize.cmake) - - file(WRITE ${ARDUINO_SIZE_SCRIPT_PATH} " - set(AVRSIZE_PROGRAM ${AVRSIZE_PROGRAM}) - set(AVRSIZE_FLAGS -C --mcu=\${MCU}) - - execute_process(COMMAND \${AVRSIZE_PROGRAM} \${AVRSIZE_FLAGS} \${FIRMWARE_IMAGE} \${EEPROM_IMAGE} - OUTPUT_VARIABLE SIZE_OUTPUT) - - - string(STRIP \"\${SIZE_OUTPUT}\" RAW_SIZE_OUTPUT) - - # Convert lines into a list - string(REPLACE \"\\n\" \";\" SIZE_OUTPUT_LIST \"\${SIZE_OUTPUT}\") - - set(SIZE_OUTPUT_LINES) - foreach(LINE \${SIZE_OUTPUT_LIST}) - if(NOT \"\${LINE}\" STREQUAL \"\") - list(APPEND SIZE_OUTPUT_LINES \"\${LINE}\") - endif() - endforeach() - - function(EXTRACT LIST_NAME INDEX VARIABLE) - list(GET \"\${LIST_NAME}\" \${INDEX} RAW_VALUE) - string(STRIP \"\${RAW_VALUE}\" VALUE) - - set(\${VARIABLE} \"\${VALUE}\" PARENT_SCOPE) - endfunction() - function(PARSE INPUT VARIABLE_PREFIX) - if(\${INPUT} MATCHES \"([^:]+):[ \\t]*([0-9]+)[ \\t]*([^ \\t]+)[ \\t]*[(]([0-9.]+)%.*\") - set(ENTRY_NAME \${CMAKE_MATCH_1}) - set(ENTRY_SIZE \${CMAKE_MATCH_2}) - set(ENTRY_SIZE_TYPE \${CMAKE_MATCH_3}) - set(ENTRY_PERCENT \${CMAKE_MATCH_4}) - endif() - - set(\${VARIABLE_PREFIX}_NAME \${ENTRY_NAME} PARENT_SCOPE) - set(\${VARIABLE_PREFIX}_SIZE \${ENTRY_SIZE} PARENT_SCOPE) - set(\${VARIABLE_PREFIX}_SIZE_TYPE \${ENTRY_SIZE_TYPE} PARENT_SCOPE) - set(\${VARIABLE_PREFIX}_PERCENT \${ENTRY_PERCENT} PARENT_SCOPE) - endfunction() - - list(LENGTH SIZE_OUTPUT_LINES SIZE_OUTPUT_LENGTH) - #message(\"\${SIZE_OUTPUT_LINES}\") - #message(\"\${SIZE_OUTPUT_LENGTH}\") - if (\${SIZE_OUTPUT_LENGTH} STREQUAL 14) - EXTRACT(SIZE_OUTPUT_LINES 3 FIRMWARE_PROGRAM_SIZE_ROW) - EXTRACT(SIZE_OUTPUT_LINES 5 FIRMWARE_DATA_SIZE_ROW) - PARSE(FIRMWARE_PROGRAM_SIZE_ROW FIRMWARE_PROGRAM) - PARSE(FIRMWARE_DATA_SIZE_ROW FIRMWARE_DATA) - - set(FIRMWARE_STATUS \"Firmware Size: \") - set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} [\${FIRMWARE_PROGRAM_NAME}: \${FIRMWARE_PROGRAM_SIZE} \${FIRMWARE_PROGRAM_SIZE_TYPE} (\${FIRMWARE_PROGRAM_PERCENT}%)] \") - set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} [\${FIRMWARE_DATA_NAME}: \${FIRMWARE_DATA_SIZE} \${FIRMWARE_DATA_SIZE_TYPE} (\${FIRMWARE_DATA_PERCENT}%)]\") - set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} on \${MCU}\") - - EXTRACT(SIZE_OUTPUT_LINES 10 EEPROM_PROGRAM_SIZE_ROW) - EXTRACT(SIZE_OUTPUT_LINES 12 EEPROM_DATA_SIZE_ROW) - PARSE(EEPROM_PROGRAM_SIZE_ROW EEPROM_PROGRAM) - PARSE(EEPROM_DATA_SIZE_ROW EEPROM_DATA) - - set(EEPROM_STATUS \"EEPROM Size: \") - set(EEPROM_STATUS \"\${EEPROM_STATUS} [\${EEPROM_PROGRAM_NAME}: \${EEPROM_PROGRAM_SIZE} \${EEPROM_PROGRAM_SIZE_TYPE} (\${EEPROM_PROGRAM_PERCENT}%)] \") - set(EEPROM_STATUS \"\${EEPROM_STATUS} [\${EEPROM_DATA_NAME}: \${EEPROM_DATA_SIZE} \${EEPROM_DATA_SIZE_TYPE} (\${EEPROM_DATA_PERCENT}%)]\") - set(EEPROM_STATUS \"\${EEPROM_STATUS} on \${MCU}\") - - message(\"\${FIRMWARE_STATUS}\") - message(\"\${EEPROM_STATUS}\\n\") - - if(\$ENV{VERBOSE}) - message(\"\${RAW_SIZE_OUTPUT}\\n\") - elseif(\$ENV{VERBOSE_SIZE}) - message(\"\${RAW_SIZE_OUTPUT}\\n\") - endif() - else() - message(\"\${RAW_SIZE_OUTPUT}\") - endif() - ") - - set(${OUTPUT_VAR} ${ARDUINO_SIZE_SCRIPT_PATH} PARENT_SCOPE) -endfunction() - - #=============================================================================# # [PRIVATE/INTERNAL] # @@ -2073,33 +2342,33 @@ endfunction() #=============================================================================# -# C Flags +# C Flags #=============================================================================# if (NOT DEFINED ARDUINO_C_FLAGS) - set(ARDUINO_C_FLAGS "-mcall-prologues -ffunction-sections -fdata-sections") + set(ARDUINO_C_FLAGS "-g -Os -w -ffunction-sections -fdata-sections -MMD") endif (NOT DEFINED ARDUINO_C_FLAGS) -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 "-Os -DNDEBUG -w ${ARDUINO_C_FLAGS}" CACHE STRING "") -set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -g -w ${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS "${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_DEBUG "${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_MINSIZEREL "${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELEASE "${ARDUINO_C_FLAGS}" CACHE STRING "") +set(CMAKE_C_FLAGS_RELWITHDEBINFO "${ARDUINO_C_FLAGS}" CACHE STRING "") #=============================================================================# -# C++ Flags +# C++ Flags #=============================================================================# if (NOT DEFINED ARDUINO_CXX_FLAGS) - set(ARDUINO_CXX_FLAGS "${ARDUINO_C_FLAGS} -fno-exceptions") + set(ARDUINO_CXX_FLAGS "-g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD") endif (NOT DEFINED ARDUINO_CXX_FLAGS) -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 "-Os -DNDEBUG ${ARDUINO_CXX_FLAGS}" CACHE STRING "") -set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-Os -g ${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS "${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_DEBUG "${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_MINSIZEREL "${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELEASE "${ARDUINO_CXX_FLAGS}" CACHE STRING "") +set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${ARDUINO_CXX_FLAGS}" CACHE STRING "") #=============================================================================# # Executable Linker Flags # #=============================================================================# -set(ARDUINO_LINKER_FLAGS "-Wl,--gc-sections -lm") +set(ARDUINO_LINKER_FLAGS "-w -Os -Wl,--gc-sections") 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 "") @@ -2124,28 +2393,52 @@ set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STR #=============================================================================# -# Arduino Settings -#=============================================================================# -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 "") - -#=============================================================================# -# Initialization +# Initialization #=============================================================================# if(NOT ARDUINO_FOUND AND ARDUINO_SDK_PATH) - register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/arduino/) - - find_file(ARDUINO_LIBRARIES_PATH - NAMES libraries - PATHS ${ARDUINO_SDK_PATH} - DOC "Path to directory containing the Arduino libraries.") find_file(ARDUINO_VERSION_PATH NAMES lib/version.txt PATHS ${ARDUINO_SDK_PATH} - DOC "Path to Arduino version file.") + DOC "Path to Arduino version file." + NO_SYSTEM_ENVIRONMENT_PATH) + + + detect_arduino_version(ARDUINO_SDK_VERSION) + set(ARDUINO_SDK_VERSION ${ARDUINO_SDK_VERSION} CACHE STRING "Arduino SDK Version") + set(ARDUINO_SDK_VERSION_MAJOR ${ARDUINO_SDK_VERSION_MAJOR} CACHE STRING "Arduino SDK Major Version") + set(ARDUINO_SDK_VERSION_MINOR ${ARDUINO_SDK_VERSION_MINOR} CACHE STRING "Arduino SDK Minor Version") + set(ARDUINO_SDK_VERSION_PATCH ${ARDUINO_SDK_VERSION_PATCH} CACHE STRING "Arduino SDK Patch Version") + + if(ARDUINO_SDK_VERSION VERSION_LESS 0.19) + message(FATAL_ERROR "Unsupported Arduino SDK (require version 0.19 or higher)") + endif() + + message(STATUS "Arduino SDK version ${ARDUINO_SDK_VERSION}: ${ARDUINO_SDK_PATH}") + + SUBDIRLIST(HARDWARES ${ARDUINO_SDK_PATH}/hardware/) + FOREACH(hardware ${HARDWARES}) + if("${hardware}" STREQUAL "tools") + continue() + endif() + + if(ARDUINO_SDK_VERSION VERSION_LESS 1.5) + # SDK less than 1.5 does not have architecture subfolders + register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/${hardware}) + else() + SUBDIRLIST(ARCHITECTURES ${ARDUINO_SDK_PATH}/hardware/${hardware}) + FOREACH(architecture ${ARCHITECTURES}) + register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/${hardware}/${architecture}) + ENDFOREACH() + endif() + + ENDFOREACH() + + find_file(ARDUINO_LIBRARIES_PATH + NAMES libraries + PATHS ${ARDUINO_SDK_PATH} + DOC "Path to directory containing the Arduino libraries." + NO_SYSTEM_ENVIRONMENT_PATH) find_program(ARDUINO_AVRDUDE_PROGRAM NAMES avrdude @@ -2165,14 +2458,8 @@ if(NOT ARDUINO_FOUND AND ARDUINO_SDK_PATH) PATHS ${ARDUINO_SDK_PATH} /etc/avrdude /etc PATH_SUFFIXES hardware/tools hardware/tools/avr/etc - DOC "Path to avrdude programmer configuration file.") - - if(NOT CMAKE_OBJCOPY) - find_program(AVROBJCOPY_PROGRAM - avr-objcopy) - set(ADDITIONAL_REQUIRED_VARS AVROBJCOPY_PROGRAM) - set(CMAKE_OBJCOPY ${AVROBJCOPY_PROGRAM}) - endif(NOT CMAKE_OBJCOPY) + DOC "Path to avrdude programmer configuration file." + NO_SYSTEM_ENVIRONMENT_PATH) set(ARDUINO_DEFAULT_BOARD uno CACHE STRING "Default Arduino Board ID when not specified.") set(ARDUINO_DEFAULT_PORT CACHE STRING "Default Arduino port when not specified.") @@ -2181,52 +2468,78 @@ if(NOT ARDUINO_FOUND AND ARDUINO_SDK_PATH) # Ensure that all required paths are found required_variables(VARS - ARDUINO_PLATFORMS - ARDUINO_CORES_PATH - ARDUINO_BOOTLOADERS_PATH - ARDUINO_LIBRARIES_PATH - ARDUINO_BOARDS_PATH - ARDUINO_PROGRAMMERS_PATH - ARDUINO_VERSION_PATH - ARDUINO_AVRDUDE_FLAGS - ARDUINO_AVRDUDE_PROGRAM - ARDUINO_AVRDUDE_CONFIG_PATH - AVRSIZE_PROGRAM - ${ADDITIONAL_REQUIRED_VARS} - MSG "Invalid Arduino SDK path (${ARDUINO_SDK_PATH}).\n") - - detect_arduino_version(ARDUINO_SDK_VERSION) - set(ARDUINO_SDK_VERSION ${ARDUINO_SDK_VERSION} CACHE STRING "Arduino SDK Version") - set(ARDUINO_SDK_VERSION_MAJOR ${ARDUINO_SDK_VERSION_MAJOR} CACHE STRING "Arduino SDK Major Version") - set(ARDUINO_SDK_VERSION_MINOR ${ARDUINO_SDK_VERSION_MINOR} CACHE STRING "Arduino SDK Minor Version") - set(ARDUINO_SDK_VERSION_PATCH ${ARDUINO_SDK_VERSION_PATCH} CACHE STRING "Arduino SDK Patch Version") - - if(ARDUINO_SDK_VERSION VERSION_LESS 0.19) - message(FATAL_ERROR "Unsupported Arduino SDK (require verion 0.19 or higher)") - endif() - - message(STATUS "Arduino SDK version ${ARDUINO_SDK_VERSION}: ${ARDUINO_SDK_PATH}") - - setup_arduino_size_script(ARDUINO_SIZE_SCRIPT) - set(ARDUINO_SIZE_SCRIPT ${ARDUINO_SIZE_SCRIPT} CACHE INTERNAL "Arduino Size Script") + ARDUINO_PLATFORMS + AVR_CORES_PATH + AVR_BOOTLOADERS_PATH + ARDUINO_LIBRARIES_PATH + AVR_BOARDS_PATH + AVR_PROGRAMMERS_PATH + ARDUINO_VERSION_PATH + ARDUINO_AVRDUDE_PROGRAM + ARDUINO_AVRDUDE_CONFIG_PATH + AVRSIZE_PROGRAM + ${ADDITIONAL_REQUIRED_VARS} + MSG "Invalid Arduino SDK path (${ARDUINO_SDK_PATH}).\n") #print_board_list() #print_programmer_list() set(ARDUINO_FOUND True CACHE INTERNAL "Arduino Found") mark_as_advanced( - ARDUINO_CORES_PATH - ARDUINO_VARIANTS_PATH - ARDUINO_BOOTLOADERS_PATH + AVR_CORES_PATH + AVR_VARIANTS_PATH + AVR_BOOTLOADERS_PATH ARDUINO_LIBRARIES_PATH - ARDUINO_BOARDS_PATH - ARDUINO_PROGRAMMERS_PATH + AVR_BOARDS_PATH + AVR_PROGRAMMERS_PATH ARDUINO_VERSION_PATH - ARDUINO_AVRDUDE_FLAGS ARDUINO_AVRDUDE_PROGRAM ARDUINO_AVRDUDE_CONFIG_PATH - ARDUINO_OBJCOPY_EEP_FLAGS - ARDUINO_OBJCOPY_HEX_FLAGS AVRSIZE_PROGRAM) endif() +# Set some predefined variable values as defined in +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5-3rd-party-Hardware-specification + +set(runtime.ide.path ${ARDUINO_SDK_PATH} CACHE INTERNAL "") +set(runtime.tools.avr-gcc.path "${ARDUINO_SDK_PATH}/hardware/tools/avr" CACHE INTERNAL "") +set(runtime.tools.avrdude.path "${ARDUINO_SDK_PATH}/hardware/tools/avr" CACHE INTERNAL "") +set(runtime.tools.arduinoOTA.path "${ARDUINO_SDK_PATH}/hardware/tools/avr" CACHE INTERNAL "") + +#TODO Fixme for windows +set(runtime.os "linux" CACHE INTERNAL "") + +if(ARDUINO_SDK_VERSION MATCHES "([0-9]+)[.]([0-9]+)[.]([0-9]+)") + string(REPLACE "." "" ARDUINO_VERSION_DEFINE "${ARDUINO_SDK_VERSION}") # Normalize version (remove all periods) + set(ARDUINO_VERSION_DEFINE "") + if(CMAKE_MATCH_1 GREATER 0) + set(ARDUINO_VERSION_DEFINE "${CMAKE_MATCH_1}") + endif() + 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() + if(CMAKE_MATCH_3 GREATER 10) + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}${CMAKE_MATCH_3}") + else() + set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}0${CMAKE_MATCH_3}") + endif() +else() + message("Invalid Arduino SDK Version (${ARDUINO_SDK_VERSION})") +endif() + +set(runtime.ide.version ${ARDUINO_VERSION_DEFINE} CACHE INTERNAL "") +set(upload.verbose "-V" CACHE INTERNAL "") +set(program.verbose "-V" CACHE INTERNAL "") +set(bootloader.verbose "-V" CACHE INTERNAL "") +set(erase.verbose "-V" CACHE INTERNAL "") + + +if(ARDUINO_SDK_VERSION VERSION_LESS 1.5) + set(ARDUINO_PLATFORM "AVR") +else() + if(NOT ARDUINO_PLATFORM) + set(ARDUINO_PLATFORM "AVR") + endif() +endif() diff --git a/cmake/Platform/size_script.py b/cmake/Platform/size_script.py new file mode 100644 index 0000000..31dc37d --- /dev/null +++ b/cmake/Platform/size_script.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + + +from __future__ import print_function +import sys + +import argparse +import subprocess +import re + +#print(sys.argv) + +def eprint(*args, **kwargs): + print(*args, file=sys.stderr, **kwargs) + +parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter) + +parser.add_argument('-c', '--cmd', + type=str, + help='The command of the size script') + +parser.add_argument('-p', '--param', + type=str, + help='The parameters for the size script') + +parser.add_argument('-r', '--regex', + type=str, + default=None, + help='The value of recipe.size.regex') + +parser.add_argument('-rd', '--regex-data', + dest="regex_data", + type=str, + default=None, + help='The value of recipe.size.regex.data') + +parser.add_argument('-re', '--regex-eeprom', + dest="regex_eeprom", + type=str, + default=None, + help='The value of recipe.size.regex.eeprom') + +parser.add_argument('-s', '--max-size', + type=str, + dest="max_size", + default=None, + help='Maximum allowed upload size to the dram. See upload.maximum_size') + +parser.add_argument('-sd', '--max-size-data', + type=str, + dest="max_size_data", + default=None, + help='Maximum allowed data size to the dram. See upload.maximum_data_size') + +parser.add_argument('-sf', '--max-size-flash', + type=str, + dest="max_size_flash", + default=None, + help='Maximum allowed flash size. See build.flash_size') + +args = parser.parse_args() +m = re.search(r"^[\"'](.*)[\"']$", args.param) +if m: + args.param = m.group(1) +args.param = args.param.replace("\\","") +output = subprocess.check_output(args.cmd + " " + args.param, shell=True) + +#print("Output:\n" + output + "\n\n") + +#args.regex = args.regex.replace('\'','') +#args.regex_data = args.regex_data.replace('\'','') +#args.regex_eeprom = args.regex_eeprom.replace('\'','') + +size_complete = 0 +if args.regex and args.regex != "": + nums = re.findall(args.regex + "", output, re.MULTILINE) + if nums: + size_complete = sum(map(int, nums)) + else: + print(output) + exit(0) + +size_data = 0 +if args.regex_data and args.regex_data != "": + nums = re.findall(args.regex_data + "", output, re.MULTILINE) + if nums: + size_data = sum(map(int, nums)) + +size_eeprom = 0 +if args.regex_eeprom and args.regex_eeprom != "": + nums = re.findall(args.regex_eeprom + "", output, re.MULTILINE) + if nums: + size_eeprom = sum(map(int, nums)) + + +def human_readable_to_bytes(size): + """Given a human-readable byte string (e.g. 2G, 10GB, 30MB, 20KB), + return the number of bytes. Will return 0 if the argument has + unexpected form. + """ + if size == "": + return 0 + if (size[-1] == 'B'): + size = size[:-1] + if (size.isdigit()): + bytes = int(size) + else: + bytes = size[:-1] + unit = size[-1] + if (bytes.isdigit()): + bytes = int(bytes) + if (unit == 'G'): + bytes *= 1073741824 + elif (unit == 'M'): + bytes *= 1048576 + elif (unit == 'K'): + bytes *= 1024 + else: + bytes = 0 + else: + bytes = 0 + return bytes + +def sizeof_fmt(num, suffix='B'): + for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']: + if abs(num) < 1024.0: + return "%3.1f%s%s" % (num, unit, suffix) + num /= 1024.0 + return "%.1f%s%s" % (num, 'Yi', suffix) + +max_size = human_readable_to_bytes(args.max_size) +max_size_data = human_readable_to_bytes(args.max_size_data) +max_size_flash = human_readable_to_bytes(args.max_size_flash) + +totalSizeStr = "Firmware size: \t{} bytes".format(size_complete) +if max_size > 0: + totalSizeStr += " \t({:.1f}%)".format(size_complete/float(max_size)*100.0) + if size_complete/float(max_size) > 1: + eprint("\nWARNING: Firmware size may not fit!\n") +print(totalSizeStr) + +if size_data > 0: + dataSizeStr = "Data size: \t\t{} bytes".format(size_data) + if max_size_data > 0: + dataSizeStr += " \t({:.1f}%)".format(size_data/float(max_size_data)*100.0) + if size_data/float(max_size_data) > 1: + eprint("\nWARNING: Data size may not fit!\n") + print(dataSizeStr) + +if size_eeprom > 0: + eepromSizeStr = "EEPROM size: \t\t{} bytes".format(size_eeprom) + print(eepromSizeStr) diff --git a/example/Blink/Blink.ino b/example/Blink/Blink.ino deleted file mode 100644 index acc2285..0000000 --- a/example/Blink/Blink.ino +++ /dev/null @@ -1,26 +0,0 @@ -/* - Blink - Turns on an LED on for one second, then off for one second, repeatedly. - - This example code is in the public domain. - */ - -#include "config.h" - -Test1 a; - -void setup() { - // initialize the digital pin as an output. - // Pin 13 has an LED connected on most Arduino boards: - pinMode(13, OUTPUT); - /* - This is a weird comment - //*/ -} - -void loop() { - digitalWrite(13, HIGH); // set the LED on - delay(1000); // wait for a second - digitalWrite(13, LOW); // set the LED off - delay(1000); // wait for a second -} diff --git a/example/Blink/config.h b/example/Blink/config.h deleted file mode 100644 index 453c34a..0000000 --- a/example/Blink/config.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef CONFIG_H -#define CONFIG_H -class Test1 { -}; -#endif diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 2302e27..66b6504 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -1,101 +1,27 @@ -# This configuration file outlines some of the ways Arduino CMake -# can be used. For a detailed explenation of all the options please -# reade README.rst. +# ESP32 needs some special compilers. Set them here +SET(CMAKE_C_COMPILER "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin/avr-gcc") +SET(CMAKE_CXX_COMPILER "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin/avr-g++") +SET(CMAKE_AR "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin/avr-gcc-ar") +SET(CMAKE_RANLIB "${ARDUINO_SDK_PATH}/hardware/tools/avr/bin/avr-gcc-ranlib") -set(ARDUINO_DEFAULT_BOARD diecimila) # Default Board ID, when not specified -set(ARDUINO_DEFAULT_PORT /dev/ttyUSB0) # Default Port, when not specified +# Set a variable for commands below +set(PROJECT_NAME example) -#====================================================================# -# master_writer example from Wire library -#====================================================================# -generate_arduino_example(wire_example - LIBRARY Wire - EXAMPLE master_writer) +# Define your project and language +project(${PROJECT_NAME}) -# Alternative: by vairables -#set(wire_example_LIBRARY Wire) -#set(wire_example_EXAMPLE master_writer) -# -#generate_arduino_example(wire_example) +set(${PROJECT_NAME}_BOARD pro) +# Define the source code +set(${PROJECT_NAME}_SRCS example.cpp) +# Define the port for uploading code to the Arduino +set(${PROJECT_NAME}_PORT COM6) -#====================================================================# -# Original blink sketch (from Arduino SDK examples) -#====================================================================# -# Some installations have renamed the example directories -if (EXISTS "${ARDUINO_SDK_PATH}/examples/01.Basics/Blink") - set(BLINK_SKETCH "${ARDUINO_SDK_PATH}/examples/01.Basics/Blink") -else() - set(BLINK_SKETCH "${ARDUINO_SDK_PATH}/examples/1.Basics/Blink") -endif() +set(${PROJECT_NAME}_CPU 16MHzatmega328) -generate_arduino_firmware(blink_original - SKETCH "${BLINK_SKETCH}" - PORT /dev/ttyACM0 - SERIAL picocom @SERIAL_PORT@ - BOARD uno) +# Command to generate code arduino firmware (.hex file) +generate_arduino_firmware(${PROJECT_NAME}) -# Alternative: by variables -#set(blink_original_SKETCH "${BLINK_SKETCH}") -#set(blink_original_PORT /dev/ttyACM) -#set(blink_original_SERIAL picocom @SERIAL_PORT@) -#set(blink_original_BOARD uno) -# -#generate_arduino_firmware(blink_original) - - - - -#====================================================================# -# Bundled blink sketch example -#====================================================================# -generate_arduino_firmware(blink_bundled - SKETCH Blink - PROGRAMMER usbtinyisp - NO_AUTOLIBS) - -# Alternative: by variables -#set(blink_bundled_SKETCH Blink) -#set(blink_bundled_PROGRAMMER usbtinyisp) -#set(blink_bundled_NO_AUTOLIBS true) -# -#generate_arduino_firmware(blink_bundled) - - - - -#====================================================================# -# Advanced static library exmaple -#====================================================================# -generate_arduino_library(blink_lib - SRCS blink_lib.cpp - HDRS blink_lib.h - BOARD uno) - -# Alternative: by variables -#set(blink_lib_SRCS blink_lib.cpp) -#set(blink_lib_HDRS blink_lib.h) -#set(blink_lib_BOARD uno) -# -#generate_arduino_library(blink_lib) - - - - -#====================================================================# -# Advanced firwmare example -#====================================================================# -generate_arduino_firmware(blink - SRCS blink.cpp - LIBS blink_lib - BOARD uno) - -# Alternative: by variables -#set(blink_SRCS blink.cpp) -#set(blink_LIBS blink_lib) -#set(blink_BOARD uno) -# -#generate_arduino_firmware(blink) diff --git a/example/blink.cpp b/example/blink.cpp deleted file mode 100644 index f04c53c..0000000 --- a/example/blink.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - Blink - Turns on an LED on for one second, then off for one second, repeatedly. - Example uses a static library to show off generate_arduino_library(). - - This example code is in the public domain. - */ -#if ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#include "blink_lib.h" - -void setup() { - blink_setup(); // Setup for blinking -} - -void loop() { - blink(1000); // Blink for a second -} diff --git a/example/blink_lib.cpp b/example/blink_lib.cpp deleted file mode 100644 index 9783a10..0000000 --- a/example/blink_lib.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#if ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -#include "blink_lib.h" - -void blink_setup(uint8_t pin) { - pinMode(pin, OUTPUT); -} - - -void blink(unsigned long duration, uint8_t pin) { - digitalWrite(pin, HIGH); // set the LED on - delay(duration); // wait for a second - digitalWrite(pin, LOW); // set the LED off - delay(duration); // wait for a second -} diff --git a/example/blink_lib.h b/example/blink_lib.h deleted file mode 100644 index 8f5a377..0000000 --- a/example/blink_lib.h +++ /dev/null @@ -1,17 +0,0 @@ -#include - -/** - * Setup for blinking. - * - * @param pin - pin number - **/ -void blink_setup(uint8_t pin=13); - - -/** - * Blink a single time for the specified duration. - * - * @param duration - duration in miliseconds - * @param pin - pin number - **/ -void blink(unsigned long duration, uint8_t pin=13); diff --git a/example/example.cpp b/example/example.cpp new file mode 100644 index 0000000..797a864 --- /dev/null +++ b/example/example.cpp @@ -0,0 +1,23 @@ +#include "Arduino.h" + +#define LED_PIN 13 + +void setup() { + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + Serial.begin(9600); +} + +void loop() { + Serial.println("Example arduino project in CLion"); + + for (int i = 0; i < 2; i++) { + digitalWrite(LED_PIN, HIGH); + delay(100); + digitalWrite(LED_PIN, LOW); + delay(100); + } + + delay(1000); +} diff --git a/example_ap/CMakeLists.txt b/example_ap/CMakeLists.txt new file mode 100644 index 0000000..cc63aa5 --- /dev/null +++ b/example_ap/CMakeLists.txt @@ -0,0 +1,36 @@ +# ESP32 needs some special compilers. Set them here +SET(CMAKE_C_COMPILER "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc") +SET(CMAKE_C_COMPILER_WORKS 1) +SET(CMAKE_CXX_COMPILER "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++") +SET(CMAKE_CXX_COMPILER_WORKS 1) +SET(CMAKE_AR "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-ar") +SET(CMAKE_RANLIB "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-ranlib") + + +# Set a variable for commands below +set(PROJECT_NAME example_ap) + +# Define your project and language +project(${PROJECT_NAME}) + +set(${PROJECT_NAME}_BOARD featheresp32) + +# Define the source code +set(${PROJECT_NAME}_SRCS wifi_ap.cpp aes.c) + +# Define the port for uploading code to the Arduino +set(${PROJECT_NAME}_PORT /dev/ttyUSB0) + +# Select a specific upload speed for the board +set(${${PROJECT_NAME}_BOARD}.upload.speed 921600) + +# Select a specific flash frequence for the board +set(${${PROJECT_NAME}_BOARD}.build.flash_freq 80m) + + +set(${PROJECT_NAME}_ARDLIBS WiFi) +set(${PROJECT_NAME}_ARDLIBS_PATH ${ESP32_LIBRARIES_PATH}) +set(${PROJECT_NAME}_LIBS esp32 wpa_supplicant lwip) + +# Command to generate code arduino firmware (.hex file) +generate_arduino_firmware(${PROJECT_NAME}) diff --git a/example_ap/aes.c b/example_ap/aes.c new file mode 100644 index 0000000..59ff4cd --- /dev/null +++ b/example_ap/aes.c @@ -0,0 +1,390 @@ +/** + * \brief AES block cipher, ESP32 hardware accelerated version + * Based on mbedTLS FIPS-197 compliant version. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * Additions Copyright (C) 2016-2017, Espressif Systems (Shanghai) PTE Ltd + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +// hardcoded since somehow the quotes are remove from the value +#define MBEDTLS_CONFIG_FILE "mbedtls/esp_config.h" + +#include +#include "mbedtls/aes.h" +#include "hwcrypto/aes.h" +#include "soc/dport_reg.h" +#include "soc/hwcrypto_reg.h" +#include + +#include + +#include "soc/cpu.h" +#include + + +/* AES uses a spinlock mux not a lock as the underlying block operation + only takes 208 cycles (to write key & compute block), +600 cycles + for DPORT protection but +3400 cycles again if you use a full sized lock. + + For CBC, CFB, etc. this may mean that interrupts are disabled for a longer + period of time for bigger lengths. However at the moment this has to happen + anyway due to DPORT protection... +*/ +static portMUX_TYPE aes_spinlock = portMUX_INITIALIZER_UNLOCKED; + +void esp_aes_acquire_hardware( void ) +{ + /* newlib locks lazy initialize on ESP-IDF */ + portENTER_CRITICAL(&aes_spinlock); + + DPORT_STALL_OTHER_CPU_START(); + { + /* Enable AES hardware */ + _DPORT_REG_SET_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES); + /* Clear reset on digital signature & secure boot units, + otherwise AES unit is held in reset also. */ + _DPORT_REG_CLR_BIT(DPORT_PERI_RST_EN_REG, + DPORT_PERI_EN_AES + | DPORT_PERI_EN_DIGITAL_SIGNATURE + | DPORT_PERI_EN_SECUREBOOT); + } + DPORT_STALL_OTHER_CPU_END(); +} + +void esp_aes_release_hardware( void ) +{ + DPORT_STALL_OTHER_CPU_START(); + { + /* Disable AES hardware */ + _DPORT_REG_SET_BIT(DPORT_PERI_RST_EN_REG, DPORT_PERI_EN_AES); + /* Don't return other units to reset, as this pulls + reset on RSA & SHA units, respectively. */ + _DPORT_REG_CLR_BIT(DPORT_PERI_CLK_EN_REG, DPORT_PERI_EN_AES); + } + DPORT_STALL_OTHER_CPU_END(); + + portEXIT_CRITICAL(&aes_spinlock); +} + +void esp_aes_init( esp_aes_context *ctx ) +{ + bzero( ctx, sizeof( esp_aes_context ) ); +} + +void esp_aes_free( esp_aes_context *ctx ) +{ + if ( ctx == NULL ) { + return; + } + + bzero( ctx, sizeof( esp_aes_context ) ); +} + +/* + * AES key schedule (same for encryption or decryption, as hardware handles schedule) + * + */ +int esp_aes_setkey( esp_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + if (keybits != 128 && keybits != 192 && keybits != 256) { + return MBEDTLS_ERR_AES_INVALID_KEY_LENGTH; + } + ctx->key_bytes = keybits / 8; + memcpy(ctx->key, key, ctx->key_bytes); + return 0; +} + +/* + * Helper function to copy key from esp_aes_context buffer + * to hardware key registers. + * + * Call only while holding esp_aes_acquire_hardware(). + */ +static inline void esp_aes_setkey_hardware( esp_aes_context *ctx, int mode) +{ + const uint32_t MODE_DECRYPT_BIT = 4; + unsigned mode_reg_base = (mode == ESP_AES_ENCRYPT) ? 0 : MODE_DECRYPT_BIT; + + memcpy((uint32_t *)AES_KEY_BASE, ctx->key, ctx->key_bytes); + DPORT_REG_WRITE(AES_MODE_REG, mode_reg_base + ((ctx->key_bytes / 8) - 2)); +} + +/* Run a single 16 byte block of AES, using the hardware engine. + * + * Call only while holding esp_aes_acquire_hardware(). + */ +static inline void esp_aes_block(const void *input, void *output) +{ + const uint32_t *input_words = (const uint32_t *)input; + uint32_t *output_words = (uint32_t *)output; + uint32_t *mem_block = (uint32_t *)AES_TEXT_BASE; + + for(int i = 0; i < 4; i++) { + mem_block[i] = input_words[i]; + } + + DPORT_REG_WRITE(AES_START_REG, 1); + + DPORT_STALL_OTHER_CPU_START(); + { + while (_DPORT_REG_READ(AES_IDLE_REG) != 1) { } + for (int i = 0; i < 4; i++) { + output_words[i] = mem_block[i]; + } + } + DPORT_STALL_OTHER_CPU_END(); +} + +/* + * AES-ECB block encryption + */ +void esp_aes_encrypt( esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + esp_aes_acquire_hardware(); + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + esp_aes_block(input, output); + esp_aes_release_hardware(); +} + +/* + * AES-ECB block decryption + */ + +void esp_aes_decrypt( esp_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + esp_aes_acquire_hardware(); + esp_aes_setkey_hardware(ctx, ESP_AES_DECRYPT); + esp_aes_block(input, output); + esp_aes_release_hardware(); +} + + +/* + * AES-ECB block encryption/decryption + */ +int esp_aes_crypt_ecb( esp_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + esp_aes_acquire_hardware(); + esp_aes_setkey_hardware(ctx, mode); + esp_aes_block(input, output); + esp_aes_release_hardware(); + + return 0; +} + + +/* + * AES-CBC buffer encryption/decryption + */ +int esp_aes_crypt_cbc( esp_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + uint32_t *output_words = (uint32_t *)output; + const uint32_t *input_words = (const uint32_t *)input; + uint32_t *iv_words = (uint32_t *)iv; + unsigned char temp[16]; + + if ( length % 16 ) { + return ( ERR_ESP_AES_INVALID_INPUT_LENGTH ); + } + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, mode); + + if ( mode == ESP_AES_DECRYPT ) { + while ( length > 0 ) { + memcpy(temp, input_words, 16); + esp_aes_block(input_words, output_words); + + for ( i = 0; i < 4; i++ ) { + output_words[i] = output_words[i] ^ iv_words[i]; + } + + memcpy( iv_words, temp, 16 ); + + input_words += 4; + output_words += 4; + length -= 16; + } + } else { // ESP_AES_ENCRYPT + while ( length > 0 ) { + + for ( i = 0; i < 4; i++ ) { + output_words[i] = input_words[i] ^ iv_words[i]; + } + + esp_aes_block(output_words, output_words); + memcpy( iv_words, output_words, 16 ); + + input_words += 4; + output_words += 4; + length -= 16; + } + } + + esp_aes_release_hardware(); + + return 0; +} + +/* + * AES-CFB128 buffer encryption/decryption + */ +int esp_aes_crypt_cfb128( esp_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + + if ( mode == ESP_AES_DECRYPT ) { + while ( length-- ) { + if ( n == 0 ) { + esp_aes_block(iv, iv ); + } + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } else { + while ( length-- ) { + if ( n == 0 ) { + esp_aes_block(iv, iv ); + } + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + esp_aes_release_hardware(); + + return 0; +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int esp_aes_crypt_cfb8( esp_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + + while ( length-- ) { + memcpy( ov, iv, 16 ); + esp_aes_block(iv, iv); + + if ( mode == ESP_AES_DECRYPT ) { + ov[16] = *input; + } + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if ( mode == ESP_AES_ENCRYPT ) { + ov[16] = c; + } + + memcpy( iv, ov + 1, 16 ); + } + + esp_aes_release_hardware(); + + return 0; +} + +/* + * AES-CTR buffer encryption/decryption + */ +int esp_aes_crypt_ctr( esp_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + esp_aes_acquire_hardware(); + + esp_aes_setkey_hardware(ctx, ESP_AES_ENCRYPT); + + while ( length-- ) { + if ( n == 0 ) { + esp_aes_block(nonce_counter, stream_block); + + for ( i = 16; i > 0; i-- ) + if ( ++nonce_counter[i - 1] != 0 ) { + break; + } + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + esp_aes_release_hardware(); + + return 0; +} diff --git a/example_ap/wifi_ap.cpp b/example_ap/wifi_ap.cpp new file mode 100644 index 0000000..1492d95 --- /dev/null +++ b/example_ap/wifi_ap.cpp @@ -0,0 +1,126 @@ +/* + WiFi Web Server LED Blink + + A simple web server that lets you blink an LED via the web. + This sketch will print the IP address of your WiFi Shield (once connected) + to the Serial monitor. From there, you can open that address in a web browser + to turn on and off the LED on pin 5. + + If the IP address of your shield is yourAddress: + http://yourAddress/H turns the LED on + http://yourAddress/L turns it off + + This example is written for a network using WPA encryption. For + WEP or WPA, change the Wifi.begin() call accordingly. + + Circuit: + * WiFi shield attached + * LED attached to pin 5 + + created for arduino 25 Nov 2012 + by Tom Igoe + +ported for sparkfun esp32 +31.01.2017 by Jan Hendrik Berlin + + */ + +#include "WiFi.h" + +const char* ssid = "your_ssid"; +const char* password = "your_pwd"; + +WiFiServer server(80); + +void setup() +{ + Serial.begin(115200); + pinMode(5, OUTPUT); // set the LED pin mode + for (int i = 0; i < 5; i++) { + digitalWrite(5, HIGH); + delay(1000); + digitalWrite(5, LOW); + delay(1000); + } + + // We start by connecting to a WiFi network + + Serial.println(); + Serial.println(); + Serial.print("Connecting to "); + Serial.println(ssid); + + WiFi.begin(ssid, password); + + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + } + + Serial.println(""); + Serial.println("WiFi connected."); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + + Serial.flush(); + + server.begin(); + +} + +int value = 0; + +void loop(){ + + + WiFiClient client = server.available(); // listen for incoming clients + + + + if (client) { // if you get a client, + Serial.println("New Client."); // print a message out the serial port + String currentLine = ""; // make a String to hold incoming data from the client + while (client.connected()) { // loop while the client's connected + if (client.available()) { // if there's bytes to read from the client, + char c = client.read(); // read a byte, then + Serial.write(c); // print it out the serial monitor + if (c == '\n') { // if the byte is a newline character + + // if the current line is blank, you got two newline characters in a row. + // that's the end of the client HTTP request, so send a response: + if (currentLine.length() == 0) { + // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) + // and a content-type so the client knows what's coming, then a blank line: + client.println("HTTP/1.1 200 OK"); + client.println("Content-type:text/html"); + client.println(); + + // the content of the HTTP response follows the header: + client.print("Click here to turn the LED on pin 5 on.
"); + client.print("Click here to turn the LED on pin 5 off.
"); + + // The HTTP response ends with another blank line: + client.println(); + // break out of the while loop: + break; + } else { // if you got a newline, then clear currentLine: + currentLine = ""; + } + } else if (c != '\r') { // if you got anything else but a carriage return character, + currentLine += c; // add it to the end of the currentLine + } + + // Check to see if the client request was "GET /H" or "GET /L": + if (currentLine.endsWith("GET /H")) { + digitalWrite(5, HIGH); // GET /H turns the LED on + } + if (currentLine.endsWith("GET /L")) { + digitalWrite(5, LOW); // GET /L turns the LED off + } + } + } + // close the connection: + client.stop(); + Serial.println("Client Disconnected."); + } +} \ No newline at end of file diff --git a/example_esp32/CMakeLists.txt b/example_esp32/CMakeLists.txt new file mode 100644 index 0000000..7dfac4a --- /dev/null +++ b/example_esp32/CMakeLists.txt @@ -0,0 +1,31 @@ +# ESP32 needs some special compilers. Set them here +SET(CMAKE_C_COMPILER "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-gcc") +SET(CMAKE_C_COMPILER_WORKS 1) +SET(CMAKE_CXX_COMPILER "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-g++") +SET(CMAKE_CXX_COMPILER_WORKS 1) +SET(CMAKE_AR "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-ar") +SET(CMAKE_RANLIB "${ARDUINO_SDK_PATH}/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/xtensa-esp32-elf-ranlib") + + +# Set a variable for commands below +set(PROJECT_NAME example_esp32) + +# Define your project and language +project(${PROJECT_NAME}) + +set(${PROJECT_NAME}_BOARD featheresp32) + +# Define the source code +set(${PROJECT_NAME}_SRCS example_esp32.cpp) + +# Define the port for uploading code to the Arduino +set(${PROJECT_NAME}_PORT /dev/ttyUSB2) + +# Select a specific upload speed for the board +set(${${PROJECT_NAME}_BOARD}.upload.speed 921600) + +# Select a specific flash frequence for the board +set(${${PROJECT_NAME}_BOARD}.build.flash_freq 80m) + +# Command to generate code arduino firmware (.hex file) +generate_arduino_firmware(${PROJECT_NAME}) diff --git a/example_esp32/example_esp32.cpp b/example_esp32/example_esp32.cpp new file mode 100644 index 0000000..d492b31 --- /dev/null +++ b/example_esp32/example_esp32.cpp @@ -0,0 +1,24 @@ +#include "Arduino.h" + +#define LED_PIN 23 + +void setup() { + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + Serial.begin(9600); + Serial.println("Example arduino start"); +} + +void loop() { + Serial.println("loop"); + + for (int i = 0; i < 2; i++) { + digitalWrite(LED_PIN, HIGH); + delay(1000); + digitalWrite(LED_PIN, LOW); + delay(1000); + } + + delay(1000); +}