├── .gitignore ├── CMakeLists.txt ├── MagSpoof.cpp ├── MagSpoof.h ├── README.md ├── cmake ├── ArduinoToolchain.cmake └── Platform │ └── Arduino.cmake ├── main.ino └── pictures ├── 20190921_151556.jpg └── 20190921_151603.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | cmake-build* 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.4) 2 | set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/ArduinoToolchain.cmake) 3 | set(PROJECT_NAME magspoof) 4 | project(${PROJECT_NAME}) 5 | 6 | set(${CMAKE_PROJECT_NAME}_BOARD nano328) 7 | set(${CMAKE_PROJECT_NAME}_PORT /dev/ttyUSB3) 8 | 9 | #nano 10 | #set(${CMAKE_PROJECT_NAME}_BOARD nano328) 11 | #set(${CMAKE_PROJECT_NAME}_PORT /dev/ttyUSB0) 12 | 13 | #mega 14 | #set(${CMAKE_PROJECT_NAME}_BOARD mega2560) 15 | #set(${CMAKE_PROJECT_NAME}_PORT /dev/ttyACM0) 16 | 17 | # /usr/share/arduino/hardware/arduino/boards.txt 18 | 19 | 20 | enable_language(ASM) 21 | set(${CMAKE_PROJECT_NAME}_ALL_SRCS main.ino MagSpoof.cpp) 22 | set(${CMAKE_PROJECT_NAME}_SKETCH main.ino) 23 | generate_arduino_firmware(${CMAKE_PROJECT_NAME}) 24 | -------------------------------------------------------------------------------- /MagSpoof.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "MagSpoof.h" 3 | 4 | MagSpoof::MagSpoof(uint8_t pinA, uint8_t pinB, uint8_t pinEnable, uint8_t clock, BPC bpc, Parity parity) 5 | : m_pinA(pinA) 6 | , m_pinB(pinB) 7 | , m_pinEnable(pinEnable) 8 | , m_clock(clock) 9 | , m_bpc(bpc) 10 | , m_parity(parity) 11 | { 12 | } 13 | 14 | void MagSpoof::setup() 15 | { 16 | pinMode(m_pinA, OUTPUT); 17 | pinMode(m_pinB, OUTPUT); 18 | pinMode(m_pinEnable, OUTPUT); 19 | } 20 | 21 | char MagSpoof::convertChar(char c) 22 | { 23 | switch (m_bpc) 24 | { 25 | case BPC4: 26 | case BPC5: 27 | return c - '0'; 28 | case BPC6: 29 | case BPC7: 30 | return c - ' '; 31 | default: 32 | return c; 33 | } 34 | } 35 | 36 | void MagSpoof::playBit(int sendBit, uint8_t& dir) 37 | { 38 | dir ^= 1; 39 | digitalWrite(m_pinA, dir); 40 | digitalWrite(m_pinB, !dir); 41 | delayMicroseconds(m_clock); 42 | 43 | if (sendBit) 44 | { 45 | dir ^= 1; 46 | digitalWrite(m_pinA, dir); 47 | digitalWrite(m_pinB, !dir); 48 | } 49 | delayMicroseconds(m_clock); 50 | 51 | } 52 | 53 | void MagSpoof::playTrack(const char* track) 54 | { 55 | int tmp, crc, lrc = 0; 56 | uint8_t dir = 0; 57 | 58 | int bl = m_bpc - (m_bpc % 2); 59 | 60 | // enable H-bridge 61 | digitalWrite(m_pinEnable, HIGH); 62 | 63 | // First put out a bunch of leading zeros. 64 | // TODO 25 sounds arbitrary 65 | for (int i = 0; i < 25; i++) 66 | { 67 | playBit(0, dir); 68 | } 69 | 70 | // 71 | for (int i = 0; track[i] != '\0'; i++) 72 | { 73 | crc = 1; 74 | tmp = convertChar(track[i]); 75 | 76 | for (int j = 0; j < bl; j++) 77 | { 78 | crc ^= tmp & 1; 79 | lrc ^= (tmp & 1) << j; 80 | playBit(tmp & 1, dir); 81 | tmp >>= 1; 82 | } 83 | if (m_bpc % 2) 84 | { 85 | playBit(m_parity == Odd ? crc : !crc, dir); 86 | } 87 | } 88 | 89 | // finish calculating and send last "byte" (LRC) 90 | tmp = lrc; 91 | crc = 1; 92 | for (int j = 0; j < bl; j++) 93 | { 94 | crc ^= tmp & 1; 95 | playBit(tmp & 1, dir); 96 | tmp >>= 1; 97 | } 98 | if (m_bpc % 2) 99 | { 100 | playBit(m_parity == Odd ? crc : !crc, dir); 101 | } 102 | 103 | // finish with 0's 104 | // TODO 5 * 5 (25) sounds arbitrary 105 | for (int i = 0; i < 5 * 5; i++) 106 | { 107 | playBit(0, dir); 108 | } 109 | 110 | digitalWrite(m_pinA, LOW); 111 | digitalWrite(m_pinB, LOW); 112 | digitalWrite(m_pinEnable, LOW); 113 | 114 | } 115 | -------------------------------------------------------------------------------- /MagSpoof.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Resources and inspired from: 4 | // https://pe2bz.philpem.me.uk/Comm01/-%20Digital/-%20MagneticCards/Info-900-MagCardDecode/magcard.html 5 | // https://github.com/miaoski/magspoof/ 6 | // https://github.com/samyk/magspoof/ 7 | // https://github.com/joshlf/magspoof/ 8 | 9 | #include 10 | 11 | class MagSpoof 12 | { 13 | public: 14 | enum BPC 15 | { 16 | BPC7 = 7, 17 | BPC6 = 6, 18 | BPC5 = 5, 19 | BPC4 = 4, 20 | }; 21 | 22 | enum Parity 23 | { 24 | Odd, 25 | Even 26 | }; 27 | 28 | MagSpoof(uint8_t pinA, uint8_t pinB, uint8_t pinEnable, uint8_t clock, BPC bpc, Parity parity); 29 | 30 | void setup(); 31 | 32 | char convertChar(char c); 33 | 34 | void playBit(int sendBit, uint8_t& dir); 35 | 36 | void playTrack(const char* track); 37 | 38 | private: 39 | const uint8_t m_pinA; 40 | const uint8_t m_pinB; 41 | const uint8_t m_pinEnable; 42 | const uint32_t m_clock; 43 | const BPC m_bpc; 44 | const Parity m_parity; 45 | }; 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Magnetic card emulator 2 | 3 | ### Abstract 4 | 5 | This project emulates a magnetic card, wirelessly. 6 | 7 | A L293D is used to create a magnetic field and "trick" the reader, as if a card has been swiped. 8 | 9 | It is similar to what Samsung calls MST (Magnetic Secure Transmission), and uses for Samsung Pay. 10 | 11 | ### Prototype 12 | 13 | ![](pictures/20190921_151556.jpg) 14 | 15 | ![](pictures/20190921_151603.jpg) 16 | 17 | ### Software 18 | 19 | A basic example can be found in [main.ino](main.ino) 20 | 21 | Check [MagSpoof.h](MagSpoof.h) and [MagSpoof.cpp](MagSpoof.cpp) for implementation details. 22 | 23 | ### Hardware 24 | 25 | Here's the hardware *I* used. [Samy Kamkar](https://github.com/samyk/) also gives hardware references in his [repo](https://github.com/samyk/magspoof/). 26 | 27 | - Arduino Nano 28 | - [L293D](https://www.amazon.com/gp/product/B00ODQM8KC/) 29 | - [24 AWG Magnet Wire](https://www.amazon.co.uk/gp/product/B07GBQM27Y/) 30 | 31 | ### Sources and references: 32 | 33 | - [samyk/magspoof](https://github.com/samyk/magspoof/) (Original project) 34 | - [miaoski/magspoof](https://github.com/miaoski/magspoof/) 35 | - [joshlf/magspoof](https://github.com/joshlf/magspoof/) 36 | - https://pe2bz.philpem.me.uk/Comm01/-%20Digital/-%20MagneticCards/Info-900-MagCardDecode/magcard.html 37 | -------------------------------------------------------------------------------- /cmake/ArduinoToolchain.cmake: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | # Author: Tomasz Bogdal (QueezyTheGreat) 3 | # Home: https://github.com/queezythegreat/arduino-cmake 4 | # 5 | # This Source Code Form is subject to the terms of the Mozilla Public 6 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 | # You can obtain one at http://mozilla.org/MPL/2.0/. 8 | #=============================================================================# 9 | set(CMAKE_SYSTEM_NAME Arduino) 10 | 11 | set(CMAKE_C_COMPILER avr-gcc) 12 | set(CMAKE_CXX_COMPILER avr-g++) 13 | 14 | # Add current directory to CMake Module path automatically 15 | if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/Platform/Arduino.cmake) 16 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}) 17 | endif() 18 | 19 | #=============================================================================# 20 | # System Paths # 21 | #=============================================================================# 22 | if(UNIX) 23 | include(Platform/UnixPaths) 24 | if(APPLE) 25 | list(APPEND CMAKE_SYSTEM_PREFIX_PATH ~/Applications 26 | /Applications 27 | /Developer/Applications 28 | /sw # Fink 29 | /opt/local) # MacPorts 30 | endif() 31 | elseif(WIN32) 32 | include(Platform/WindowsPaths) 33 | endif() 34 | 35 | 36 | #=============================================================================# 37 | # Detect Arduino SDK # 38 | #=============================================================================# 39 | if(NOT ARDUINO_SDK_PATH) 40 | set(ARDUINO_PATHS) 41 | 42 | foreach(DETECT_VERSION_MAJOR 1) 43 | foreach(DETECT_VERSION_MINOR RANGE 5 0) 44 | list(APPEND ARDUINO_PATHS arduino-${DETECT_VERSION_MAJOR}.${DETECT_VERSION_MINOR}) 45 | foreach(DETECT_VERSION_PATCH RANGE 3 0) 46 | list(APPEND ARDUINO_PATHS arduino-${DETECT_VERSION_MAJOR}.${DETECT_VERSION_MINOR}.${DETECT_VERSION_PATCH}) 47 | endforeach() 48 | endforeach() 49 | endforeach() 50 | 51 | foreach(VERSION RANGE 23 19) 52 | list(APPEND ARDUINO_PATHS arduino-00${VERSION}) 53 | endforeach() 54 | 55 | if(UNIX) 56 | file(GLOB SDK_PATH_HINTS /usr/share/arduino* 57 | /opt/local/arduino* 58 | /opt/arduino* 59 | /usr/local/share/arduino*) 60 | elseif(WIN32) 61 | set(SDK_PATH_HINTS "C:\\Program Files\\Arduino" 62 | "C:\\Program Files (x86)\\Arduino" 63 | ) 64 | endif() 65 | list(SORT SDK_PATH_HINTS) 66 | list(REVERSE SDK_PATH_HINTS) 67 | endif() 68 | 69 | find_path(ARDUINO_SDK_PATH 70 | NAMES lib/version.txt 71 | PATH_SUFFIXES share/arduino 72 | Arduino.app/Contents/Java/ 73 | Arduino.app/Contents/Resources/Java/ 74 | ${ARDUINO_PATHS} 75 | HINTS ${SDK_PATH_HINTS} 76 | DOC "Arduino SDK path.") 77 | 78 | if(ARDUINO_SDK_PATH) 79 | list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr) 80 | list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${ARDUINO_SDK_PATH}/hardware/tools/avr/utils) 81 | else() 82 | message(FATAL_ERROR "Could not find Arduino SDK (set ARDUINO_SDK_PATH)!") 83 | endif() 84 | 85 | set(ARDUINO_CPUMENU) 86 | if(ARDUINO_CPU) 87 | set(ARDUINO_CPUMENU ".menu.cpu.${ARDUINO_CPU}") 88 | endif(ARDUINO_CPU) 89 | 90 | -------------------------------------------------------------------------------- /cmake/Platform/Arduino.cmake: -------------------------------------------------------------------------------- 1 | #=============================================================================# 2 | # generate_arduino_firmware(name 3 | # [BOARD board_id] 4 | # [SKETCH sketch_path | 5 | # SRCS src1 src2 ... srcN] 6 | # [HDRS hdr1 hdr2 ... hdrN] 7 | # [LIBS lib1 lib2 ... libN] 8 | # [PORT port] 9 | # [SERIAL serial_cmd] 10 | # [PROGRAMMER programmer_id] 11 | # [AFLAGS flags] 12 | # [NO_AUTOLIBS] 13 | # [MANUAL]) 14 | # 15 | #=============================================================================# 16 | # 17 | # generaters firmware and libraries for Arduino devices 18 | # 19 | # The arguments are as follows: 20 | # 21 | # name # The name of the firmware target [REQUIRED] 22 | # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] 23 | # SKETCH # Arduino sketch [must have SRCS or SKETCH] 24 | # SRCS # Sources [must have SRCS or SKETCH] 25 | # HDRS # Headers 26 | # LIBS # Libraries to link 27 | # ARDLIBS # Arduino libraries to link (Wire, Servo, SPI, etc) 28 | # PORT # Serial port (enables upload support) 29 | # SERIAL # Serial command for serial target 30 | # PROGRAMMER # Programmer id (enables programmer support) 31 | # AFLAGS # Avrdude flags for target 32 | # NO_AUTOLIBS # Disables Arduino library detection 33 | # MANUAL # (Advanced) Only use AVR Libc/Includes 34 | # 35 | # Here is a short example for a target named test: 36 | # 37 | # generate_arduino_firmware( 38 | # NAME test 39 | # SRCS test.cpp 40 | # test2.cpp 41 | # HDRS test.h test2.h 42 | # BOARD uno) 43 | # 44 | # Alternatively you can specify the option by variables: 45 | # 46 | # set(test_SRCS test.cpp test2.cpp) 47 | # set(test_HDRS test.h test2.h 48 | # set(test_BOARD uno) 49 | # 50 | # generate_arduino_firmware(test) 51 | # 52 | # All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). 53 | # 54 | #=============================================================================# 55 | # generate_avr_firmware(name 56 | # [BOARD board_id] 57 | # SRCS src1 src2 ... srcN] 58 | # [HDRS hdr1 hdr2 ... hdrN] 59 | # [LIBS lib1 lib2 ... libN] 60 | # [PORT port] 61 | # [SERIAL serial_cmd] 62 | # [PROGRAMMER programmer_id] 63 | # [AFLAGS flags]) 64 | #=============================================================================# 65 | # 66 | # generaters firmware and libraries for AVR devices 67 | # it simply calls generate_arduino_firmware() with NO_AUTOLIBS and MANUAL 68 | # 69 | # The arguments are as follows: 70 | # 71 | # name # The name of the firmware target [REQUIRED] 72 | # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] 73 | # SRCS # Sources [REQUIRED] 74 | # HDRS # Headers 75 | # LIBS # Libraries to link 76 | # PORT # Serial port (enables upload support) 77 | # SERIAL # Serial command for serial target 78 | # PROGRAMMER # Programmer id (enables programmer support) 79 | # AFLAGS # Avrdude flags for target 80 | # 81 | # Here is a short example for a target named test: 82 | # 83 | # generate_avr_firmware( 84 | # NAME test 85 | # SRCS test.cpp 86 | # test2.cpp 87 | # HDRS test.h test2.h 88 | # BOARD uno) 89 | # 90 | # Alternatively you can specify the option by variables: 91 | # 92 | # set(test_SRCS test.cpp test2.cpp) 93 | # set(test_HDRS test.h test2.h 94 | # set(test_BOARD uno) 95 | # 96 | # generate_avr_firmware(test) 97 | # 98 | # All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). 99 | # 100 | #=============================================================================# 101 | # generate_arduino_library(name 102 | # [BOARD board_id] 103 | # [SRCS src1 src2 ... srcN] 104 | # [HDRS hdr1 hdr2 ... hdrN] 105 | # [LIBS lib1 lib2 ... libN] 106 | # [NO_AUTOLIBS] 107 | # [MANUAL]) 108 | #=============================================================================# 109 | # generaters firmware and libraries for Arduino devices 110 | # 111 | # The arguments are as follows: 112 | # 113 | # name # The name of the firmware target [REQUIRED] 114 | # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] 115 | # SRCS # Sources [REQUIRED] 116 | # HDRS # Headers 117 | # LIBS # Libraries to link 118 | # NO_AUTOLIBS # Disables Arduino library detection 119 | # MANUAL # (Advanced) Only use AVR Libc/Includes 120 | # 121 | # Here is a short example for a target named test: 122 | # 123 | # generate_arduino_library( 124 | # NAME test 125 | # SRCS test.cpp 126 | # test2.cpp 127 | # HDRS test.h test2.h 128 | # BOARD uno) 129 | # 130 | # Alternatively you can specify the option by variables: 131 | # 132 | # set(test_SRCS test.cpp test2.cpp) 133 | # set(test_HDRS test.h test2.h 134 | # set(test_BOARD uno) 135 | # 136 | # generate_arduino_library(test) 137 | # 138 | # All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). 139 | # 140 | #=============================================================================# 141 | # generate_avr_library(name 142 | # [BOARD board_id] 143 | # [SRCS src1 src2 ... srcN] 144 | # [HDRS hdr1 hdr2 ... hdrN] 145 | # [LIBS lib1 lib2 ... libN]) 146 | #=============================================================================# 147 | # generaters firmware and libraries for AVR devices 148 | # it simply calls generate_arduino_library() with NO_AUTOLIBS and MANUAL 149 | # 150 | # The arguments are as follows: 151 | # 152 | # name # The name of the firmware target [REQUIRED] 153 | # BOARD # Board name (such as uno, mega2560, ...) [REQUIRED] 154 | # SRCS # Sources [REQUIRED] 155 | # HDRS # Headers 156 | # LIBS # Libraries to link 157 | # 158 | # Here is a short example for a target named test: 159 | # 160 | # generate_avr_library( 161 | # NAME test 162 | # SRCS test.cpp 163 | # test2.cpp 164 | # HDRS test.h test2.h 165 | # BOARD uno) 166 | # 167 | # Alternatively you can specify the option by variables: 168 | # 169 | # set(test_SRCS test.cpp test2.cpp) 170 | # set(test_HDRS test.h test2.h 171 | # set(test_BOARD uno) 172 | # 173 | # generate_avr_library(test) 174 | # 175 | # All variables need to be prefixed with the target name (${TARGET_NAME}_${OPTION}). 176 | # 177 | #=============================================================================# 178 | # generate_arduino_example(name 179 | # LIBRARY library_name 180 | # EXAMPLE example_name 181 | # [BOARD board_id] 182 | # [PORT port] 183 | # [SERIAL serial command] 184 | # [PORGRAMMER programmer_id] 185 | # [AFLAGS avrdude_flags]) 186 | #=============================================================================# 187 | # 188 | # name - The name of the library example [REQUIRED] 189 | # LIBRARY - Library name [REQUIRED] 190 | # EXAMPLE - Example name [REQUIRED] 191 | # BOARD - Board ID 192 | # PORT - Serial port [optional] 193 | # SERIAL - Serial command [optional] 194 | # PROGRAMMER - Programmer id (enables programmer support) 195 | # AFLAGS - Avrdude flags for target 196 | # 197 | # Creates a example from the specified library. 198 | # 199 | # 200 | #=============================================================================# 201 | # print_board_list() 202 | #=============================================================================# 203 | # 204 | # Print list of detected Arduino Boards. 205 | # 206 | #=============================================================================# 207 | # print_programmer_list() 208 | #=============================================================================# 209 | # 210 | # Print list of detected Programmers. 211 | # 212 | #=============================================================================# 213 | # print_programmer_settings(PROGRAMMER) 214 | #=============================================================================# 215 | # 216 | # PROGRAMMER - programmer id 217 | # 218 | # Print the detected Programmer settings. 219 | # 220 | #=============================================================================# 221 | # print_board_settings(ARDUINO_BOARD) 222 | #=============================================================================# 223 | # 224 | # ARDUINO_BOARD - Board id 225 | # 226 | # Print the detected Arduino board settings. 227 | # 228 | #=============================================================================# 229 | # register_hardware_platform(HARDWARE_PLATFORM_PATH) 230 | #=============================================================================# 231 | # 232 | # HARDWARE_PLATFORM_PATH - Hardware platform path 233 | # 234 | # Registers a Hardware Platform path. 235 | # See: http://code.google.com/p/arduino/wiki/Platforms 236 | # 237 | # This enables you to register new types of hardware platforms such as the 238 | # Sagnuino, without having to copy the files into your Arduion SDK. 239 | # 240 | # A Hardware Platform is a directory containing the following: 241 | # 242 | # HARDWARE_PLATFORM_PATH/ 243 | # |-- bootloaders/ 244 | # |-- cores/ 245 | # |-- variants/ 246 | # |-- boards.txt 247 | # `-- programmers.txt 248 | # 249 | # The board.txt describes the target boards and bootloaders. While 250 | # programmers.txt the programmer defintions. 251 | # 252 | # A good example of a Hardware Platform is in the Arduino SDK: 253 | # 254 | # ${ARDUINO_SDK_PATH}/hardware/arduino/ 255 | # 256 | #=============================================================================# 257 | # Configuration Options 258 | #=============================================================================# 259 | # 260 | # ARDUINO_SDK_PATH - Arduino SDK Path 261 | # ARDUINO_AVRDUDE_PROGRAM - Full path to avrdude programmer 262 | # ARDUINO_AVRDUDE_CONFIG_PATH - Full path to avrdude configuration file 263 | # 264 | # ARDUINO_C_FLAGS - C compiler flags 265 | # ARDUINO_CXX_FLAGS - C++ compiler flags 266 | # ARDUINO_LINKER_FLAGS - Linker flags 267 | # 268 | # ARDUINO_DEFAULT_BOARD - Default Arduino Board ID when not specified. 269 | # ARDUINO_DEFAULT_PORT - Default Arduino port when not specified. 270 | # ARDUINO_DEFAULT_SERIAL - Default Arduino Serial command when not specified. 271 | # ARDUINO_DEFAULT_PROGRAMMER - Default Arduino Programmer ID when not specified. 272 | # 273 | # 274 | # ARDUINO_FOUND - Set to True when the Arduino SDK is detected and configured. 275 | # ARDUINO_SDK_VERSION - Set to the version of the detected Arduino SDK (ex: 1.0) 276 | 277 | #=============================================================================# 278 | # Author: Tomasz Bogdal (QueezyTheGreat) 279 | # Home: https://github.com/queezythegreat/arduino-cmake 280 | # 281 | # This Source Code Form is subject to the terms of the Mozilla Public 282 | # License, v. 2.0. If a copy of the MPL was not distributed with this file, 283 | # You can obtain one at http://mozilla.org/MPL/2.0/. 284 | #=============================================================================# 285 | cmake_minimum_required(VERSION 2.8.5) 286 | include(CMakeParseArguments) 287 | 288 | 289 | 290 | 291 | 292 | 293 | #=============================================================================# 294 | # User Functions 295 | #=============================================================================# 296 | 297 | #=============================================================================# 298 | # [PUBLIC/USER] 299 | # 300 | # print_board_list() 301 | # 302 | # see documentation at top 303 | #=============================================================================# 304 | function(PRINT_BOARD_LIST) 305 | foreach(PLATFORM ${ARDUINO_PLATFORMS}) 306 | if(${PLATFORM}_BOARDS) 307 | message(STATUS "${PLATFORM} Boards:") 308 | print_list(${PLATFORM}_BOARDS) 309 | message(STATUS "") 310 | endif() 311 | endforeach() 312 | endfunction() 313 | 314 | #=============================================================================# 315 | # [PUBLIC/USER] 316 | # 317 | # print_programmer_list() 318 | # 319 | # see documentation at top 320 | #=============================================================================# 321 | function(PRINT_PROGRAMMER_LIST) 322 | foreach(PLATFORM ${ARDUINO_PLATFORMS}) 323 | if(${PLATFORM}_PROGRAMMERS) 324 | message(STATUS "${PLATFORM} Programmers:") 325 | print_list(${PLATFORM}_PROGRAMMERS) 326 | endif() 327 | message(STATUS "") 328 | endforeach() 329 | endfunction() 330 | 331 | #=============================================================================# 332 | # [PUBLIC/USER] 333 | # 334 | # print_programmer_settings(PROGRAMMER) 335 | # 336 | # see documentation at top 337 | #=============================================================================# 338 | function(PRINT_PROGRAMMER_SETTINGS PROGRAMMER) 339 | if(${PROGRAMMER}.SETTINGS) 340 | message(STATUS "Programmer ${PROGRAMMER} Settings:") 341 | print_settings(${PROGRAMMER}) 342 | endif() 343 | endfunction() 344 | 345 | # [PUBLIC/USER] 346 | # 347 | # print_board_settings(ARDUINO_BOARD) 348 | # 349 | # see documentation at top 350 | function(PRINT_BOARD_SETTINGS ARDUINO_BOARD) 351 | if(${ARDUINO_BOARD}.SETTINGS) 352 | message(STATUS "Arduino ${ARDUINO_BOARD} Board:") 353 | print_settings(${ARDUINO_BOARD}) 354 | endif() 355 | endfunction() 356 | 357 | #=============================================================================# 358 | # [PUBLIC/USER] 359 | # see documentation at top 360 | #=============================================================================# 361 | function(GENERATE_ARDUINO_LIBRARY INPUT_NAME) 362 | message(STATUS "Generating ${INPUT_NAME}") 363 | parse_generator_arguments(${INPUT_NAME} INPUT 364 | "NO_AUTOLIBS;MANUAL" # Options 365 | "BOARD" # One Value Keywords 366 | "SRCS;HDRS;LIBS" # Multi Value Keywords 367 | ${ARGN}) 368 | 369 | if(NOT INPUT_BOARD) 370 | set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) 371 | endif() 372 | if(NOT INPUT_MANUAL) 373 | set(INPUT_MANUAL FALSE) 374 | endif() 375 | required_variables(VARS INPUT_SRCS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") 376 | 377 | set(ALL_LIBS) 378 | set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) 379 | 380 | if(NOT INPUT_MANUAL) 381 | setup_arduino_core(CORE_LIB ${INPUT_BOARD}) 382 | endif() 383 | 384 | find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "") 385 | set(LIB_DEP_INCLUDES) 386 | foreach(LIB_DEP ${TARGET_LIBS}) 387 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${LIB_DEP}\"") 388 | endforeach() 389 | 390 | if(NOT ${INPUT_NO_AUTOLIBS}) 391 | setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "" "${LIB_DEP_INCLUDES}" "") 392 | endif() 393 | 394 | list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) 395 | 396 | add_library(${INPUT_NAME} ${ALL_SRCS}) 397 | 398 | get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${INPUT_BOARD} ${INPUT_MANUAL}) 399 | 400 | set_target_properties(${INPUT_NAME} PROPERTIES 401 | COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS} ${LIB_DEP_INCLUDES}" 402 | LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") 403 | 404 | target_link_libraries(${INPUT_NAME} ${ALL_LIBS} "-lc -lm") 405 | endfunction() 406 | 407 | #=============================================================================# 408 | # [PUBLIC/USER] 409 | # see documentation at top 410 | #=============================================================================# 411 | function(GENERATE_AVR_LIBRARY INPUT_NAME) 412 | message(STATUS "Generating ${INPUT_NAME}") 413 | parse_generator_arguments(${INPUT_NAME} INPUT 414 | "NO_AUTOLIBS;MANUAL" # Options 415 | "BOARD" # One Value Keywords 416 | "SRCS;HDRS;LIBS" # Multi Value Keywords 417 | ${ARGN}) 418 | 419 | if(NOT INPUT_BOARD) 420 | set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) 421 | endif() 422 | 423 | required_variables(VARS INPUT_SRCS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") 424 | 425 | if(INPUT_HDRS) 426 | set( INPUT_HDRS "SRCS ${INPUT_HDRS}" ) 427 | endif() 428 | if(INPUT_LIBS) 429 | set( INPUT_LIBS "LIBS ${INPUT_LIBS}" ) 430 | endif() 431 | 432 | if(INPUT_HDRS) 433 | list(INSERT INPUT_HDRS 0 "HDRS") 434 | endif() 435 | if(INPUT_LIBS) 436 | list(INSERT INPUT_LIBS 0 "LIBS") 437 | endif() 438 | 439 | 440 | generate_arduino_library( ${INPUT_NAME} 441 | NO_AUTOLIBS 442 | MANUAL 443 | BOARD ${INPUT_BOARD} 444 | SRCS ${INPUT_SRCS} 445 | ${INPUT_HDRS} 446 | ${INPUT_LIBS} ) 447 | 448 | endfunction() 449 | 450 | #=============================================================================# 451 | # [PUBLIC/USER] 452 | # see documentation at top 453 | #=============================================================================# 454 | function(GENERATE_ARDUINO_FIRMWARE INPUT_NAME) 455 | message(STATUS "Generating ${INPUT_NAME}") 456 | parse_generator_arguments(${INPUT_NAME} INPUT 457 | "NO_AUTOLIBS;MANUAL" # Options 458 | "BOARD;PORT;SKETCH;PROGRAMMER" # One Value Keywords 459 | "SERIAL;SRCS;HDRS;LIBS;ARDLIBS;AFLAGS" # Multi Value Keywords 460 | ${ARGN}) 461 | 462 | if(NOT INPUT_BOARD) 463 | set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) 464 | endif() 465 | if(NOT INPUT_PORT) 466 | set(INPUT_PORT ${ARDUINO_DEFAULT_PORT}) 467 | endif() 468 | if(NOT INPUT_SERIAL) 469 | set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) 470 | endif() 471 | if(NOT INPUT_PROGRAMMER) 472 | set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) 473 | endif() 474 | if(NOT INPUT_MANUAL) 475 | set(INPUT_MANUAL FALSE) 476 | endif() 477 | required_variables(VARS INPUT_BOARD MSG "must define for target ${INPUT_NAME}") 478 | 479 | set(ALL_LIBS) 480 | set(ALL_SRCS ${INPUT_SRCS} ${INPUT_HDRS}) 481 | set(LIB_DEP_INCLUDES) 482 | 483 | if(NOT INPUT_MANUAL) 484 | setup_arduino_core(CORE_LIB ${INPUT_BOARD}) 485 | endif() 486 | 487 | if(NOT "${INPUT_SKETCH}" STREQUAL "") 488 | get_filename_component(INPUT_SKETCH "${INPUT_SKETCH}" ABSOLUTE) 489 | setup_arduino_sketch(${INPUT_NAME} ${INPUT_SKETCH} ALL_SRCS) 490 | if (IS_DIRECTORY "${INPUT_SKETCH}") 491 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${INPUT_SKETCH}\"") 492 | else() 493 | get_filename_component(INPUT_SKETCH_PATH "${INPUT_SKETCH}" PATH) 494 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${INPUT_SKETCH_PATH}\"") 495 | endif() 496 | endif() 497 | 498 | required_variables(VARS ALL_SRCS MSG "must define SRCS or SKETCH for target ${INPUT_NAME}") 499 | 500 | find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "${INPUT_ARDLIBS}") 501 | foreach(LIB_DEP ${TARGET_LIBS}) 502 | arduino_debug_msg("Arduino Library: ${LIB_DEP}") 503 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${LIB_DEP}\" -I\"${LIB_DEP}/src\"") 504 | endforeach() 505 | 506 | if(NOT INPUT_NO_AUTOLIBS) 507 | setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "${INPUT_ARDLIBS}" "${LIB_DEP_INCLUDES}" "") 508 | foreach(LIB_INCLUDES ${ALL_LIBS_INCLUDES}) 509 | arduino_debug_msg("Arduino Library Includes: ${LIB_INCLUDES}") 510 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} ${LIB_INCLUDES}") 511 | endforeach() 512 | endif() 513 | 514 | list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) 515 | 516 | setup_arduino_target(${INPUT_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "" "${INPUT_MANUAL}") 517 | 518 | if(INPUT_PORT) 519 | setup_arduino_upload(${INPUT_BOARD} ${INPUT_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "${INPUT_AFLAGS}") 520 | endif() 521 | 522 | if(INPUT_SERIAL) 523 | setup_serial_target(${INPUT_NAME} "${INPUT_SERIAL}" "${INPUT_PORT}") 524 | endif() 525 | 526 | endfunction() 527 | 528 | #=============================================================================# 529 | # [PUBLIC/USER] 530 | # see documentation at top 531 | #=============================================================================# 532 | function(GENERATE_AVR_FIRMWARE INPUT_NAME) 533 | # TODO: This is not optimal!!!! 534 | message(STATUS "Generating ${INPUT_NAME}") 535 | parse_generator_arguments(${INPUT_NAME} INPUT 536 | "NO_AUTOLIBS;MANUAL" # Options 537 | "BOARD;PORT;PROGRAMMER" # One Value Keywords 538 | "SERIAL;SRCS;HDRS;LIBS;AFLAGS" # Multi Value Keywords 539 | ${ARGN}) 540 | 541 | if(NOT INPUT_BOARD) 542 | set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) 543 | endif() 544 | if(NOT INPUT_PORT) 545 | set(INPUT_PORT ${ARDUINO_DEFAULT_PORT}) 546 | endif() 547 | if(NOT INPUT_SERIAL) 548 | set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) 549 | endif() 550 | if(NOT INPUT_PROGRAMMER) 551 | set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) 552 | endif() 553 | 554 | required_variables(VARS INPUT_BOARD INPUT_SRCS MSG "must define for target ${INPUT_NAME}") 555 | 556 | if(INPUT_HDRS) 557 | list(INSERT INPUT_HDRS 0 "HDRS") 558 | endif() 559 | if(INPUT_LIBS) 560 | list(INSERT INPUT_LIBS 0 "LIBS") 561 | endif() 562 | if(INPUT_AFLAGS) 563 | list(INSERT INPUT_AFLAGS 0 "AFLAGS") 564 | endif() 565 | 566 | generate_arduino_firmware( ${INPUT_NAME} 567 | NO_AUTOLIBS 568 | MANUAL 569 | BOARD ${INPUT_BOARD} 570 | PORT ${INPUT_PORT} 571 | PROGRAMMER ${INPUT_PROGRAMMER} 572 | SERIAL ${INPUT_SERIAL} 573 | SRCS ${INPUT_SRCS} 574 | ${INPUT_HDRS} 575 | ${INPUT_LIBS} 576 | ${INPUT_AFLAGS} ) 577 | 578 | endfunction() 579 | 580 | #=============================================================================# 581 | # [PUBLIC/USER] 582 | # see documentation at top 583 | #=============================================================================# 584 | function(GENERATE_ARDUINO_EXAMPLE INPUT_NAME) 585 | parse_generator_arguments(${INPUT_NAME} INPUT 586 | "" # Options 587 | "LIBRARY;EXAMPLE;BOARD;PORT;PROGRAMMER" # One Value Keywords 588 | "SERIAL;AFLAGS" # Multi Value Keywords 589 | ${ARGN}) 590 | 591 | 592 | if(NOT INPUT_BOARD) 593 | set(INPUT_BOARD ${ARDUINO_DEFAULT_BOARD}) 594 | endif() 595 | if(NOT INPUT_PORT) 596 | set(INPUT_PORT ${ARDUINO_DEFAULT_PORT}) 597 | endif() 598 | if(NOT INPUT_SERIAL) 599 | set(INPUT_SERIAL ${ARDUINO_DEFAULT_SERIAL}) 600 | endif() 601 | if(NOT INPUT_PROGRAMMER) 602 | set(INPUT_PROGRAMMER ${ARDUINO_DEFAULT_PROGRAMMER}) 603 | endif() 604 | required_variables(VARS INPUT_LIBRARY INPUT_EXAMPLE INPUT_BOARD 605 | MSG "must define for target ${INPUT_NAME}") 606 | 607 | message(STATUS "Generating ${INPUT_NAME}") 608 | 609 | set(ALL_LIBS) 610 | set(ALL_SRCS) 611 | 612 | setup_arduino_core(CORE_LIB ${INPUT_BOARD}) 613 | 614 | setup_arduino_example("${INPUT_NAME}" "${INPUT_LIBRARY}" "${INPUT_EXAMPLE}" ALL_SRCS) 615 | 616 | if(NOT ALL_SRCS) 617 | message(FATAL_ERROR "Missing sources for example, aborting!") 618 | endif() 619 | 620 | find_arduino_libraries(TARGET_LIBS "${ALL_SRCS}" "") 621 | set(LIB_DEP_INCLUDES) 622 | foreach(LIB_DEP ${TARGET_LIBS}) 623 | set(LIB_DEP_INCLUDES "${LIB_DEP_INCLUDES} -I\"${LIB_DEP}\"") 624 | endforeach() 625 | 626 | setup_arduino_libraries(ALL_LIBS ${INPUT_BOARD} "${ALL_SRCS}" "" "${LIB_DEP_INCLUDES}" "") 627 | 628 | list(APPEND ALL_LIBS ${CORE_LIB} ${INPUT_LIBS}) 629 | 630 | setup_arduino_target(${INPUT_NAME} ${INPUT_BOARD} "${ALL_SRCS}" "${ALL_LIBS}" "${LIB_DEP_INCLUDES}" "" FALSE) 631 | 632 | if(INPUT_PORT) 633 | setup_arduino_upload(${INPUT_BOARD} ${INPUT_NAME} ${INPUT_PORT} "${INPUT_PROGRAMMER}" "${INPUT_AFLAGS}") 634 | endif() 635 | 636 | if(INPUT_SERIAL) 637 | setup_serial_target(${INPUT_NAME} "${INPUT_SERIAL}" "${INPUT_PORT}") 638 | endif() 639 | endfunction() 640 | 641 | #=============================================================================# 642 | # [PUBLIC/USER] 643 | # see documentation at top 644 | #=============================================================================# 645 | function(REGISTER_HARDWARE_PLATFORM PLATFORM_PATH) 646 | string(REGEX REPLACE "/$" "" PLATFORM_PATH ${PLATFORM_PATH}) 647 | GET_FILENAME_COMPONENT(PLATFORM ${PLATFORM_PATH} NAME) 648 | 649 | if(PLATFORM) 650 | string(TOUPPER ${PLATFORM} PLATFORM) 651 | list(FIND ARDUINO_PLATFORMS ${PLATFORM} platform_exists) 652 | 653 | if (platform_exists EQUAL -1) 654 | set(${PLATFORM}_PLATFORM_PATH ${PLATFORM_PATH} CACHE INTERNAL "The path to ${PLATFORM}") 655 | set(ARDUINO_PLATFORMS ${ARDUINO_PLATFORMS} ${PLATFORM} CACHE INTERNAL "A list of registered platforms") 656 | 657 | find_file(${PLATFORM}_CORES_PATH 658 | NAMES cores 659 | PATHS ${PLATFORM_PATH} 660 | DOC "Path to directory containing the Arduino core sources." 661 | NO_SYSTEM_ENVIRONMENT_PATH) 662 | 663 | find_file(${PLATFORM}_VARIANTS_PATH 664 | NAMES variants 665 | PATHS ${PLATFORM_PATH} 666 | DOC "Path to directory containing the Arduino variant sources." 667 | NO_SYSTEM_ENVIRONMENT_PATH) 668 | 669 | find_file(${PLATFORM}_BOOTLOADERS_PATH 670 | NAMES bootloaders 671 | PATHS ${PLATFORM_PATH} 672 | DOC "Path to directory containing the Arduino bootloader images and sources." 673 | NO_SYSTEM_ENVIRONMENT_PATH) 674 | 675 | find_file(${PLATFORM}_LIBRARIES_PATH 676 | NAMES libraries 677 | PATHS ${PLATFORM_PATH} 678 | DOC "Path to directory containing the Arduino hardware libraries sources." 679 | NO_SYSTEM_ENVIRONMENT_PATH) 680 | 681 | find_file(${PLATFORM}_PROGRAMMERS_PATH 682 | NAMES programmers.txt 683 | PATHS ${PLATFORM_PATH} 684 | DOC "Path to Arduino programmers definition file." 685 | NO_SYSTEM_ENVIRONMENT_PATH) 686 | 687 | find_file(${PLATFORM}_BOARDS_PATH 688 | NAMES boards.txt 689 | PATHS ${PLATFORM_PATH} 690 | DOC "Path to Arduino boards definition file." 691 | NO_SYSTEM_ENVIRONMENT_PATH) 692 | 693 | if(${PLATFORM}_BOARDS_PATH) 694 | load_arduino_style_settings(${PLATFORM}_BOARDS "${PLATFORM_PATH}/boards.txt") 695 | endif() 696 | 697 | if(${PLATFORM}_PROGRAMMERS_PATH) 698 | load_arduino_style_settings(${PLATFORM}_PROGRAMMERS "${ARDUINO_PROGRAMMERS_PATH}") 699 | endif() 700 | 701 | if(${PLATFORM}_VARIANTS_PATH) 702 | file(GLOB sub-dir ${${PLATFORM}_VARIANTS_PATH}/*) 703 | foreach(dir ${sub-dir}) 704 | if(IS_DIRECTORY ${dir}) 705 | get_filename_component(variant ${dir} NAME) 706 | set(VARIANTS ${VARIANTS} ${variant} CACHE INTERNAL "A list of registered variant boards") 707 | set(${variant}.path ${dir} CACHE INTERNAL "The path to the variant ${variant}") 708 | endif() 709 | endforeach() 710 | endif() 711 | 712 | if(${PLATFORM}_CORES_PATH) 713 | file(GLOB sub-dir ${${PLATFORM}_CORES_PATH}/*) 714 | foreach(dir ${sub-dir}) 715 | if(IS_DIRECTORY ${dir}) 716 | get_filename_component(core ${dir} NAME) 717 | set(CORES ${CORES} ${core} CACHE INTERNAL "A list of registered cores") 718 | set(${core}.path ${dir} CACHE INTERNAL "The path to the core ${core}") 719 | endif() 720 | endforeach() 721 | endif() 722 | 723 | endif() 724 | endif() 725 | 726 | endfunction() 727 | 728 | #=============================================================================# 729 | # Internal Functions 730 | #=============================================================================# 731 | 732 | #=============================================================================# 733 | # [PRIVATE/INTERNAL] 734 | # 735 | # parse_generator_arguments(TARGET_NAME PREFIX OPTIONS ARGS MULTI_ARGS [ARG1 ARG2 .. ARGN]) 736 | # 737 | # PREFIX - Parsed options prefix 738 | # OPTIONS - List of options 739 | # ARGS - List of one value keyword arguments 740 | # MULTI_ARGS - List of multi value keyword arguments 741 | # [ARG1 ARG2 .. ARGN] - command arguments [optional] 742 | # 743 | # Parses generator options from either variables or command arguments 744 | # 745 | #=============================================================================# 746 | macro(PARSE_GENERATOR_ARGUMENTS TARGET_NAME PREFIX OPTIONS ARGS MULTI_ARGS) 747 | cmake_parse_arguments(${PREFIX} "${OPTIONS}" "${ARGS}" "${MULTI_ARGS}" ${ARGN}) 748 | error_for_unparsed(${PREFIX}) 749 | load_generator_settings(${TARGET_NAME} ${PREFIX} ${OPTIONS} ${ARGS} ${MULTI_ARGS}) 750 | endmacro() 751 | 752 | #=============================================================================# 753 | # [PRIVATE/INTERNAL] 754 | # 755 | # load_generator_settings(TARGET_NAME PREFIX [SUFFIX_1 SUFFIX_2 .. SUFFIX_N]) 756 | # 757 | # TARGET_NAME - The base name of the user settings 758 | # PREFIX - The prefix name used for generator settings 759 | # SUFFIX_XX - List of suffixes to load 760 | # 761 | # Loads a list of user settings into the generators scope. User settings have 762 | # the following syntax: 763 | # 764 | # ${BASE_NAME}${SUFFIX} 765 | # 766 | # The BASE_NAME is the target name and the suffix is a specific generator settings. 767 | # 768 | # For every user setting found a generator setting is created of the follwoing fromat: 769 | # 770 | # ${PREFIX}${SUFFIX} 771 | # 772 | # The purpose of loading the settings into the generator is to not modify user settings 773 | # and to have a generic naming of the settings within the generator. 774 | # 775 | #=============================================================================# 776 | function(LOAD_GENERATOR_SETTINGS TARGET_NAME PREFIX) 777 | foreach(GEN_SUFFIX ${ARGN}) 778 | if(${TARGET_NAME}_${GEN_SUFFIX} AND NOT ${PREFIX}_${GEN_SUFFIX}) 779 | set(${PREFIX}_${GEN_SUFFIX} ${${TARGET_NAME}_${GEN_SUFFIX}} PARENT_SCOPE) 780 | endif() 781 | endforeach() 782 | endfunction() 783 | 784 | #=============================================================================# 785 | # [PRIVATE/INTERNAL] 786 | # 787 | # get_arduino_flags(COMPILE_FLAGS LINK_FLAGS BOARD_ID MANUAL) 788 | # 789 | # COMPILE_FLAGS_VAR -Variable holding compiler flags 790 | # LINK_FLAGS_VAR - Variable holding linker flags 791 | # BOARD_ID - The board id name 792 | # MANUAL - (Advanced) Only use AVR Libc/Includes 793 | # 794 | # Configures the the build settings for the specified Arduino Board. 795 | # 796 | #=============================================================================# 797 | function(get_arduino_flags COMPILE_FLAGS_VAR LINK_FLAGS_VAR BOARD_ID MANUAL) 798 | 799 | set(BOARD_CORE ${${BOARD_ID}.build.core}) 800 | if(BOARD_CORE) 801 | if(ARDUINO_SDK_VERSION MATCHES "([0-9]+)[.]([0-9]+)[.]([0-9]+)") 802 | string(REPLACE "." "" ARDUINO_VERSION_DEFINE "${ARDUINO_SDK_VERSION}") # Normalize version (remove all periods) 803 | set(ARDUINO_VERSION_DEFINE "") 804 | if(CMAKE_MATCH_1 GREATER 0) 805 | set(ARDUINO_VERSION_DEFINE "${CMAKE_MATCH_1}") 806 | endif() 807 | if(CMAKE_MATCH_2 GREATER 10) 808 | set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}${CMAKE_MATCH_2}") 809 | else() 810 | set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}0${CMAKE_MATCH_2}") 811 | endif() 812 | if(CMAKE_MATCH_3 GREATER 10) 813 | set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}${CMAKE_MATCH_3}") 814 | else() 815 | set(ARDUINO_VERSION_DEFINE "${ARDUINO_VERSION_DEFINE}0${CMAKE_MATCH_3}") 816 | endif() 817 | else() 818 | message("Invalid Arduino SDK Version (${ARDUINO_SDK_VERSION})") 819 | endif() 820 | 821 | # output 822 | set(COMPILE_FLAGS "-DF_CPU=${${BOARD_ID}${ARDUINO_CPUMENU}.build.f_cpu} -DARDUINO=${ARDUINO_VERSION_DEFINE} -DARDUINO_${${BOARD_ID}.build.board} -DARDUINO_ARCH_AVR -mmcu=${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu}") 823 | if(DEFINED ${BOARD_ID}.build.vid) 824 | set(COMPILE_FLAGS "${COMPILE_FLAGS} -DUSB_VID=${${BOARD_ID}.build.vid}") 825 | endif() 826 | if(DEFINED ${BOARD_ID}.build.pid) 827 | set(COMPILE_FLAGS "${COMPILE_FLAGS} -DUSB_PID=${${BOARD_ID}.build.pid}") 828 | endif() 829 | if(NOT MANUAL) 830 | set(COMPILE_FLAGS "${COMPILE_FLAGS} -I\"${${BOARD_CORE}.path}\" -I\"${ARDUINO_LIBRARIES_PATH}\"") 831 | endif() 832 | set(LINK_FLAGS "-mmcu=${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu}") 833 | if(ARDUINO_SDK_VERSION VERSION_GREATER 1.0 OR ARDUINO_SDK_VERSION VERSION_EQUAL 1.0) 834 | if(NOT MANUAL) 835 | set(PIN_HEADER ${${${BOARD_ID}.build.variant}.path}) 836 | if(PIN_HEADER) 837 | set(COMPILE_FLAGS "${COMPILE_FLAGS} -I\"${PIN_HEADER}\"") 838 | endif() 839 | endif() 840 | endif() 841 | 842 | # output 843 | set(${COMPILE_FLAGS_VAR} "${COMPILE_FLAGS}" PARENT_SCOPE) 844 | set(${LINK_FLAGS_VAR} "${LINK_FLAGS}" PARENT_SCOPE) 845 | 846 | else() 847 | message(FATAL_ERROR "Invalid Arduino board ID (${BOARD_ID}), aborting.") 848 | endif() 849 | endfunction() 850 | 851 | #=============================================================================# 852 | # [PRIVATE/INTERNAL] 853 | # 854 | # setup_arduino_core(VAR_NAME BOARD_ID) 855 | # 856 | # VAR_NAME - Variable name that will hold the generated library name 857 | # BOARD_ID - Arduino board id 858 | # 859 | # Creates the Arduino Core library for the specified board, 860 | # each board gets it's own version of the library. 861 | # 862 | #=============================================================================# 863 | function(setup_arduino_core VAR_NAME BOARD_ID) 864 | set(CORE_LIB_NAME ${BOARD_ID}_CORE) 865 | set(BOARD_CORE ${${BOARD_ID}.build.core}) 866 | if(BOARD_CORE) 867 | if(NOT TARGET ${CORE_LIB_NAME}) 868 | set(BOARD_CORE_PATH ${${BOARD_CORE}.path}) 869 | find_sources(CORE_SRCS ${BOARD_CORE_PATH} True) 870 | # Debian/Ubuntu fix 871 | list(REMOVE_ITEM CORE_SRCS "${BOARD_CORE_PATH}/main.cxx") 872 | add_library(${CORE_LIB_NAME} ${CORE_SRCS}) 873 | get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} FALSE) 874 | set_target_properties(${CORE_LIB_NAME} PROPERTIES 875 | COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS}" 876 | LINK_FLAGS "${ARDUINO_LINK_FLAGS}") 877 | endif() 878 | set(${VAR_NAME} ${CORE_LIB_NAME} PARENT_SCOPE) 879 | endif() 880 | endfunction() 881 | 882 | #=============================================================================# 883 | # [PRIVATE/INTERNAL] 884 | # 885 | # find_arduino_libraries(VAR_NAME SRCS ARDLIBS) 886 | # 887 | # VAR_NAME - Variable name which will hold the results 888 | # SRCS - Sources that will be analized 889 | # ARDLIBS - Arduino libraries identified by name (e.g., Wire, SPI, Servo) 890 | # 891 | # returns a list of paths to libraries found. 892 | # 893 | # Finds all Arduino type libraries included in sources. Available libraries 894 | # are ${ARDUINO_SDK_PATH}/libraries and ${CMAKE_CURRENT_SOURCE_DIR}. 895 | # 896 | # Also adds Arduino libraries specifically names in ALIBS. We add ".h" to the 897 | # names and then process them just like the Arduino libraries found in the sources. 898 | # 899 | # A Arduino library is a folder that has the same name as the include header. 900 | # For example, if we have a include "#include " then the following 901 | # directory structure is considered a Arduino library: 902 | # 903 | # LibraryName/ 904 | # |- LibraryName.h 905 | # `- LibraryName.c 906 | # 907 | # If such a directory is found then all sources within that directory are considred 908 | # to be part of that Arduino library. 909 | # 910 | #=============================================================================# 911 | function(find_arduino_libraries VAR_NAME SRCS ARDLIBS) 912 | set(ARDUINO_LIBS ) 913 | foreach(SRC ${SRCS}) 914 | 915 | # Skipping generated files. They are, probably, not exist yet. 916 | # TODO: Maybe it's possible to skip only really nonexisting files, 917 | # but then it wiil be less deterministic. 918 | get_source_file_property(_srcfile_generated ${SRC} GENERATED) 919 | # Workaround for sketches, which are marked as generated 920 | get_source_file_property(_sketch_generated ${SRC} GENERATED_SKETCH) 921 | 922 | if(NOT ${_srcfile_generated} OR ${_sketch_generated}) 923 | if(NOT (EXISTS ${SRC} OR 924 | EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SRC} OR 925 | EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${SRC})) 926 | message(FATAL_ERROR "Invalid source file: ${SRC}") 927 | endif() 928 | file(STRINGS ${SRC} SRC_CONTENTS) 929 | 930 | foreach(LIBNAME ${ARDLIBS}) 931 | list(APPEND SRC_CONTENTS "#include <${LIBNAME}.h>") 932 | endforeach() 933 | 934 | foreach(SRC_LINE ${SRC_CONTENTS}) 935 | if("${SRC_LINE}" MATCHES "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"]") 936 | get_filename_component(INCLUDE_NAME ${CMAKE_MATCH_1} NAME_WE) 937 | get_property(LIBRARY_SEARCH_PATH 938 | DIRECTORY # Property Scope 939 | PROPERTY LINK_DIRECTORIES) 940 | foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${${ARDUINO_PLATFORM}_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries ${ARDUINO_EXTRA_LIBRARIES_PATH}) 941 | if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}) 942 | list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) 943 | break() 944 | endif() 945 | if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/src/${CMAKE_MATCH_1}) 946 | list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}) 947 | break() 948 | endif() 949 | if(EXISTS ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1}) 950 | list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}) 951 | break() 952 | endif() 953 | endforeach() 954 | endif() 955 | endforeach() 956 | endif() 957 | endforeach() 958 | if(ARDUINO_LIBS) 959 | list(REMOVE_DUPLICATES ARDUINO_LIBS) 960 | endif() 961 | set(${VAR_NAME} ${ARDUINO_LIBS} PARENT_SCOPE) 962 | endfunction() 963 | 964 | #=============================================================================# 965 | # [PRIVATE/INTERNAL] 966 | # 967 | # setup_arduino_library(VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS) 968 | # 969 | # VAR_NAME - Vairable wich will hold the generated library names 970 | # BOARD_ID - Board ID 971 | # LIB_PATH - Path of the library 972 | # COMPILE_FLAGS - Compile flags 973 | # LINK_FLAGS - Link flags 974 | # 975 | # Creates an Arduino library, with all it's library dependencies. 976 | # 977 | # ${LIB_NAME}_RECURSE controls if the library will recurse 978 | # when looking for source files. 979 | # 980 | #=============================================================================# 981 | 982 | # For known libraries can list recurse here 983 | set(Wire_RECURSE True) 984 | set(Ethernet_RECURSE True) 985 | set(SD_RECURSE True) 986 | set(SPI_RECURSE True) 987 | set(SoftwareSerial_RECURSE True) 988 | set(EEPROM_RECURSE True) 989 | set(LiquidCrystal_RECURSE True) 990 | function(setup_arduino_library VAR_NAME BOARD_ID LIB_PATH COMPILE_FLAGS LINK_FLAGS) 991 | set(LIB_TARGETS) 992 | set(LIB_INCLUDES) 993 | 994 | get_filename_component(LIB_NAME ${LIB_PATH} NAME) 995 | set(TARGET_LIB_NAME ${BOARD_ID}_${LIB_NAME}) 996 | if(NOT TARGET ${TARGET_LIB_NAME}) 997 | string(REGEX REPLACE ".*/" "" LIB_SHORT_NAME ${LIB_NAME}) 998 | 999 | # Detect if recursion is needed 1000 | if (NOT DEFINED ${LIB_SHORT_NAME}_RECURSE) 1001 | set(${LIB_SHORT_NAME}_RECURSE False) 1002 | endif() 1003 | 1004 | find_sources(LIB_SRCS ${LIB_PATH} ${${LIB_SHORT_NAME}_RECURSE}) 1005 | if(LIB_SRCS) 1006 | message(STATUS "Generating ${TARGET_LIB_NAME} for library ${LIB_NAME}") 1007 | arduino_debug_msg("Generating Arduino ${LIB_NAME} library") 1008 | add_library(${TARGET_LIB_NAME} STATIC ${LIB_SRCS}) 1009 | 1010 | get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} FALSE) 1011 | 1012 | find_arduino_libraries(LIB_DEPS "${LIB_SRCS}" "") 1013 | 1014 | foreach(LIB_DEP ${LIB_DEPS}) 1015 | if(NOT DEP_LIB_SRCS STREQUAL TARGET_LIB_NAME AND DEP_LIB_SRCS) 1016 | message(STATUS "Found library ${LIB_NAME} needs ${DEP_LIB_SRCS}") 1017 | endif() 1018 | 1019 | setup_arduino_library(DEP_LIB_SRCS ${BOARD_ID} ${LIB_DEP} "${COMPILE_FLAGS}" "${LINK_FLAGS}") 1020 | # Do not link to this library. DEP_LIB_SRCS will always be only one entry 1021 | # if we are looking at the same library. 1022 | if(NOT DEP_LIB_SRCS STREQUAL TARGET_LIB_NAME) 1023 | list(APPEND LIB_TARGETS ${DEP_LIB_SRCS}) 1024 | list(APPEND LIB_INCLUDES ${DEP_LIB_SRCS_INCLUDES}) 1025 | endif() 1026 | endforeach() 1027 | 1028 | if (LIB_INCLUDES) 1029 | string(REPLACE ";" " " LIB_INCLUDES "${LIB_INCLUDES}") 1030 | endif() 1031 | 1032 | set_target_properties(${TARGET_LIB_NAME} PROPERTIES 1033 | COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${LIB_INCLUDES} -I\"${LIB_PATH}\" -I\"${LIB_PATH}/src\" -I\"${LIB_PATH}/utility\" ${COMPILE_FLAGS}" 1034 | LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") 1035 | list(APPEND LIB_INCLUDES "-I\"${LIB_PATH}\" -I\"${LIB_PATH}/src\" -I\"${LIB_PATH}/utility\"") 1036 | 1037 | target_link_libraries(${TARGET_LIB_NAME} ${BOARD_ID}_CORE ${LIB_TARGETS}) 1038 | list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) 1039 | 1040 | endif() 1041 | else() 1042 | # Target already exists, skiping creating 1043 | list(APPEND LIB_TARGETS ${TARGET_LIB_NAME}) 1044 | endif() 1045 | if(LIB_TARGETS) 1046 | list(REMOVE_DUPLICATES LIB_TARGETS) 1047 | endif() 1048 | set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) 1049 | set(${VAR_NAME}_INCLUDES ${LIB_INCLUDES} PARENT_SCOPE) 1050 | endfunction() 1051 | 1052 | #=============================================================================# 1053 | # [PRIVATE/INTERNAL] 1054 | # 1055 | # setup_arduino_libraries(VAR_NAME BOARD_ID SRCS COMPILE_FLAGS LINK_FLAGS) 1056 | # 1057 | # VAR_NAME - Vairable wich will hold the generated library names 1058 | # BOARD_ID - Board ID 1059 | # SRCS - source files 1060 | # COMPILE_FLAGS - Compile flags 1061 | # LINK_FLAGS - Linker flags 1062 | # 1063 | # Finds and creates all dependency libraries based on sources. 1064 | # 1065 | #=============================================================================# 1066 | function(setup_arduino_libraries VAR_NAME BOARD_ID SRCS ARDLIBS COMPILE_FLAGS LINK_FLAGS) 1067 | set(LIB_TARGETS) 1068 | set(LIB_INCLUDES) 1069 | 1070 | find_arduino_libraries(TARGET_LIBS "${SRCS}" ARDLIBS) 1071 | foreach(TARGET_LIB ${TARGET_LIBS}) 1072 | # Create static library instead of returning sources 1073 | setup_arduino_library(LIB_DEPS ${BOARD_ID} ${TARGET_LIB} "${COMPILE_FLAGS}" "${LINK_FLAGS}") 1074 | list(APPEND LIB_TARGETS ${LIB_DEPS}) 1075 | list(APPEND LIB_INCLUDES ${LIB_DEPS_INCLUDES}) 1076 | endforeach() 1077 | 1078 | set(${VAR_NAME} ${LIB_TARGETS} PARENT_SCOPE) 1079 | set(${VAR_NAME}_INCLUDES ${LIB_INCLUDES} PARENT_SCOPE) 1080 | endfunction() 1081 | 1082 | 1083 | #=============================================================================# 1084 | # [PRIVATE/INTERNAL] 1085 | # 1086 | # setup_arduino_target(TARGET_NAME ALL_SRCS ALL_LIBS COMPILE_FLAGS LINK_FLAGS MANUAL) 1087 | # 1088 | # TARGET_NAME - Target name 1089 | # BOARD_ID - Arduino board ID 1090 | # ALL_SRCS - All sources 1091 | # ALL_LIBS - All libraries 1092 | # COMPILE_FLAGS - Compile flags 1093 | # LINK_FLAGS - Linker flags 1094 | # MANUAL - (Advanced) Only use AVR Libc/Includes 1095 | # 1096 | # Creates an Arduino firmware target. 1097 | # 1098 | #=============================================================================# 1099 | function(setup_arduino_target TARGET_NAME BOARD_ID ALL_SRCS ALL_LIBS COMPILE_FLAGS LINK_FLAGS MANUAL) 1100 | 1101 | add_executable(${TARGET_NAME} ${ALL_SRCS}) 1102 | set_target_properties(${TARGET_NAME} PROPERTIES SUFFIX ".elf") 1103 | 1104 | get_arduino_flags(ARDUINO_COMPILE_FLAGS ARDUINO_LINK_FLAGS ${BOARD_ID} ${MANUAL}) 1105 | 1106 | set_target_properties(${TARGET_NAME} PROPERTIES 1107 | COMPILE_FLAGS "${ARDUINO_COMPILE_FLAGS} ${COMPILE_FLAGS}" 1108 | LINK_FLAGS "${ARDUINO_LINK_FLAGS} ${LINK_FLAGS}") 1109 | target_link_libraries(${TARGET_NAME} ${ALL_LIBS} "-lc -lm") 1110 | 1111 | if(NOT EXECUTABLE_OUTPUT_PATH) 1112 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) 1113 | endif() 1114 | set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) 1115 | 1116 | message(STATUS "Using ${CMAKE_OBJCOPY} for converting firmware image to hex") 1117 | add_custom_command(TARGET ${TARGET_NAME} POST_BUILD 1118 | COMMAND ${CMAKE_OBJCOPY} 1119 | ARGS ${ARDUINO_OBJCOPY_EEP_FLAGS} 1120 | ${TARGET_PATH}.elf 1121 | ${TARGET_PATH}.eep 1122 | COMMENT "Generating EEP image" 1123 | VERBATIM) 1124 | 1125 | # Convert firmware image to ASCII HEX format 1126 | add_custom_command(TARGET ${TARGET_NAME} POST_BUILD 1127 | COMMAND ${CMAKE_OBJCOPY} 1128 | ARGS ${ARDUINO_OBJCOPY_HEX_FLAGS} 1129 | ${TARGET_PATH}.elf 1130 | ${TARGET_PATH}.hex 1131 | COMMENT "Generating HEX image" 1132 | VERBATIM) 1133 | 1134 | # Display target size 1135 | add_custom_command(TARGET ${TARGET_NAME} POST_BUILD 1136 | COMMAND ${CMAKE_COMMAND} 1137 | ARGS -DFIRMWARE_IMAGE=${TARGET_PATH}.elf 1138 | -DMCU=${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu} 1139 | -DEEPROM_IMAGE=${TARGET_PATH}.eep 1140 | -P ${ARDUINO_SIZE_SCRIPT} 1141 | COMMENT "Calculating image size" 1142 | VERBATIM) 1143 | 1144 | # Create ${TARGET_NAME}-size target 1145 | add_custom_target(${TARGET_NAME}-size 1146 | COMMAND ${CMAKE_COMMAND} 1147 | -DFIRMWARE_IMAGE=${TARGET_PATH}.elf 1148 | -DMCU=${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu} 1149 | -DEEPROM_IMAGE=${TARGET_PATH}.eep 1150 | -P ${ARDUINO_SIZE_SCRIPT} 1151 | DEPENDS ${TARGET_NAME} 1152 | COMMENT "Calculating ${TARGET_NAME} image size") 1153 | 1154 | endfunction() 1155 | 1156 | #=============================================================================# 1157 | # [PRIVATE/INTERNAL] 1158 | # 1159 | # setup_arduino_upload(BOARD_ID TARGET_NAME PORT) 1160 | # 1161 | # BOARD_ID - Arduino board id 1162 | # TARGET_NAME - Target name 1163 | # PORT - Serial port for upload 1164 | # PROGRAMMER_ID - Programmer ID 1165 | # AVRDUDE_FLAGS - avrdude flags 1166 | # 1167 | # Create an upload target (${TARGET_NAME}-upload) for the specified Arduino target. 1168 | # 1169 | #=============================================================================# 1170 | function(setup_arduino_upload BOARD_ID TARGET_NAME PORT PROGRAMMER_ID AVRDUDE_FLAGS) 1171 | setup_arduino_bootloader_upload(${TARGET_NAME} ${BOARD_ID} ${PORT} "${AVRDUDE_FLAGS}") 1172 | 1173 | # Add programmer support if defined 1174 | if(PROGRAMMER_ID AND ${PROGRAMMER_ID}.protocol) 1175 | setup_arduino_programmer_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") 1176 | setup_arduino_bootloader_burn(${TARGET_NAME} ${BOARD_ID} ${PROGRAMMER_ID} ${PORT} "${AVRDUDE_FLAGS}") 1177 | endif() 1178 | endfunction() 1179 | 1180 | 1181 | #=============================================================================# 1182 | # [PRIVATE/INTERNAL] 1183 | # 1184 | # setup_arduino_bootloader_upload(TARGET_NAME BOARD_ID PORT) 1185 | # 1186 | # TARGET_NAME - target name 1187 | # BOARD_ID - board id 1188 | # PORT - serial port 1189 | # AVRDUDE_FLAGS - avrdude flags (override) 1190 | # 1191 | # Set up target for upload firmware via the bootloader. 1192 | # 1193 | # The target for uploading the firmware is ${TARGET_NAME}-upload . 1194 | # 1195 | #=============================================================================# 1196 | function(setup_arduino_bootloader_upload TARGET_NAME BOARD_ID PORT AVRDUDE_FLAGS) 1197 | set(UPLOAD_TARGET ${TARGET_NAME}-upload) 1198 | set(AVRDUDE_ARGS) 1199 | 1200 | setup_arduino_bootloader_args(${BOARD_ID} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) 1201 | 1202 | if(NOT AVRDUDE_ARGS) 1203 | message("Could not generate default avrdude bootloader args, aborting!") 1204 | return() 1205 | endif() 1206 | 1207 | if(NOT EXECUTABLE_OUTPUT_PATH) 1208 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) 1209 | endif() 1210 | set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) 1211 | 1212 | list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_PATH}.hex:i") 1213 | list(APPEND AVRDUDE_ARGS "-Ueeprom:w:${TARGET_PATH}.eep:i") 1214 | add_custom_target(${UPLOAD_TARGET} 1215 | ${ARDUINO_AVRDUDE_PROGRAM} 1216 | ${AVRDUDE_ARGS} 1217 | DEPENDS ${TARGET_NAME}) 1218 | 1219 | # Global upload target 1220 | if(NOT TARGET upload) 1221 | add_custom_target(upload) 1222 | endif() 1223 | 1224 | add_dependencies(upload ${UPLOAD_TARGET}) 1225 | endfunction() 1226 | 1227 | #=============================================================================# 1228 | # [PRIVATE/INTERNAL] 1229 | # 1230 | # setup_arduino_programmer_burn(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) 1231 | # 1232 | # TARGET_NAME - name of target to burn 1233 | # BOARD_ID - board id 1234 | # PROGRAMMER - programmer id 1235 | # PORT - serial port 1236 | # AVRDUDE_FLAGS - avrdude flags (override) 1237 | # 1238 | # Sets up target for burning firmware via a programmer. 1239 | # 1240 | # The target for burning the firmware is ${TARGET_NAME}-burn . 1241 | # 1242 | #=============================================================================# 1243 | function(setup_arduino_programmer_burn TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) 1244 | set(PROGRAMMER_TARGET ${TARGET_NAME}-burn) 1245 | 1246 | set(AVRDUDE_ARGS) 1247 | 1248 | setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) 1249 | 1250 | if(NOT AVRDUDE_ARGS) 1251 | message("Could not generate default avrdude programmer args, aborting!") 1252 | return() 1253 | endif() 1254 | 1255 | if(NOT EXECUTABLE_OUTPUT_PATH) 1256 | set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) 1257 | endif() 1258 | set(TARGET_PATH ${EXECUTABLE_OUTPUT_PATH}/${TARGET_NAME}) 1259 | 1260 | list(APPEND AVRDUDE_ARGS "-Uflash:w:${TARGET_PATH}.hex") 1261 | 1262 | add_custom_target(${PROGRAMMER_TARGET} 1263 | ${ARDUINO_AVRDUDE_PROGRAM} 1264 | ${AVRDUDE_ARGS} 1265 | DEPENDS ${TARGET_NAME}) 1266 | endfunction() 1267 | 1268 | #=============================================================================# 1269 | # [PRIVATE/INTERNAL] 1270 | # 1271 | # setup_arduino_bootloader_burn(TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) 1272 | # 1273 | # TARGET_NAME - name of target to burn 1274 | # BOARD_ID - board id 1275 | # PROGRAMMER - programmer id 1276 | # PORT - serial port 1277 | # AVRDUDE_FLAGS - avrdude flags (override) 1278 | # 1279 | # Create a target for burning a bootloader via a programmer. 1280 | # 1281 | # The target for burning the bootloader is ${TARGET_NAME}-burn-bootloader 1282 | # 1283 | #=============================================================================# 1284 | function(setup_arduino_bootloader_burn TARGET_NAME BOARD_ID PROGRAMMER PORT AVRDUDE_FLAGS) 1285 | set(BOOTLOADER_TARGET ${TARGET_NAME}-burn-bootloader) 1286 | 1287 | set(AVRDUDE_ARGS) 1288 | 1289 | setup_arduino_programmer_args(${BOARD_ID} ${PROGRAMMER} ${TARGET_NAME} ${PORT} "${AVRDUDE_FLAGS}" AVRDUDE_ARGS) 1290 | 1291 | if(NOT AVRDUDE_ARGS) 1292 | message("Could not generate default avrdude programmer args, aborting!") 1293 | return() 1294 | endif() 1295 | 1296 | foreach( ITEM unlock_bits high_fuses low_fuses path file) 1297 | if(NOT ${BOARD_ID}.bootloader.${ITEM}) 1298 | message("Missing ${BOARD_ID}.bootloader.${ITEM}, not creating bootloader burn target ${BOOTLOADER_TARGET}.") 1299 | return() 1300 | endif() 1301 | endforeach() 1302 | 1303 | if(NOT EXISTS "${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.file}") 1304 | message("${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path}/${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.file}") 1305 | message("Missing bootloader image, not creating bootloader burn target ${BOOTLOADER_TARGET}.") 1306 | return() 1307 | endif() 1308 | 1309 | # Erase the chip 1310 | list(APPEND AVRDUDE_ARGS "-e") 1311 | 1312 | # Set unlock bits and fuses (because chip is going to be erased) 1313 | list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.unlock_bits}:m") 1314 | if(${BOARD_ID}.bootloader.extended_fuses) 1315 | list(APPEND AVRDUDE_ARGS "-Uefuse:w:${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.extended_fuses}:m") 1316 | endif() 1317 | list(APPEND AVRDUDE_ARGS 1318 | "-Uhfuse:w:${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.high_fuses}:m" 1319 | "-Ulfuse:w:${${BOARD_ID}.bootloader.low_fuses}:m") 1320 | 1321 | # Set bootloader image 1322 | list(APPEND AVRDUDE_ARGS "-Uflash:w:${${BOARD_ID}${ARDUINO_CPUMENU}.bootloader.file}:i") 1323 | 1324 | # Set lockbits 1325 | list(APPEND AVRDUDE_ARGS "-Ulock:w:${${BOARD_ID}.bootloader.lock_bits}:m") 1326 | 1327 | # Create burn bootloader target 1328 | add_custom_target(${BOOTLOADER_TARGET} 1329 | ${ARDUINO_AVRDUDE_PROGRAM} 1330 | ${AVRDUDE_ARGS} 1331 | WORKING_DIRECTORY ${ARDUINO_BOOTLOADERS_PATH}/${${BOARD_ID}.bootloader.path} 1332 | DEPENDS ${TARGET_NAME}) 1333 | endfunction() 1334 | 1335 | #=============================================================================# 1336 | # [PRIVATE/INTERNAL] 1337 | # 1338 | # setup_arduino_programmer_args(BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) 1339 | # 1340 | # BOARD_ID - board id 1341 | # PROGRAMMER - programmer id 1342 | # TARGET_NAME - target name 1343 | # PORT - serial port 1344 | # AVRDUDE_FLAGS - avrdude flags (override) 1345 | # OUTPUT_VAR - name of output variable for result 1346 | # 1347 | # Sets up default avrdude settings for burning firmware via a programmer. 1348 | #=============================================================================# 1349 | function(setup_arduino_programmer_args BOARD_ID PROGRAMMER TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) 1350 | set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) 1351 | 1352 | if(NOT AVRDUDE_FLAGS) 1353 | set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) 1354 | endif() 1355 | 1356 | list(APPEND AVRDUDE_ARGS "-C${ARDUINO_AVRDUDE_CONFIG_PATH}") 1357 | 1358 | #TODO: Check mandatory settings before continuing 1359 | if(NOT ${PROGRAMMER}.protocol) 1360 | message(FATAL_ERROR "Missing ${PROGRAMMER}.protocol, aborting!") 1361 | endif() 1362 | 1363 | list(APPEND AVRDUDE_ARGS "-c${${PROGRAMMER}.protocol}") # Set programmer 1364 | 1365 | if(${PROGRAMMER}.communication STREQUAL "usb") 1366 | list(APPEND AVRDUDE_ARGS "-Pusb") # Set USB as port 1367 | elseif(${PROGRAMMER}.communication STREQUAL "serial") 1368 | list(APPEND AVRDUDE_ARGS "-P${PORT}") # Set port 1369 | if(${PROGRAMMER}.speed) 1370 | list(APPEND AVRDUDE_ARGS "-b${${PROGRAMMER}.speed}") # Set baud rate 1371 | endif() 1372 | endif() 1373 | 1374 | if(${PROGRAMMER}.force) 1375 | list(APPEND AVRDUDE_ARGS "-F") # Set force 1376 | endif() 1377 | 1378 | if(${PROGRAMMER}.delay) 1379 | list(APPEND AVRDUDE_ARGS "-i${${PROGRAMMER}.delay}") # Set delay 1380 | endif() 1381 | 1382 | list(APPEND AVRDUDE_ARGS "-p${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu}") # MCU Type 1383 | 1384 | list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) 1385 | 1386 | set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) 1387 | endfunction() 1388 | 1389 | #=============================================================================# 1390 | # [PRIVATE/INTERNAL] 1391 | # 1392 | # setup_arduino_bootloader_args(BOARD_ID TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) 1393 | # 1394 | # BOARD_ID - board id 1395 | # TARGET_NAME - target name 1396 | # PORT - serial port 1397 | # AVRDUDE_FLAGS - avrdude flags (override) 1398 | # OUTPUT_VAR - name of output variable for result 1399 | # 1400 | # Sets up default avrdude settings for uploading firmware via the bootloader. 1401 | #=============================================================================# 1402 | function(setup_arduino_bootloader_args BOARD_ID TARGET_NAME PORT AVRDUDE_FLAGS OUTPUT_VAR) 1403 | set(AVRDUDE_ARGS ${${OUTPUT_VAR}}) 1404 | 1405 | if(NOT AVRDUDE_FLAGS) 1406 | set(AVRDUDE_FLAGS ${ARDUINO_AVRDUDE_FLAGS}) 1407 | endif() 1408 | 1409 | list(APPEND AVRDUDE_ARGS 1410 | "-C${ARDUINO_AVRDUDE_CONFIG_PATH}" # avrdude config 1411 | "-p${${BOARD_ID}${ARDUINO_CPUMENU}.build.mcu}" # MCU Type 1412 | ) 1413 | 1414 | # Programmer 1415 | if(NOT ${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol OR ${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol STREQUAL "stk500") 1416 | if(NOT ${BOARD_ID}.upload.protocol OR ${BOARD_ID}.upload.protocol STREQUAL "stk500") 1417 | list(APPEND AVRDUDE_ARGS "-cstk500v1") 1418 | else() 1419 | list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}.upload.protocol}") 1420 | endif() 1421 | else() 1422 | list(APPEND AVRDUDE_ARGS "-c${${BOARD_ID}${ARDUINO_CPUMENU}.upload.protocol}") 1423 | endif() 1424 | 1425 | set(UPLOAD_SPEED "19200") 1426 | if(${BOARD_ID}${ARDUINO_CPUMENU}.upload.speed) 1427 | set(UPLOAD_SPEED ${${BOARD_ID}${ARDUINO_CPUMENU}.upload.speed}) 1428 | endif() 1429 | 1430 | list(APPEND AVRDUDE_ARGS 1431 | "-b${UPLOAD_SPEED}" # Baud rate 1432 | "-P${PORT}" # Serial port 1433 | "-D" # Dont erase 1434 | ) 1435 | 1436 | list(APPEND AVRDUDE_ARGS ${AVRDUDE_FLAGS}) 1437 | 1438 | set(${OUTPUT_VAR} ${AVRDUDE_ARGS} PARENT_SCOPE) 1439 | endfunction() 1440 | 1441 | #=============================================================================# 1442 | # [PRIVATE/INTERNAL] 1443 | # 1444 | # find_sources(VAR_NAME LIB_PATH RECURSE) 1445 | # 1446 | # VAR_NAME - Variable name that will hold the detected sources 1447 | # LIB_PATH - The base path 1448 | # RECURSE - Whether or not to recurse 1449 | # 1450 | # Finds all C/C++ sources located at the specified path. 1451 | # 1452 | #=============================================================================# 1453 | function(find_sources VAR_NAME LIB_PATH RECURSE) 1454 | set(FILE_SEARCH_LIST 1455 | ${LIB_PATH}/*.S 1456 | ${LIB_PATH}/*.inc 1457 | ${LIB_PATH}/*.cpp 1458 | ${LIB_PATH}/*.c 1459 | ${LIB_PATH}/*.cc 1460 | ${LIB_PATH}/*.cxx 1461 | ${LIB_PATH}/*.h 1462 | ${LIB_PATH}/*.hh 1463 | ${LIB_PATH}/*.hxx) 1464 | 1465 | if(RECURSE) 1466 | file(GLOB_RECURSE LIB_FILES ${FILE_SEARCH_LIST}) 1467 | else() 1468 | file(GLOB LIB_FILES ${FILE_SEARCH_LIST}) 1469 | endif() 1470 | 1471 | if(LIB_FILES) 1472 | set(${VAR_NAME} ${LIB_FILES} PARENT_SCOPE) 1473 | endif() 1474 | endfunction() 1475 | 1476 | #=============================================================================# 1477 | # [PRIVATE/INTERNAL] 1478 | # 1479 | # setup_serial_target(TARGET_NAME CMD) 1480 | # 1481 | # TARGET_NAME - Target name 1482 | # CMD - Serial terminal command 1483 | # 1484 | # Creates a target (${TARGET_NAME}-serial) for launching the serial termnial. 1485 | # 1486 | #=============================================================================# 1487 | function(setup_serial_target TARGET_NAME CMD SERIAL_PORT) 1488 | string(CONFIGURE "${CMD}" FULL_CMD @ONLY) 1489 | add_custom_target(${TARGET_NAME}-serial 1490 | COMMAND ${FULL_CMD}) 1491 | endfunction() 1492 | 1493 | 1494 | #=============================================================================# 1495 | # [PRIVATE/INTERNAL] 1496 | # 1497 | # detect_arduino_version(VAR_NAME) 1498 | # 1499 | # VAR_NAME - Variable name where the detected version will be saved 1500 | # 1501 | # Detects the Arduino SDK Version based on the revisions.txt file. The 1502 | # following variables will be generated: 1503 | # 1504 | # ${VAR_NAME} -> the full version (major.minor.patch) 1505 | # ${VAR_NAME}_MAJOR -> the major version 1506 | # ${VAR_NAME}_MINOR -> the minor version 1507 | # ${VAR_NAME}_PATCH -> the patch version 1508 | # 1509 | #=============================================================================# 1510 | function(detect_arduino_version VAR_NAME) 1511 | if(ARDUINO_VERSION_PATH) 1512 | file(READ ${ARDUINO_VERSION_PATH} RAW_VERSION) 1513 | if("${RAW_VERSION}" MATCHES " *[0]+([0-9]+)") 1514 | set(PARSED_VERSION 0.${CMAKE_MATCH_1}.0) 1515 | elseif("${RAW_VERSION}" MATCHES "[ ]*([0-9]+[.][0-9]+[.][0-9]+)") 1516 | set(PARSED_VERSION ${CMAKE_MATCH_1}) 1517 | elseif("${RAW_VERSION}" MATCHES "[ ]*([0-9]+[.][0-9]+)") 1518 | set(PARSED_VERSION ${CMAKE_MATCH_1}.0) 1519 | endif() 1520 | 1521 | if(NOT PARSED_VERSION STREQUAL "") 1522 | string(REPLACE "." ";" SPLIT_VERSION ${PARSED_VERSION}) 1523 | list(GET SPLIT_VERSION 0 SPLIT_VERSION_MAJOR) 1524 | list(GET SPLIT_VERSION 1 SPLIT_VERSION_MINOR) 1525 | list(GET SPLIT_VERSION 2 SPLIT_VERSION_PATCH) 1526 | 1527 | set(${VAR_NAME} "${PARSED_VERSION}" PARENT_SCOPE) 1528 | set(${VAR_NAME}_MAJOR "${SPLIT_VERSION_MAJOR}" PARENT_SCOPE) 1529 | set(${VAR_NAME}_MINOR "${SPLIT_VERSION_MINOR}" PARENT_SCOPE) 1530 | set(${VAR_NAME}_PATCH "${SPLIT_VERSION_PATCH}" PARENT_SCOPE) 1531 | endif() 1532 | endif() 1533 | endfunction() 1534 | 1535 | 1536 | #=============================================================================# 1537 | # [PRIVATE/INTERNAL] 1538 | # 1539 | # load_arduino_style_settings(SETTINGS_LIST SETTINGS_PATH) 1540 | # 1541 | # SETTINGS_LIST - Variable name of settings list 1542 | # SETTINGS_PATH - File path of settings file to load. 1543 | # 1544 | # Load a Arduino style settings file into the cache. 1545 | # 1546 | # Examples of this type of settings file is the boards.txt and 1547 | # programmers.txt files located in ${ARDUINO_SDK}/hardware/arduino. 1548 | # 1549 | # Settings have to following format: 1550 | # 1551 | # entry.setting[.subsetting] = value 1552 | # 1553 | # where [.subsetting] is optional 1554 | # 1555 | # For example, the following settings: 1556 | # 1557 | # uno.name=Arduino Uno 1558 | # uno.upload.protocol=stk500 1559 | # uno.upload.maximum_size=32256 1560 | # uno.build.mcu=atmega328p 1561 | # uno.build.core=arduino 1562 | # 1563 | # will generate the follwoing equivalent CMake variables: 1564 | # 1565 | # set(uno.name "Arduino Uno") 1566 | # set(uno.upload.protocol "stk500") 1567 | # set(uno.upload.maximum_size "32256") 1568 | # set(uno.build.mcu "atmega328p") 1569 | # set(uno.build.core "arduino") 1570 | # 1571 | # set(uno.SETTINGS name upload build) # List of settings for uno 1572 | # set(uno.upload.SUBSETTINGS protocol maximum_size) # List of sub-settings for uno.upload 1573 | # set(uno.build.SUBSETTINGS mcu core) # List of sub-settings for uno.build 1574 | # 1575 | # The ${ENTRY_NAME}.SETTINGS variable lists all settings for the entry, while 1576 | # ${ENTRY_NAME}.SUBSETTINGS variables lists all settings for a sub-setting of 1577 | # a entry setting pair. 1578 | # 1579 | # These variables are generated in order to be able to programatically traverse 1580 | # all settings (for a example see print_board_settings() function). 1581 | # 1582 | #=============================================================================# 1583 | function(LOAD_ARDUINO_STYLE_SETTINGS SETTINGS_LIST SETTINGS_PATH) 1584 | 1585 | if(NOT ${SETTINGS_LIST} AND EXISTS ${SETTINGS_PATH}) 1586 | file(STRINGS ${SETTINGS_PATH} FILE_ENTRIES) # Settings file split into lines 1587 | 1588 | foreach(FILE_ENTRY ${FILE_ENTRIES}) 1589 | if("${FILE_ENTRY}" MATCHES "^[^#]+=.*") 1590 | string(REGEX MATCH "^[^=]+" SETTING_NAME ${FILE_ENTRY}) 1591 | string(REGEX MATCH "[^=]+$" SETTING_VALUE ${FILE_ENTRY}) 1592 | string(REPLACE "." ";" ENTRY_NAME_TOKENS ${SETTING_NAME}) 1593 | string(STRIP "${SETTING_VALUE}" SETTING_VALUE) 1594 | 1595 | list(LENGTH ENTRY_NAME_TOKENS ENTRY_NAME_TOKENS_LEN) 1596 | 1597 | # Add entry to settings list if it does not exist 1598 | list(GET ENTRY_NAME_TOKENS 0 ENTRY_NAME) 1599 | list(FIND ${SETTINGS_LIST} ${ENTRY_NAME} ENTRY_NAME_INDEX) 1600 | if(ENTRY_NAME_INDEX LESS 0) 1601 | # Add entry to main list 1602 | list(APPEND ${SETTINGS_LIST} ${ENTRY_NAME}) 1603 | endif() 1604 | 1605 | # Add entry setting to entry settings list if it does not exist 1606 | set(ENTRY_SETTING_LIST ${ENTRY_NAME}.SETTINGS) 1607 | list(GET ENTRY_NAME_TOKENS 1 ENTRY_SETTING) 1608 | set(PARAMETERS 2) 1609 | if(ENTRY_SETTING STREQUAL "menu") 1610 | list(GET ENTRY_NAME_TOKENS 3 CPUNAME) 1611 | if(ENTRY_NAME_TOKENS_LEN GREATER 4) 1612 | list(GET ENTRY_NAME_TOKENS 4 PROPERTYNAME) 1613 | set(ENTRY_SETTING "menu.cpu.${CPUNAME}.${PROPERTYNAME}") 1614 | set(PARAMETERS 5) 1615 | else() 1616 | set(ENTRY_SETTING "menu.cpu.${CPUNAME}") 1617 | set(PARAMETERS 4) 1618 | endif() 1619 | list(APPEND ${ENTRY_SETTING_LIST} "${ENTRY_SETTING}") 1620 | else() 1621 | list(FIND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING} ENTRY_SETTING_INDEX) 1622 | if(ENTRY_SETTING_INDEX LESS 0) 1623 | # Add setting to entry 1624 | list(APPEND ${ENTRY_SETTING_LIST} ${ENTRY_SETTING}) 1625 | set(${ENTRY_SETTING_LIST} ${${ENTRY_SETTING_LIST}} 1626 | CACHE INTERNAL "Arduino ${ENTRY_NAME} Board settings list") 1627 | endif() 1628 | endif() 1629 | 1630 | set(FULL_SETTING_NAME ${ENTRY_NAME}.${ENTRY_SETTING}) 1631 | 1632 | # Add entry sub-setting to entry sub-settings list if it does not exists 1633 | if(ENTRY_NAME_TOKENS_LEN GREATER ${PARAMETERS}) 1634 | set(ENTRY_SUBSETTING_LIST ${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) 1635 | list(GET ENTRY_NAME_TOKENS ${PARAMETERS} ENTRY_SUBSETTING) 1636 | list(FIND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING} ENTRY_SUBSETTING_INDEX) 1637 | if(ENTRY_SUBSETTING_INDEX LESS 0) 1638 | list(APPEND ${ENTRY_SUBSETTING_LIST} ${ENTRY_SUBSETTING}) 1639 | set(${ENTRY_SUBSETTING_LIST} ${${ENTRY_SUBSETTING_LIST}} 1640 | CACHE INTERNAL "Arduino ${ENTRY_NAME} Board sub-settings list") 1641 | endif() 1642 | set(FULL_SETTING_NAME ${FULL_SETTING_NAME}.${ENTRY_SUBSETTING}) 1643 | endif() 1644 | 1645 | # Save setting value 1646 | set(${FULL_SETTING_NAME} ${SETTING_VALUE} 1647 | CACHE INTERNAL "Arduino ${ENTRY_NAME} Board setting") 1648 | 1649 | 1650 | endif() 1651 | endforeach() 1652 | set(${SETTINGS_LIST} ${${SETTINGS_LIST}} 1653 | CACHE STRING "List of detected Arduino Board configurations") 1654 | mark_as_advanced(${SETTINGS_LIST}) 1655 | endif() 1656 | endfunction() 1657 | 1658 | #=============================================================================# 1659 | # print_settings(ENTRY_NAME) 1660 | # 1661 | # ENTRY_NAME - name of entry 1662 | # 1663 | # Print the entry settings (see load_arduino_syle_settings()). 1664 | # 1665 | #=============================================================================# 1666 | function(PRINT_SETTINGS ENTRY_NAME) 1667 | if(${ENTRY_NAME}.SETTINGS) 1668 | 1669 | foreach(ENTRY_SETTING ${${ENTRY_NAME}.SETTINGS}) 1670 | if(${ENTRY_NAME}.${ENTRY_SETTING}) 1671 | message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}}") 1672 | endif() 1673 | if(${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS) 1674 | foreach(ENTRY_SUBSETTING ${${ENTRY_NAME}.${ENTRY_SETTING}.SUBSETTINGS}) 1675 | if(${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}) 1676 | message(STATUS " ${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}=${${ENTRY_NAME}.${ENTRY_SETTING}.${ENTRY_SUBSETTING}}") 1677 | endif() 1678 | endforeach() 1679 | endif() 1680 | message(STATUS "") 1681 | endforeach() 1682 | endif() 1683 | endfunction() 1684 | 1685 | #=============================================================================# 1686 | # [PRIVATE/INTERNAL] 1687 | # 1688 | # print_list(SETTINGS_LIST) 1689 | # 1690 | # SETTINGS_LIST - Variables name of settings list 1691 | # 1692 | # Print list settings and names (see load_arduino_syle_settings()). 1693 | #=============================================================================# 1694 | function(PRINT_LIST SETTINGS_LIST) 1695 | if(${SETTINGS_LIST}) 1696 | set(MAX_LENGTH 0) 1697 | foreach(ENTRY_NAME ${${SETTINGS_LIST}}) 1698 | string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) 1699 | if(CURRENT_LENGTH GREATER MAX_LENGTH) 1700 | set(MAX_LENGTH ${CURRENT_LENGTH}) 1701 | endif() 1702 | endforeach() 1703 | foreach(ENTRY_NAME ${${SETTINGS_LIST}}) 1704 | string(LENGTH "${ENTRY_NAME}" CURRENT_LENGTH) 1705 | math(EXPR PADDING_LENGTH "${MAX_LENGTH}-${CURRENT_LENGTH}") 1706 | set(PADDING "") 1707 | foreach(X RANGE ${PADDING_LENGTH}) 1708 | set(PADDING "${PADDING} ") 1709 | endforeach() 1710 | message(STATUS " ${PADDING}${ENTRY_NAME}: ${${ENTRY_NAME}.name}") 1711 | endforeach() 1712 | endif() 1713 | endfunction() 1714 | 1715 | #=============================================================================# 1716 | # [PRIVATE/INTERNAL] 1717 | # 1718 | # setup_arduino_example(TARGET_NAME LIBRARY_NAME EXAMPLE_NAME OUTPUT_VAR) 1719 | # 1720 | # TARGET_NAME - Target name 1721 | # LIBRARY_NAME - Library name 1722 | # EXAMPLE_NAME - Example name 1723 | # OUTPUT_VAR - Variable name to save sketch path. 1724 | # 1725 | # Creates a Arduino example from a the specified library. 1726 | #=============================================================================# 1727 | function(SETUP_ARDUINO_EXAMPLE TARGET_NAME LIBRARY_NAME EXAMPLE_NAME OUTPUT_VAR) 1728 | set(EXAMPLE_SKETCH_PATH ) 1729 | 1730 | get_property(LIBRARY_SEARCH_PATH 1731 | DIRECTORY # Property Scope 1732 | PROPERTY LINK_DIRECTORIES) 1733 | foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${${ARDUINO_PLATFORM}_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries) 1734 | message(STATUS "Search ${LIBRARY_NAME} example directory in ${LIB_SEARCH_PATH}") 1735 | if(EXISTS "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") 1736 | set(EXAMPLE_SKETCH_PATH "${LIB_SEARCH_PATH}/${LIBRARY_NAME}/examples/${EXAMPLE_NAME}") 1737 | break() 1738 | endif() 1739 | endforeach() 1740 | 1741 | if(EXAMPLE_SKETCH_PATH) 1742 | setup_arduino_sketch(${TARGET_NAME} ${EXAMPLE_SKETCH_PATH} SKETCH_CPP) 1743 | set("${OUTPUT_VAR}" ${${OUTPUT_VAR}} ${SKETCH_CPP} PARENT_SCOPE) 1744 | else() 1745 | message(FATAL_ERROR "Could not find example ${EXAMPLE_NAME} from library ${LIBRARY_NAME}") 1746 | endif() 1747 | endfunction() 1748 | 1749 | #=============================================================================# 1750 | # [PRIVATE/INTERNAL] 1751 | # 1752 | # setup_arduino_sketch(TARGET_NAME SKETCH_PATH OUTPUT_VAR) 1753 | # 1754 | # TARGET_NAME - Target name 1755 | # SKETCH_PATH - Path to sketch directory 1756 | # OUTPUT_VAR - Variable name where to save generated sketch source 1757 | # 1758 | # Generates C++ sources from Arduino Sketch. 1759 | #=============================================================================# 1760 | function(SETUP_ARDUINO_SKETCH TARGET_NAME SKETCH_PATH OUTPUT_VAR) 1761 | get_filename_component(SKETCH_NAME "${SKETCH_PATH}" NAME) 1762 | get_filename_component(SKETCH_PATH "${SKETCH_PATH}" ABSOLUTE) 1763 | 1764 | if(EXISTS "${SKETCH_PATH}") 1765 | set(SKETCH_CPP ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}_${SKETCH_NAME}.cpp) 1766 | 1767 | if (IS_DIRECTORY "${SKETCH_PATH}") 1768 | # Sketch directory specified, try to find main sketch... 1769 | set(MAIN_SKETCH ${SKETCH_PATH}/${SKETCH_NAME}) 1770 | 1771 | if(EXISTS "${MAIN_SKETCH}.pde") 1772 | set(MAIN_SKETCH "${MAIN_SKETCH}.pde") 1773 | elseif(EXISTS "${MAIN_SKETCH}.ino") 1774 | set(MAIN_SKETCH "${MAIN_SKETCH}.ino") 1775 | else() 1776 | message(FATAL_ERROR "Could not find main sketch (${SKETCH_NAME}.pde or ${SKETCH_NAME}.ino) at ${SKETCH_PATH}! Please specify the main sketch file path instead of directory.") 1777 | endif() 1778 | else() 1779 | # Sektch file specified, assuming parent directory as sketch directory 1780 | set(MAIN_SKETCH ${SKETCH_PATH}) 1781 | get_filename_component(SKETCH_PATH "${SKETCH_PATH}" PATH) 1782 | endif() 1783 | arduino_debug_msg("sketch: ${MAIN_SKETCH}") 1784 | 1785 | # Find all sketch files 1786 | file(GLOB SKETCH_SOURCES ${SKETCH_PATH}/*.pde ${SKETCH_PATH}/*.ino) 1787 | list(REMOVE_ITEM SKETCH_SOURCES ${MAIN_SKETCH}) 1788 | list(SORT SKETCH_SOURCES) 1789 | 1790 | generate_cpp_from_sketch("${MAIN_SKETCH}" "${SKETCH_SOURCES}" "${SKETCH_CPP}") 1791 | 1792 | # Regenerate build system if sketch changes 1793 | add_custom_command(OUTPUT ${SKETCH_CPP} 1794 | COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR} 1795 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} 1796 | DEPENDS ${MAIN_SKETCH} ${SKETCH_SOURCES} 1797 | COMMENT "Regnerating ${SKETCH_NAME} Sketch") 1798 | set_source_files_properties(${SKETCH_CPP} PROPERTIES GENERATED TRUE) 1799 | # Mark file that it exists for find_file 1800 | set_source_files_properties(${SKETCH_CPP} PROPERTIES GENERATED_SKETCH TRUE) 1801 | 1802 | set("${OUTPUT_VAR}" ${${OUTPUT_VAR}} ${SKETCH_CPP} PARENT_SCOPE) 1803 | else() 1804 | message(FATAL_ERROR "Sketch does not exist: ${SKETCH_PATH}") 1805 | endif() 1806 | endfunction() 1807 | 1808 | 1809 | #=============================================================================# 1810 | # [PRIVATE/INTERNAL] 1811 | # 1812 | # generate_cpp_from_sketch(MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) 1813 | # 1814 | # MAIN_SKETCH_PATH - Main sketch file path 1815 | # SKETCH_SOURCES - Setch source paths 1816 | # SKETCH_CPP - Name of file to generate 1817 | # 1818 | # Generate C++ source file from Arduino sketch files. 1819 | #=============================================================================# 1820 | function(GENERATE_CPP_FROM_SKETCH MAIN_SKETCH_PATH SKETCH_SOURCES SKETCH_CPP) 1821 | file(WRITE ${SKETCH_CPP} "// automatically generated by arduino-cmake\n") 1822 | file(READ ${MAIN_SKETCH_PATH} MAIN_SKETCH) 1823 | 1824 | # remove comments 1825 | remove_comments(MAIN_SKETCH MAIN_SKETCH_NO_COMMENTS) 1826 | 1827 | # find first statement 1828 | string(REGEX MATCH "[\n][_a-zA-Z0-9]+[^\n]*" FIRST_STATEMENT "${MAIN_SKETCH_NO_COMMENTS}") 1829 | string(FIND "${MAIN_SKETCH}" "${FIRST_STATEMENT}" HEAD_LENGTH) 1830 | if ("${HEAD_LENGTH}" STREQUAL "-1") 1831 | set(HEAD_LENGTH 0) 1832 | endif() 1833 | #message(STATUS "FIRST STATEMENT: ${FIRST_STATEMENT}") 1834 | #message(STATUS "FIRST STATEMENT POSITION: ${HEAD_LENGTH}") 1835 | string(LENGTH "${MAIN_SKETCH}" MAIN_SKETCH_LENGTH) 1836 | 1837 | string(SUBSTRING "${MAIN_SKETCH}" 0 ${HEAD_LENGTH} SKETCH_HEAD) 1838 | #arduino_debug_msg("SKETCH_HEAD:\n${SKETCH_HEAD}") 1839 | 1840 | # find the body of the main pde 1841 | math(EXPR BODY_LENGTH "${MAIN_SKETCH_LENGTH}-${HEAD_LENGTH}") 1842 | string(SUBSTRING "${MAIN_SKETCH}" "${HEAD_LENGTH}+1" "${BODY_LENGTH}-1" SKETCH_BODY) 1843 | #arduino_debug_msg("BODY:\n${SKETCH_BODY}") 1844 | 1845 | # write the file head 1846 | file(APPEND ${SKETCH_CPP} "#line 1 \"${MAIN_SKETCH_PATH}\"\n${SKETCH_HEAD}") 1847 | 1848 | # Count head line offset (for GCC error reporting) 1849 | file(STRINGS ${SKETCH_CPP} SKETCH_HEAD_LINES) 1850 | list(LENGTH SKETCH_HEAD_LINES SKETCH_HEAD_LINES_COUNT) 1851 | math(EXPR SKETCH_HEAD_OFFSET "${SKETCH_HEAD_LINES_COUNT}+2") 1852 | 1853 | # add arduino include header 1854 | #file(APPEND ${SKETCH_CPP} "\n#line 1 \"autogenerated\"\n") 1855 | file(APPEND ${SKETCH_CPP} "\n#line ${SKETCH_HEAD_OFFSET} \"${SKETCH_CPP}\"\n") 1856 | if(ARDUINO_SDK_VERSION VERSION_LESS 1.0) 1857 | file(APPEND ${SKETCH_CPP} "#include \"WProgram.h\"\n") 1858 | else() 1859 | file(APPEND ${SKETCH_CPP} "#include \"Arduino.h\"\n") 1860 | endif() 1861 | 1862 | # add function prototypes 1863 | foreach(SKETCH_SOURCE_PATH ${SKETCH_SOURCES} ${MAIN_SKETCH_PATH}) 1864 | arduino_debug_msg("Sketch: ${SKETCH_SOURCE_PATH}") 1865 | file(READ ${SKETCH_SOURCE_PATH} SKETCH_SOURCE) 1866 | remove_comments(SKETCH_SOURCE SKETCH_SOURCE) 1867 | 1868 | set(ALPHA "a-zA-Z") 1869 | set(NUM "0-9") 1870 | set(ALPHANUM "${ALPHA}${NUM}") 1871 | set(WORD "_${ALPHANUM}") 1872 | set(LINE_START "(^|[\n])") 1873 | set(QUALIFIERS "[ \t]*([${ALPHA}]+[ ])*") 1874 | set(TYPE "[${WORD}]+([ ]*[\n][\t]*|[ ])+") 1875 | set(FNAME "[${WORD}]+[ ]?[\n]?[\t]*[ ]*") 1876 | set(FARGS "[(]([\t]*[ ]*[*&]?[ ]?[${WORD}](\\[([${NUM}]+)?\\])*[,]?[ ]*[\n]?)*([,]?[ ]*[\n]?)?[)]") 1877 | set(BODY_START "([ ]*[\n][\t]*|[ ]|[\n])*{") 1878 | set(PROTOTYPE_PATTERN "${LINE_START}${QUALIFIERS}${TYPE}${FNAME}${FARGS}${BODY_START}") 1879 | 1880 | string(REGEX MATCHALL "${PROTOTYPE_PATTERN}" SKETCH_PROTOTYPES "${SKETCH_SOURCE}") 1881 | 1882 | # Write function prototypes 1883 | file(APPEND ${SKETCH_CPP} "\n//=== START Forward: ${SKETCH_SOURCE_PATH}\n") 1884 | foreach(SKETCH_PROTOTYPE ${SKETCH_PROTOTYPES}) 1885 | string(REPLACE "\n" " " SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") 1886 | string(REPLACE "{" "" SKETCH_PROTOTYPE "${SKETCH_PROTOTYPE}") 1887 | arduino_debug_msg("\tprototype: ${SKETCH_PROTOTYPE};") 1888 | # " else if(var == other) {" shoudn't be listed as prototype 1889 | if(NOT SKETCH_PROTOTYPE MATCHES "(if[ ]?[\n]?[\t]*[ ]*[)])") 1890 | file(APPEND ${SKETCH_CPP} "${SKETCH_PROTOTYPE};\n") 1891 | else() 1892 | arduino_debug_msg("\trejected prototype: ${SKETCH_PROTOTYPE};") 1893 | endif() 1894 | file(APPEND ${SKETCH_CPP} "${SKETCH_PROTOTYPE};\n") 1895 | endforeach() 1896 | file(APPEND ${SKETCH_CPP} "//=== END Forward: ${SKETCH_SOURCE_PATH}\n") 1897 | endforeach() 1898 | 1899 | # Write Sketch CPP source 1900 | get_num_lines("${SKETCH_HEAD}" HEAD_NUM_LINES) 1901 | file(APPEND ${SKETCH_CPP} "#line ${HEAD_NUM_LINES} \"${MAIN_SKETCH_PATH}\"\n") 1902 | file(APPEND ${SKETCH_CPP} "\n${SKETCH_BODY}") 1903 | foreach (SKETCH_SOURCE_PATH ${SKETCH_SOURCES}) 1904 | file(READ ${SKETCH_SOURCE_PATH} SKETCH_SOURCE) 1905 | file(APPEND ${SKETCH_CPP} "\n//=== START : ${SKETCH_SOURCE_PATH}\n") 1906 | file(APPEND ${SKETCH_CPP} "#line 1 \"${SKETCH_SOURCE_PATH}\"\n") 1907 | file(APPEND ${SKETCH_CPP} "${SKETCH_SOURCE}") 1908 | file(APPEND ${SKETCH_CPP} "\n//=== END : ${SKETCH_SOURCE_PATH}\n") 1909 | endforeach() 1910 | endfunction() 1911 | 1912 | #=============================================================================# 1913 | # [PRIVATE/INTERNAL] 1914 | # 1915 | # setup_arduino_size_script(OUTPUT_VAR) 1916 | # 1917 | # OUTPUT_VAR - Output variable that will contain the script path 1918 | # 1919 | # Generates script used to display the firmware size. 1920 | #=============================================================================# 1921 | function(SETUP_ARDUINO_SIZE_SCRIPT OUTPUT_VAR) 1922 | set(ARDUINO_SIZE_SCRIPT_PATH ${CMAKE_BINARY_DIR}/CMakeFiles/FirmwareSize.cmake) 1923 | 1924 | file(WRITE ${ARDUINO_SIZE_SCRIPT_PATH} " 1925 | set(AVRSIZE_PROGRAM \"${AVRSIZE_PROGRAM}\") 1926 | set(AVRSIZE_FLAGS -C --mcu=\${MCU}) 1927 | 1928 | execute_process(COMMAND \${AVRSIZE_PROGRAM} \${AVRSIZE_FLAGS} \${FIRMWARE_IMAGE} \${EEPROM_IMAGE} 1929 | OUTPUT_VARIABLE SIZE_OUTPUT) 1930 | 1931 | 1932 | string(STRIP \"\${SIZE_OUTPUT}\" RAW_SIZE_OUTPUT) 1933 | 1934 | # Convert lines into a list 1935 | string(REPLACE \"\\n\" \";\" SIZE_OUTPUT_LIST \"\${SIZE_OUTPUT}\") 1936 | 1937 | set(SIZE_OUTPUT_LINES) 1938 | foreach(LINE \${SIZE_OUTPUT_LIST}) 1939 | if(NOT \"\${LINE}\" STREQUAL \"\") 1940 | list(APPEND SIZE_OUTPUT_LINES \"\${LINE}\") 1941 | endif() 1942 | endforeach() 1943 | 1944 | function(EXTRACT LIST_NAME INDEX VARIABLE) 1945 | list(GET \"\${LIST_NAME}\" \${INDEX} RAW_VALUE) 1946 | string(STRIP \"\${RAW_VALUE}\" VALUE) 1947 | 1948 | set(\${VARIABLE} \"\${VALUE}\" PARENT_SCOPE) 1949 | endfunction() 1950 | function(PARSE INPUT VARIABLE_PREFIX) 1951 | if(\${INPUT} MATCHES \"([^:]+):[ \\t]*([0-9]+)[ \\t]*([^ \\t]+)[ \\t]*[(]([0-9.]+)%.*\") 1952 | set(ENTRY_NAME \${CMAKE_MATCH_1}) 1953 | set(ENTRY_SIZE \${CMAKE_MATCH_2}) 1954 | set(ENTRY_SIZE_TYPE \${CMAKE_MATCH_3}) 1955 | set(ENTRY_PERCENT \${CMAKE_MATCH_4}) 1956 | endif() 1957 | 1958 | set(\${VARIABLE_PREFIX}_NAME \${ENTRY_NAME} PARENT_SCOPE) 1959 | set(\${VARIABLE_PREFIX}_SIZE \${ENTRY_SIZE} PARENT_SCOPE) 1960 | set(\${VARIABLE_PREFIX}_SIZE_TYPE \${ENTRY_SIZE_TYPE} PARENT_SCOPE) 1961 | set(\${VARIABLE_PREFIX}_PERCENT \${ENTRY_PERCENT} PARENT_SCOPE) 1962 | endfunction() 1963 | 1964 | list(LENGTH SIZE_OUTPUT_LINES SIZE_OUTPUT_LENGTH) 1965 | #message(\"\${SIZE_OUTPUT_LINES}\") 1966 | #message(\"\${SIZE_OUTPUT_LENGTH}\") 1967 | if (\${SIZE_OUTPUT_LENGTH} STREQUAL 14) 1968 | EXTRACT(SIZE_OUTPUT_LINES 3 FIRMWARE_PROGRAM_SIZE_ROW) 1969 | EXTRACT(SIZE_OUTPUT_LINES 5 FIRMWARE_DATA_SIZE_ROW) 1970 | PARSE(FIRMWARE_PROGRAM_SIZE_ROW FIRMWARE_PROGRAM) 1971 | PARSE(FIRMWARE_DATA_SIZE_ROW FIRMWARE_DATA) 1972 | 1973 | set(FIRMWARE_STATUS \"Firmware Size: \") 1974 | set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} [\${FIRMWARE_PROGRAM_NAME}: \${FIRMWARE_PROGRAM_SIZE} \${FIRMWARE_PROGRAM_SIZE_TYPE} (\${FIRMWARE_PROGRAM_PERCENT}%)] \") 1975 | set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} [\${FIRMWARE_DATA_NAME}: \${FIRMWARE_DATA_SIZE} \${FIRMWARE_DATA_SIZE_TYPE} (\${FIRMWARE_DATA_PERCENT}%)]\") 1976 | set(FIRMWARE_STATUS \"\${FIRMWARE_STATUS} on \${MCU}\") 1977 | 1978 | EXTRACT(SIZE_OUTPUT_LINES 10 EEPROM_PROGRAM_SIZE_ROW) 1979 | EXTRACT(SIZE_OUTPUT_LINES 12 EEPROM_DATA_SIZE_ROW) 1980 | PARSE(EEPROM_PROGRAM_SIZE_ROW EEPROM_PROGRAM) 1981 | PARSE(EEPROM_DATA_SIZE_ROW EEPROM_DATA) 1982 | 1983 | set(EEPROM_STATUS \"EEPROM Size: \") 1984 | set(EEPROM_STATUS \"\${EEPROM_STATUS} [\${EEPROM_PROGRAM_NAME}: \${EEPROM_PROGRAM_SIZE} \${EEPROM_PROGRAM_SIZE_TYPE} (\${EEPROM_PROGRAM_PERCENT}%)] \") 1985 | set(EEPROM_STATUS \"\${EEPROM_STATUS} [\${EEPROM_DATA_NAME}: \${EEPROM_DATA_SIZE} \${EEPROM_DATA_SIZE_TYPE} (\${EEPROM_DATA_PERCENT}%)]\") 1986 | set(EEPROM_STATUS \"\${EEPROM_STATUS} on \${MCU}\") 1987 | 1988 | message(\"\${FIRMWARE_STATUS}\") 1989 | message(\"\${EEPROM_STATUS}\\n\") 1990 | 1991 | if(\$ENV{VERBOSE}) 1992 | message(\"\${RAW_SIZE_OUTPUT}\\n\") 1993 | elseif(\$ENV{VERBOSE_SIZE}) 1994 | message(\"\${RAW_SIZE_OUTPUT}\\n\") 1995 | endif() 1996 | else() 1997 | message(\"\${RAW_SIZE_OUTPUT}\") 1998 | endif() 1999 | ") 2000 | 2001 | set(${OUTPUT_VAR} ${ARDUINO_SIZE_SCRIPT_PATH} PARENT_SCOPE) 2002 | endfunction() 2003 | 2004 | 2005 | #=============================================================================# 2006 | # [PRIVATE/INTERNAL] 2007 | # 2008 | # arduino_debug_on() 2009 | # 2010 | # Enables Arduino module debugging. 2011 | #=============================================================================# 2012 | function(ARDUINO_DEBUG_ON) 2013 | set(ARDUINO_DEBUG True PARENT_SCOPE) 2014 | endfunction() 2015 | 2016 | 2017 | #=============================================================================# 2018 | # [PRIVATE/INTERNAL] 2019 | # 2020 | # arduino_debug_off() 2021 | # 2022 | # Disables Arduino module debugging. 2023 | #=============================================================================# 2024 | function(ARDUINO_DEBUG_OFF) 2025 | set(ARDUINO_DEBUG False PARENT_SCOPE) 2026 | endfunction() 2027 | 2028 | 2029 | #=============================================================================# 2030 | # [PRIVATE/INTERNAL] 2031 | # 2032 | # arduino_debug_msg(MSG) 2033 | # 2034 | # MSG - Message to print 2035 | # 2036 | # Print Arduino debugging information. In order to enable printing 2037 | # use arduino_debug_on() and to disable use arduino_debug_off(). 2038 | #=============================================================================# 2039 | function(ARDUINO_DEBUG_MSG MSG) 2040 | if(ARDUINO_DEBUG) 2041 | message("## ${MSG}") 2042 | endif() 2043 | endfunction() 2044 | 2045 | #=============================================================================# 2046 | # [PRIVATE/INTERNAL] 2047 | # 2048 | # remove_comments(SRC_VAR OUT_VAR) 2049 | # 2050 | # SRC_VAR - variable holding sources 2051 | # OUT_VAR - variable holding sources with no comments 2052 | # 2053 | # Removes all comments from the source code. 2054 | #=============================================================================# 2055 | function(REMOVE_COMMENTS SRC_VAR OUT_VAR) 2056 | string(REGEX REPLACE "[\\./\\\\]" "_" FILE "${NAME}") 2057 | 2058 | set(SRC ${${SRC_VAR}}) 2059 | 2060 | #message(STATUS "removing comments from: ${FILE}") 2061 | #file(WRITE "${CMAKE_BINARY_DIR}/${FILE}_pre_remove_comments.txt" ${SRC}) 2062 | #message(STATUS "\n${SRC}") 2063 | 2064 | # remove all comments 2065 | string(REGEX REPLACE "([/][/][^\n]*)|([/][\\*]([^\\*]|([\\*]+[^/\\*]))*[\\*]+[/])" "" OUT "${SRC}") 2066 | 2067 | #file(WRITE "${CMAKE_BINARY_DIR}/${FILE}_post_remove_comments.txt" ${SRC}) 2068 | #message(STATUS "\n${SRC}") 2069 | 2070 | set(${OUT_VAR} ${OUT} PARENT_SCOPE) 2071 | 2072 | endfunction() 2073 | 2074 | #=============================================================================# 2075 | # [PRIVATE/INTERNAL] 2076 | # 2077 | # get_num_lines(DOCUMENT OUTPUT_VAR) 2078 | # 2079 | # DOCUMENT - Document contents 2080 | # OUTPUT_VAR - Variable which will hold the line number count 2081 | # 2082 | # Counts the line number of the document. 2083 | #=============================================================================# 2084 | function(GET_NUM_LINES DOCUMENT OUTPUT_VAR) 2085 | string(REGEX MATCHALL "[\n]" MATCH_LIST "${DOCUMENT}") 2086 | list(LENGTH MATCH_LIST NUM) 2087 | set(${OUTPUT_VAR} ${NUM} PARENT_SCOPE) 2088 | endfunction() 2089 | 2090 | #=============================================================================# 2091 | # [PRIVATE/INTERNAL] 2092 | # 2093 | # required_variables(MSG msg VARS var1 var2 .. varN) 2094 | # 2095 | # MSG - Message to be displayed in case of error 2096 | # VARS - List of variables names to check 2097 | # 2098 | # Ensure the specified variables are not empty, otherwise a fatal error is emmited. 2099 | #=============================================================================# 2100 | function(REQUIRED_VARIABLES) 2101 | cmake_parse_arguments(INPUT "" "MSG" "VARS" ${ARGN}) 2102 | error_for_unparsed(INPUT) 2103 | foreach(VAR ${INPUT_VARS}) 2104 | if ("${${VAR}}" STREQUAL "") 2105 | message(FATAL_ERROR "${VAR} not set: ${INPUT_MSG}") 2106 | endif() 2107 | endforeach() 2108 | endfunction() 2109 | 2110 | #=============================================================================# 2111 | # [PRIVATE/INTERNAL] 2112 | # 2113 | # error_for_unparsed(PREFIX) 2114 | # 2115 | # PREFIX - Prefix name 2116 | # 2117 | # Emit fatal error if there are unparsed argument from cmake_parse_arguments(). 2118 | #=============================================================================# 2119 | function(ERROR_FOR_UNPARSED PREFIX) 2120 | set(ARGS "${${PREFIX}_UNPARSED_ARGUMENTS}") 2121 | if (NOT ( "${ARGS}" STREQUAL "") ) 2122 | message(FATAL_ERROR "unparsed argument: ${ARGS}") 2123 | endif() 2124 | endfunction() 2125 | 2126 | 2127 | 2128 | 2129 | 2130 | 2131 | #=============================================================================# 2132 | # C Flags 2133 | #=============================================================================# 2134 | if (NOT DEFINED ARDUINO_C_FLAGS) 2135 | set(ARDUINO_C_FLAGS "-g -Os -w -ffunction-sections -fdata-sections -MMD") 2136 | endif (NOT DEFINED ARDUINO_C_FLAGS) 2137 | set(CMAKE_C_FLAGS "${ARDUINO_C_FLAGS}" CACHE STRING "") 2138 | set(CMAKE_C_FLAGS_DEBUG "${ARDUINO_C_FLAGS}" CACHE STRING "") 2139 | set(CMAKE_C_FLAGS_MINSIZEREL "${ARDUINO_C_FLAGS}" CACHE STRING "") 2140 | set(CMAKE_C_FLAGS_RELEASE "${ARDUINO_C_FLAGS}" CACHE STRING "") 2141 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "${ARDUINO_C_FLAGS}" CACHE STRING "") 2142 | 2143 | #=============================================================================# 2144 | # C++ Flags 2145 | #=============================================================================# 2146 | if (NOT DEFINED ARDUINO_CXX_FLAGS) 2147 | set(ARDUINO_CXX_FLAGS "-g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD") 2148 | endif (NOT DEFINED ARDUINO_CXX_FLAGS) 2149 | set(CMAKE_CXX_FLAGS "${ARDUINO_CXX_FLAGS}" CACHE STRING "") 2150 | set(CMAKE_CXX_FLAGS_DEBUG "${ARDUINO_CXX_FLAGS}" CACHE STRING "") 2151 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${ARDUINO_CXX_FLAGS}" CACHE STRING "") 2152 | set(CMAKE_CXX_FLAGS_RELEASE "${ARDUINO_CXX_FLAGS}" CACHE STRING "") 2153 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${ARDUINO_CXX_FLAGS}" CACHE STRING "") 2154 | 2155 | #=============================================================================# 2156 | # Executable Linker Flags # 2157 | #=============================================================================# 2158 | set(ARDUINO_LINKER_FLAGS "-w -Os -Wl,--gc-sections") 2159 | set(CMAKE_EXE_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2160 | set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2161 | set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2162 | set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2163 | set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2164 | 2165 | #=============================================================================# 2166 | #=============================================================================# 2167 | # Shared Lbrary Linker Flags # 2168 | #=============================================================================# 2169 | set(CMAKE_SHARED_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2170 | set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2171 | set(CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2172 | set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2173 | set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2174 | 2175 | set(CMAKE_MODULE_LINKER_FLAGS "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2176 | set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2177 | set(CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2178 | set(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2179 | set(CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO "${ARDUINO_LINKER_FLAGS}" CACHE STRING "") 2180 | 2181 | 2182 | #=============================================================================# 2183 | # Arduino Settings 2184 | #=============================================================================# 2185 | set(ARDUINO_OBJCOPY_EEP_FLAGS -O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load 2186 | --no-change-warnings --change-section-lma .eeprom=0 CACHE STRING "") 2187 | set(ARDUINO_OBJCOPY_HEX_FLAGS -O ihex -R .eeprom CACHE STRING "") 2188 | set(ARDUINO_AVRDUDE_FLAGS -V CACHE STRING "") 2189 | 2190 | #=============================================================================# 2191 | # Initialization 2192 | #=============================================================================# 2193 | if(NOT ARDUINO_FOUND AND ARDUINO_SDK_PATH) 2194 | register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/arduino/) 2195 | 2196 | find_file(ARDUINO_LIBRARIES_PATH 2197 | NAMES libraries 2198 | PATHS ${ARDUINO_SDK_PATH} 2199 | DOC "Path to directory containing the Arduino libraries." 2200 | NO_SYSTEM_ENVIRONMENT_PATH) 2201 | 2202 | find_file(ARDUINO_VERSION_PATH 2203 | NAMES lib/version.txt 2204 | PATHS ${ARDUINO_SDK_PATH} 2205 | DOC "Path to Arduino version file." 2206 | NO_SYSTEM_ENVIRONMENT_PATH) 2207 | 2208 | find_program(ARDUINO_AVRDUDE_PROGRAM 2209 | NAMES avrdude 2210 | PATHS ${ARDUINO_SDK_PATH} 2211 | PATH_SUFFIXES hardware/tools hardware/tools/avr/bin 2212 | NO_DEFAULT_PATH) 2213 | 2214 | find_program(ARDUINO_AVRDUDE_PROGRAM 2215 | NAMES avrdude 2216 | DOC "Path to avrdude programmer binary.") 2217 | 2218 | find_program(AVRSIZE_PROGRAM 2219 | NAMES avr-size) 2220 | 2221 | find_file(ARDUINO_AVRDUDE_CONFIG_PATH 2222 | NAMES avrdude.conf 2223 | PATHS ${ARDUINO_SDK_PATH} /etc/avrdude /etc 2224 | PATH_SUFFIXES hardware/tools 2225 | hardware/tools/avr/etc 2226 | DOC "Path to avrdude programmer configuration file." 2227 | NO_SYSTEM_ENVIRONMENT_PATH) 2228 | 2229 | if(NOT CMAKE_OBJCOPY) 2230 | find_program(AVROBJCOPY_PROGRAM 2231 | avr-objcopy) 2232 | set(ADDITIONAL_REQUIRED_VARS AVROBJCOPY_PROGRAM) 2233 | set(CMAKE_OBJCOPY ${AVROBJCOPY_PROGRAM} CACHE PATH "OBJCOPY Program for firmware convertion in hex") 2234 | endif(NOT CMAKE_OBJCOPY) 2235 | 2236 | set(ARDUINO_DEFAULT_BOARD uno CACHE STRING "Default Arduino Board ID when not specified.") 2237 | set(ARDUINO_DEFAULT_PORT CACHE STRING "Default Arduino port when not specified.") 2238 | set(ARDUINO_DEFAULT_SERIAL CACHE STRING "Default Arduino Serial command when not specified.") 2239 | set(ARDUINO_DEFAULT_PROGRAMMER CACHE STRING "Default Arduino Programmer ID when not specified.") 2240 | 2241 | # Ensure that all required paths are found 2242 | required_variables(VARS 2243 | ARDUINO_PLATFORMS 2244 | ARDUINO_CORES_PATH 2245 | ARDUINO_BOOTLOADERS_PATH 2246 | ARDUINO_LIBRARIES_PATH 2247 | ARDUINO_BOARDS_PATH 2248 | ARDUINO_PROGRAMMERS_PATH 2249 | ARDUINO_VERSION_PATH 2250 | ARDUINO_AVRDUDE_FLAGS 2251 | ARDUINO_AVRDUDE_PROGRAM 2252 | ARDUINO_AVRDUDE_CONFIG_PATH 2253 | AVRSIZE_PROGRAM 2254 | ${ADDITIONAL_REQUIRED_VARS} 2255 | MSG "Invalid Arduino SDK path (${ARDUINO_SDK_PATH}).\n") 2256 | 2257 | detect_arduino_version(ARDUINO_SDK_VERSION) 2258 | set(ARDUINO_SDK_VERSION ${ARDUINO_SDK_VERSION} CACHE STRING "Arduino SDK Version") 2259 | set(ARDUINO_SDK_VERSION_MAJOR ${ARDUINO_SDK_VERSION_MAJOR} CACHE STRING "Arduino SDK Major Version") 2260 | set(ARDUINO_SDK_VERSION_MINOR ${ARDUINO_SDK_VERSION_MINOR} CACHE STRING "Arduino SDK Minor Version") 2261 | set(ARDUINO_SDK_VERSION_PATCH ${ARDUINO_SDK_VERSION_PATCH} CACHE STRING "Arduino SDK Patch Version") 2262 | 2263 | if(ARDUINO_SDK_VERSION VERSION_LESS 0.19) 2264 | message(FATAL_ERROR "Unsupported Arduino SDK (require verion 0.19 or higher)") 2265 | endif() 2266 | 2267 | message(STATUS "Arduino SDK version ${ARDUINO_SDK_VERSION}: ${ARDUINO_SDK_PATH}") 2268 | 2269 | setup_arduino_size_script(ARDUINO_SIZE_SCRIPT) 2270 | set(ARDUINO_SIZE_SCRIPT ${ARDUINO_SIZE_SCRIPT} CACHE INTERNAL "Arduino Size Script") 2271 | 2272 | #print_board_list() 2273 | #print_programmer_list() 2274 | 2275 | set(ARDUINO_FOUND True CACHE INTERNAL "Arduino Found") 2276 | mark_as_advanced( 2277 | ARDUINO_CORES_PATH 2278 | ARDUINO_VARIANTS_PATH 2279 | ARDUINO_BOOTLOADERS_PATH 2280 | ARDUINO_LIBRARIES_PATH 2281 | ARDUINO_BOARDS_PATH 2282 | ARDUINO_PROGRAMMERS_PATH 2283 | ARDUINO_VERSION_PATH 2284 | ARDUINO_AVRDUDE_FLAGS 2285 | ARDUINO_AVRDUDE_PROGRAM 2286 | ARDUINO_AVRDUDE_CONFIG_PATH 2287 | ARDUINO_OBJCOPY_EEP_FLAGS 2288 | ARDUINO_OBJCOPY_HEX_FLAGS 2289 | AVRSIZE_PROGRAM) 2290 | endif() 2291 | 2292 | if(ARDUINO_SDK_VERSION VERSION_LESS 1.5) 2293 | set(ARDUINO_PLATFORM "AVR") 2294 | else() 2295 | if(NOT ARDUINO_PLATFORM) 2296 | register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/arduino/avr) 2297 | set(ARDUINO_PLATFORM "AVR") 2298 | else() 2299 | string(TOLOWER ${ARDUINO_PLATFORM} _platform) 2300 | register_hardware_platform(${ARDUINO_SDK_PATH}/hardware/arduino/${_platform}) 2301 | endif() 2302 | endif() 2303 | 2304 | 2305 | -------------------------------------------------------------------------------- /main.ino: -------------------------------------------------------------------------------- 1 | #include "MagSpoof.h" 2 | 3 | #define PIN_A 3 // L293D pin 2 4 | #define PIN_B 4 // L293D pin 7 5 | #define PIN_ENABLE 13 // L293D pin 1; Using Arduino pin 13 to switch on embedded LED during transmission 6 | #define CLOCK_US 400 // Delay for bit transmission, in micro seconds 7 | 8 | MagSpoof magSpoof(PIN_A, PIN_B, PIN_ENABLE, CLOCK_US, MagSpoof::BPC7, MagSpoof::Odd); 9 | 10 | const char* testTracks[] = 11 | { 12 | "%B123456781234567^LASTNAME/FIRST^YYMMSSSDDDDDDDDDDDDDDDDDDDDDDDDD?", 13 | ";4242004800500=0123456789?", 14 | }; 15 | 16 | void setup() 17 | { 18 | magSpoof.setup(); 19 | Serial.begin(9600); 20 | } 21 | 22 | 23 | void loop() 24 | { 25 | // Transmit track every 2 seconds 26 | delay(2000); 27 | magSpoof.playTrack(testTracks[0]); 28 | } 29 | -------------------------------------------------------------------------------- /pictures/20190921_151556.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-thoni/arduino-magspoof/993f6fb8a3cefeccf6c4458c78abdabf4a2d7ab8/pictures/20190921_151556.jpg -------------------------------------------------------------------------------- /pictures/20190921_151603.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robin-thoni/arduino-magspoof/993f6fb8a3cefeccf6c4458c78abdabf4a2d7ab8/pictures/20190921_151603.jpg --------------------------------------------------------------------------------