arduino_ci 0.3.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +125 -69
  3. data/REFERENCE.md +711 -0
  4. data/cpp/arduino/Arduino.h +1 -7
  5. data/cpp/arduino/ArduinoDefines.h +3 -0
  6. data/cpp/arduino/AvrMath.h +117 -17
  7. data/cpp/arduino/Client.h +27 -0
  8. data/cpp/arduino/EEPROM.h +64 -0
  9. data/cpp/arduino/Godmode.cpp +7 -0
  10. data/cpp/arduino/Godmode.h +121 -15
  11. data/cpp/arduino/HardwareSerial.h +4 -4
  12. data/cpp/arduino/IPAddress.h +59 -0
  13. data/cpp/arduino/Print.h +9 -12
  14. data/cpp/arduino/Printable.h +8 -0
  15. data/cpp/arduino/SPI.h +11 -3
  16. data/cpp/arduino/Server.h +5 -0
  17. data/cpp/arduino/Udp.h +27 -0
  18. data/cpp/arduino/Wire.h +197 -77
  19. data/cpp/arduino/avr/io.h +10 -1
  20. data/cpp/arduino/avr/pgmspace.h +76 -46
  21. data/cpp/unittest/ArduinoUnitTests.h +32 -0
  22. data/cpp/unittest/Assertion.h +54 -26
  23. data/cpp/unittest/Compare.h +58 -51
  24. data/cpp/unittest/OstreamHelpers.h +4 -0
  25. data/exe/arduino_ci.rb +538 -0
  26. data/exe/arduino_ci_remote.rb +2 -393
  27. data/exe/arduino_library_location.rb +2 -2
  28. data/exe/ensure_arduino_installation.rb +7 -1
  29. data/lib/arduino_ci.rb +1 -0
  30. data/lib/arduino_ci/arduino_backend.rb +238 -0
  31. data/lib/arduino_ci/arduino_downloader.rb +43 -73
  32. data/lib/arduino_ci/arduino_downloader_linux.rb +17 -55
  33. data/lib/arduino_ci/arduino_downloader_osx.rb +21 -33
  34. data/lib/arduino_ci/arduino_downloader_windows.rb +11 -53
  35. data/lib/arduino_ci/arduino_installation.rb +18 -80
  36. data/lib/arduino_ci/ci_config.rb +8 -11
  37. data/lib/arduino_ci/cpp_library.rb +250 -59
  38. data/lib/arduino_ci/host.rb +59 -4
  39. data/lib/arduino_ci/library_properties.rb +101 -0
  40. data/lib/arduino_ci/version.rb +1 -1
  41. data/misc/default.yml +57 -6
  42. metadata +19 -87
  43. data/cpp/arduino/Arduino.h.orig +0 -143
  44. data/exe/libasan.rb +0 -29
  45. data/lib/arduino_ci/arduino_cmd.rb +0 -332
  46. data/lib/arduino_ci/arduino_cmd_linux.rb +0 -17
  47. data/lib/arduino_ci/arduino_cmd_linux_builder.rb +0 -19
  48. data/lib/arduino_ci/arduino_cmd_osx.rb +0 -17
  49. data/lib/arduino_ci/arduino_cmd_windows.rb +0 -17
@@ -1,143 +0,0 @@
1
- #pragma once
2
- /*
3
- Mock Arduino.h library.
4
-
5
- Where possible, variable names from the Arduino library are used to avoid conflicts
6
-
7
- */
8
- // Chars and strings
9
-
10
- #include "ArduinoDefines.h"
11
-
12
- #include "WCharacter.h"
13
- #include "WString.h"
14
- #include "Print.h"
15
- #include "Stream.h"
16
- #include "HardwareSerial.h"
17
- #include "SPI.h"
18
- #include "Nullptr.h"
19
-
20
- typedef bool boolean;
21
- typedef uint8_t byte;
22
-
23
- #include "binary.h"
24
-
25
- // Math and Trig
26
- #include "AvrMath.h"
27
-
28
- #include "Godmode.h"
29
-
30
-
31
- // Bits and Bytes
32
- #define bit(b) (1UL << (b))
33
- #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
34
- #define bitRead(value, bit) (((value) >> (bit)) & 0x01)
35
- #define bitSet(value, bit) ((value) |= (1UL << (bit)))
36
- #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
37
- #define highByte(w) ((uint8_t) ((w) >> 8))
38
- #define lowByte(w) ((uint8_t) ((w) & 0xff))
39
-
40
- // Arduino defines this
41
- #define _NOP() do { 0; } while (0)
42
-
43
- // might as well use that NO-op macro for these, while unit testing
44
- // you need interrupts? interrupt yourself
45
- #define yield() _NOP()
46
- #define interrupts() _NOP()
47
- #define noInterrupts() _NOP()
48
-
49
- // TODO: correctly establish this per-board!
50
- #define F_CPU 1000000UL
51
- #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
52
- #define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
53
- #define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
54
-
55
- typedef unsigned int word;
56
-
57
- #define bit(b) (1UL << (b))
58
-
59
-
60
-
61
- /*
62
- unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout);
63
- unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout);
64
-
65
- void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val);
66
- uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder);
67
-
68
- */
69
-
70
- // Get the bit location within the hardware port of the given virtual pin.
71
- // This comes from the pins_*.c file for the active board configuration.
72
-
73
- #define analogInPinToBit(P) (P)
74
- #define digitalPinToInterrupt(P) (P)
75
-
76
- /*
77
- // On the ATmega1280, the addresses of some of the port registers are
78
- // greater than 255, so we can't store them in uint8_t's.
79
- extern const uint16_t PROGMEM port_to_mode_PGM[];
80
- extern const uint16_t PROGMEM port_to_input_PGM[];
81
- extern const uint16_t PROGMEM port_to_output_PGM[];
82
-
83
- extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
84
- // extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
85
- extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
86
- extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
87
-
88
- // Get the bit location within the hardware port of the given virtual pin.
89
- // This comes from the pins_*.c file for the active board configuration.
90
- //
91
- // These perform slightly better as macros compared to inline functions
92
- //
93
- #define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
94
- #define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
95
- #define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
96
- #define analogInPinToBit(P) (P)
97
- #define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
98
- #define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
99
- #define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
100
-
101
- */
102
-
103
-
104
- /* TODO
105
-
106
- // USB
107
- #include "USBAPI.h"
108
- Keyboard
109
- Mouse
110
-
111
- */
112
-
113
- // uint16_t makeWord(uint16_t w);
114
- // uint16_t makeWord(byte h, byte l);
115
- inline unsigned int makeWord(unsigned int w) { return w; }
116
- inline unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
117
-
118
- #define word(...) makeWord(__VA_ARGS__)
119
-
120
- <<<<<<< Updated upstream
121
-
122
- =======
123
- unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
124
- unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
125
-
126
- // audio is taken care of in GODMODE
127
-
128
-
129
- // BIG TODO ON THIS ONE
130
- // $ find . | grep pins_
131
- // ./arduino-1.8.5/hardware/arduino/avr/variants/circuitplay32u4/pins_arduino.h
132
- // ./arduino-1.8.5/hardware/arduino/avr/variants/eightanaloginputs/pins_arduino.h
133
- // ./arduino-1.8.5/hardware/arduino/avr/variants/ethernet/pins_arduino.h
134
- // ./arduino-1.8.5/hardware/arduino/avr/variants/gemma/pins_arduino.h
135
- // ./arduino-1.8.5/hardware/arduino/avr/variants/leonardo/pins_arduino.h
136
- // ./arduino-1.8.5/hardware/arduino/avr/variants/mega/pins_arduino.h
137
- // ./arduino-1.8.5/hardware/arduino/avr/variants/micro/pins_arduino.h
138
- // ./arduino-1.8.5/hardware/arduino/avr/variants/robot_control/pins_arduino.h
139
- // ./arduino-1.8.5/hardware/arduino/avr/variants/robot_motor/pins_arduino.h
140
- // ./arduino-1.8.5/hardware/arduino/avr/variants/standard/pins_arduino.h
141
- // ./arduino-1.8.5/hardware/arduino/avr/variants/yun/pins_arduino.h
142
- // #include "pins_arduino.h"
143
- >>>>>>> Stashed changes
@@ -1,29 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'arduino_ci'
3
- require 'set'
4
- require 'pathname'
5
-
6
- WIDTH = 80
7
-
8
- # initialize command and config
9
- config = ArduinoCI::CIConfig.default.from_project_library
10
- @arduino_cmd = ArduinoCI::ArduinoInstallation.autolocate!
11
-
12
- # initialize library under test
13
- installed_library_path = @arduino_cmd.install_local_library(Pathname.new("."))
14
- cpp_library = ArduinoCI::CppLibrary.new(installed_library_path, @arduino_cmd.lib_dir)
15
-
16
- # check GCC
17
- compilers = config.compilers_to_use
18
- compilers.each do |gcc_binary|
19
- puts "Checking #{gcc_binary} version"
20
- puts cpp_library.gcc_version(gcc_binary).split("\n").map { |l| " #{l}" }.join("\n")
21
- exists = cpp_library.libasan?(gcc_binary)
22
- puts "libasan availability for #{gcc_binary}: #{exists}"
23
- next unless exists
24
-
25
- puts "========== Stdout:"
26
- puts @arduino_cmd.last_out
27
- puts "========== Stderr:"
28
- puts @arduino_cmd.last_err
29
- end
@@ -1,332 +0,0 @@
1
- require 'fileutils'
2
- require 'pathname'
3
-
4
- # workaround for https://github.com/arduino/Arduino/issues/3535
5
- WORKAROUND_LIB = "USBHost".freeze
6
-
7
- module ArduinoCI
8
-
9
- # To report errors that we can't resolve or possibly even explain
10
- class ArduinoExecutionError < StandardError; end
11
-
12
- # Wrap the Arduino executable. This requires, in some cases, a faked display.
13
- class ArduinoCmd
14
-
15
- # Enable a shortcut syntax for command line flags
16
- # @param name [String] What the flag will be called (prefixed with 'flag_')
17
- # @return [void]
18
- # @macro [attach] flag
19
- # The text of the command line flag for $1
20
- # @!attribute [r] flag_$1
21
- # @return [String] the text of the command line flag (`$2` in this case)
22
- def self.flag(name, text = nil)
23
- text = "(flag #{name} not defined)" if text.nil?
24
- self.class_eval("def flag_#{name};\"#{text}\";end", __FILE__, __LINE__)
25
- end
26
-
27
- # the array of command components to launch the Arduino executable
28
- # @return [Array<String>]
29
- attr_accessor :base_cmd
30
-
31
- # the actual path to the executable on this platform
32
- # @return [Pathname]
33
- attr_accessor :binary_path
34
-
35
- # part of a workaround for https://github.com/arduino/Arduino/issues/3535
36
- attr_reader :libraries_indexed
37
-
38
- # @return [String] STDOUT of the most recently-run command
39
- attr_reader :last_out
40
-
41
- # @return [String] STDERR of the most recently-run command
42
- attr_reader :last_err
43
-
44
- # @return [String] the most recently-run command
45
- attr_reader :last_msg
46
-
47
- # set the command line flags (undefined for now).
48
- # These vary between gui/cli. Inline comments added for greppability
49
- flag :get_pref # flag_get_pref
50
- flag :set_pref # flag_set_pref
51
- flag :save_prefs # flag_save_prefs
52
- flag :use_board # flag_use_board
53
- flag :install_boards # flag_install_boards
54
- flag :install_library # flag_install_library
55
- flag :verify # flag_verify
56
-
57
- def initialize
58
- @prefs_cache = {}
59
- @prefs_fetched = false
60
- @libraries_indexed = false
61
- @last_out = ""
62
- @last_err = ""
63
- @last_msg = ""
64
- end
65
-
66
- # Convert a preferences dump into a flat hash
67
- # @param arduino_output [String] The raw Arduino executable output
68
- # @return [Hash] preferences as a hash
69
- def parse_pref_string(arduino_output)
70
- lines = arduino_output.split("\n").select { |l| l.include? "=" }
71
- ret = lines.each_with_object({}) do |e, acc|
72
- parts = e.split("=", 2)
73
- acc[parts[0]] = parts[1]
74
- acc
75
- end
76
- ret
77
- end
78
-
79
- # @return [String] the path to the Arduino libraries directory
80
- def lib_dir
81
- Pathname.new(get_pref("sketchbook.path")) + "libraries"
82
- end
83
-
84
- # fetch preferences in their raw form
85
- # @return [String] Preferences as a set of lines
86
- def _prefs_raw
87
- resp = run_and_capture(flag_get_pref)
88
- fail_msg = "Arduino binary failed to operate as expected; you will have to troubleshoot it manually"
89
- raise ArduinoExecutionError, "#{fail_msg}. The command was #{@last_msg}" unless resp[:success]
90
-
91
- @prefs_fetched = true
92
- resp[:out]
93
- end
94
-
95
- # Get the Arduino preferences, from cache if possible
96
- # @return [Hash] The full set of preferences
97
- def prefs
98
- prefs_raw = _prefs_raw unless @prefs_fetched
99
- return nil if prefs_raw.nil?
100
-
101
- @prefs_cache = parse_pref_string(prefs_raw)
102
- @prefs_cache.clone
103
- end
104
-
105
- # get a preference key
106
- # @param key [String] The preferences key to look up
107
- # @return [String] The preference value
108
- def get_pref(key)
109
- data = @prefs_fetched ? @prefs_cache : prefs
110
- data[key]
111
- end
112
-
113
- # underlying preference-setter.
114
- # @param key [String] The preference name
115
- # @param value [String] The value to set to
116
- # @return [bool] whether the command succeeded
117
- def _set_pref(key, value)
118
- run_and_capture(flag_set_pref, "#{key}=#{value}", flag_save_prefs)[:success]
119
- end
120
-
121
- # set a preference key/value pair, and update the cache.
122
- # @param key [String] the preference key
123
- # @param value [String] the preference value
124
- # @return [bool] whether the command succeeded
125
- def set_pref(key, value)
126
- prefs unless @prefs_fetched # update cache first
127
- success = _set_pref(key, value)
128
- @prefs_cache[key] = value if success
129
- success
130
- end
131
-
132
- def _wrap_run(work_fn, *args, **kwargs)
133
- # do some work to extract & merge environment variables if they exist
134
- has_env = !args.empty? && args[0].class == Hash
135
- env_vars = has_env ? args[0] : {}
136
- actual_args = has_env ? args[1..-1] : args # need to shift over if we extracted args
137
- full_args = @base_cmd + actual_args
138
- full_cmd = env_vars.empty? ? full_args : [env_vars] + full_args
139
-
140
- shell_vars = env_vars.map { |k, v| "#{k}=#{v}" }.join(" ")
141
- @last_msg = " $ #{shell_vars} #{full_args.join(' ')}"
142
- work_fn.call(*full_cmd, **kwargs)
143
- end
144
-
145
- # build and run the arduino command
146
- def run_and_output(*args, **kwargs)
147
- _wrap_run((proc { |*a, **k| Host.run_and_output(*a, **k) }), *args, **kwargs)
148
- end
149
-
150
- # run a command and capture its output
151
- # @return [Hash] {:out => String, :err => String, :success => bool}
152
- def run_and_capture(*args, **kwargs)
153
- ret = _wrap_run((proc { |*a, **k| Host.run_and_capture(*a, **k) }), *args, **kwargs)
154
- @last_err = ret[:err]
155
- @last_out = ret[:out]
156
- ret
157
- end
158
-
159
- # Board manager URLs
160
- # @return [Array<String>] The additional URLs used by the board manager
161
- def board_manager_urls
162
- url_list = get_pref("boardsmanager.additional.urls")
163
- return [] if url_list.nil?
164
-
165
- url_list.split(",")
166
- end
167
-
168
- # Set board manager URLs
169
- # @return [Array<String>] The additional URLs used by the board manager
170
- def board_manager_urls=(all_urls)
171
- set_pref("boardsmanager.additional.urls", all_urls.join(","))
172
- end
173
-
174
- # check whether a board is installed
175
- # we do this by just selecting a board.
176
- # the arduino binary will error if unrecognized and do a successful no-op if it's installed
177
- # @param boardname [String] The board to test
178
- # @return [bool] Whether the board is installed
179
- def board_installed?(boardname)
180
- run_and_capture(flag_use_board, boardname)[:success]
181
- end
182
-
183
- # install a board by name
184
- # @param name [String] the board name
185
- # @return [bool] whether the command succeeded
186
- def install_boards(boardfamily)
187
- # TODO: find out why IO.pipe fails but File::NULL succeeds :(
188
- result = run_and_capture(flag_install_boards, boardfamily)
189
- already_installed = result[:err].include?("Platform is already installed!")
190
- result[:success] || already_installed
191
- end
192
-
193
- # install a library by name
194
- # @param name [String] the library name
195
- # @return [bool] whether the command succeeded
196
- def _install_library(library_name)
197
- result = run_and_capture(flag_install_library, library_name)
198
-
199
- already_installed = result[:err].include?("Library is already installed: #{library_name}")
200
- success = result[:success] || already_installed
201
-
202
- @libraries_indexed = (@libraries_indexed || success) if library_name == WORKAROUND_LIB
203
- success
204
- end
205
-
206
- # index the set of libraries by installing a dummy library
207
- # related to WORKAROUND_LIB and https://github.com/arduino/Arduino/issues/3535
208
- # TODO: unclear if this is still necessary
209
- def index_libraries
210
- return true if @libraries_indexed
211
-
212
- _install_library(WORKAROUND_LIB)
213
- @libraries_indexed
214
- end
215
-
216
- # install a library by name
217
- # @param name [String] the library name
218
- # @return [bool] whether the command succeeded
219
- def install_library(library_name)
220
- index_libraries
221
- _install_library(library_name)
222
- end
223
-
224
- # generate the (very likely) path of a library given its name
225
- # @param library_name [String] The name of the library
226
- # @return [Pathname] The fully qualified library name
227
- def library_path(library_name)
228
- Pathname.new(lib_dir) + library_name
229
- end
230
-
231
- # Determine whether a library is present in the lib dir
232
- #
233
- # Note that `true` doesn't guarantee that the library is valid/installed
234
- # and `false` doesn't guarantee that the library isn't built-in
235
- #
236
- # @param library_name [String] The name of the library
237
- # @return [bool]
238
- def library_present?(library_name)
239
- library_path(library_name).exist?
240
- end
241
-
242
- # update the library index
243
- # @return [bool] Whether the update succeeded
244
- def update_library_index
245
- # install random lib so the arduino IDE grabs a new library index
246
- # see: https://github.com/arduino/Arduino/issues/3535
247
- install_library(WORKAROUND_LIB)
248
- end
249
-
250
- # use a particular board for compilation
251
- # @param boardname [String] The board to use
252
- # @return [bool] whether the command succeeded
253
- def use_board(boardname)
254
- run_and_capture(flag_use_board, boardname, flag_save_prefs)[:success]
255
- end
256
-
257
- # use a particular board for compilation, installing it if necessary
258
- # @param boardname [String] The board to use
259
- # @return [bool] whether the command succeeded
260
- def use_board!(boardname)
261
- return true if use_board(boardname)
262
-
263
- boardfamily = boardname.split(":")[0..1].join(":")
264
- puts "Board '#{boardname}' not found; attempting to install '#{boardfamily}'"
265
- return false unless install_boards(boardfamily) # guess board family from first 2 :-separated fields
266
-
267
- use_board(boardname)
268
- end
269
-
270
- # @param path [String] The sketch to verify
271
- # @return [bool] whether the command succeeded
272
- def verify_sketch(path)
273
- ext = File.extname path
274
- unless ext.casecmp(".ino").zero?
275
- @last_msg = "Refusing to verify sketch with '#{ext}' extension -- rename it to '.ino'!"
276
- return false
277
- end
278
- unless File.exist? path
279
- @last_msg = "Can't verify Sketch at nonexistent path '#{path}'!"
280
- return false
281
- end
282
- ret = run_and_capture(flag_verify, path)
283
- ret[:success]
284
- end
285
-
286
- # ensure that the given library is installed, or symlinked as appropriate
287
- # return the path of the prepared library, or nil
288
- # @param path [Pathname] library to use
289
- # @return [String] the path of the installed library
290
- def install_local_library(path)
291
- src_path = path.realpath
292
- library_name = src_path.basename
293
- destination_path = library_path(library_name)
294
-
295
- # things get weird if the sketchbook contains the library.
296
- # check that first
297
- if destination_path.exist?
298
- uhoh = "There is already a library '#{library_name}' in the library directory"
299
- return destination_path if destination_path == src_path
300
-
301
- # maybe it's a symlink? that would be OK
302
- if destination_path.symlink?
303
- return destination_path if destination_path.readlink == src_path
304
-
305
- @last_msg = "#{uhoh} and it's not symlinked to #{src_path}"
306
- return nil
307
- end
308
-
309
- @last_msg = "#{uhoh}. It may need to be removed manually."
310
- return nil
311
- end
312
-
313
- # install the library
314
- Host.symlink(src_path, destination_path)
315
- destination_path
316
- end
317
-
318
- # @param installed_library_path [String] The library to query
319
- # @return [Array<String>] Example sketch files
320
- def library_examples(installed_library_path)
321
- example_path = Pathname.new(installed_library_path) + "examples"
322
- return [] unless File.exist?(example_path)
323
-
324
- examples = example_path.children.select(&:directory?).map(&:to_path).map(&File.method(:basename))
325
- files = examples.map do |e|
326
- proj_file = example_path + e + "#{e}.ino"
327
- proj_file.exist? ? proj_file.to_s : nil
328
- end
329
- files.reject(&:nil?).sort_by(&:to_s)
330
- end
331
- end
332
- end