arduino_ci 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6dab88af65d6e71fd9cd3e2f389340b184fb1fbb063ccb7a6743f893c47f690d
4
- data.tar.gz: 267b58186eea10a1f52ff4c16838270437a7d52d8fd0a3681f84e770845efa0d
3
+ metadata.gz: 95cc7dc7ab0591e45ffe7c1a9cdf31f64b21a8cf794a12ea83a4190af20e7488
4
+ data.tar.gz: 6e20b49ad3b015445c79511e9795fddbf205f01e20eb8c413e7ff342f4b240f9
5
5
  SHA512:
6
- metadata.gz: 8765d7d3c01fb5a4f9737604ee9ee33a020629e3e5d404403069ac346caad36f69a94893ca2db49cdc14bb50a1d5557d29cccd9b58022fb3d1a00cd9de348323
7
- data.tar.gz: e537d36bd505b31630aae9e7359a71f82dbb07977bac93dbc4194d6da4112ca005e22b2e9051970d0d67afd4e5dcdabcd9a6dddda1ee399c0a7cfc01aecb631c
6
+ metadata.gz: f40e840a35f788a4e02e0e332b5e7669198214419d9361abf10cc03558028bc691bb16379143b95c258dd2527fb8b03924d3cfb240c3af6b2fac526966b30274
7
+ data.tar.gz: bf8dc24b59f479ad858b75450a546ebd5e7bee694e33c8b443d2fa89576fe40fb09dede3c17353b7ca6c9c7dcda921aa7bb3f156c3beb98fd62cc99123c03119
data/README.md CHANGED
@@ -1,17 +1,24 @@
1
1
 
2
2
  # ArduinoCI Ruby gem (`arduino_ci`)
3
3
  [![Gem Version](https://badge.fury.io/rb/arduino_ci.svg)](https://rubygems.org/gems/arduino_ci)
4
- [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/1.1.0)
4
+ [![Documentation](http://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/arduino_ci/1.2.0)
5
5
  [![Gitter](https://badges.gitter.im/Arduino-CI/arduino_ci.svg)](https://gitter.im/Arduino-CI/arduino_ci?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
6
+ [![GitHub Marketplace](https://img.shields.io/badge/Get_it-on_Marketplace-informational.svg)](https://github.com/marketplace/actions/arduino_ci)
6
7
 
7
- You want to run tests on your Arduino library (bonus: without hardware present), but the IDE doesn't support that. Arduino CI provides that ability.
8
+ Arduino CI was created to enable better collaboration among Arduino library maintainers and contributors, by enabling automated code checks to be performed as part of a pull request process.
8
9
 
9
- You want to precisely replicate certain software states in your library, but you don't have sub-millisecond reflexes for physically faking the inputs, outputs, and serial port. Arduino CI fakes 100% of the physical input and output of an Arduino board, including the clock.
10
+ * enables running unit tests against the library **without hardware present**
11
+ * provides a system of mocks that allow fine-grained control over the hardare inputs, including the system's clock
12
+ * verifies compilation of any example sketches included in the library
13
+ * can test a wide range of arduino boards with different hardware options available
14
+ * compares entries in `library.properties` to the contents of the library and reports mismatches
15
+ * can be run both locally and as part of CI (GitHub Actions, TravisCI, Appveyor, etc.)
16
+ * runs on multiple platforms -- any platform that supports the Arduino IDE
17
+ * provides detailed analysis of segfaults in compilers that support such debugging features
10
18
 
11
- You want your Arduino library to be automatically built and tested every time someone contributes code to your project on GitHub, but the Arduino IDE lacks the ability to run unit tests. [Arduino CI](https://github.com/Arduino-CI/arduino_ci) provides that ability.
12
-
13
- `arduino_ci` is a cross-platform build/test system, consisting of a Ruby gem and a series of C++ mocks. It enables tests to be run both locally and as part of a CI service like GitHub Actions, TravisCI, Appveyor, etc. Any OS that can run the Arduino IDE can run `arduino_ci`.
19
+ > Note: for running tests in response to [GitHub events](https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events/github-event-types), an [Arduino CI GitHub Action](https://github.com/marketplace/actions/arduino_ci) is available for your convenience. This method of running `arduino_ci` is driven by Docker, which may also serve your local testing needs (as it does not require a ruby environment to be installed).
14
20
 
21
+ Arduino CI works on multiple platforms, which should enable your CI system of choice to leverage it for testing.
15
22
 
16
23
  Platform | CI Status
17
24
  ---------|:---------
@@ -20,30 +27,22 @@ Linux | [![Linux Build Status](https://github.com/Arduino-CI/arduino_ci/workf
20
27
  Windows | [![Windows Build status](https://github.com/Arduino-CI/arduino_ci/workflows/windows/badge.svg)](https://github.com/Arduino-CI/arduino_ci/actions?workflow=windows)
21
28
 
22
29
 
23
- ## Comparison to Other Arduino Testing Tools
30
+ ## Quick Start
24
31
 
25
- | Project | CI | Builds Examples | Unittest | Arduino Mocks | Windows | OSX | Linux | License |
26
- |-----------------------------------------------------------------------------|:--:|:---------------:|:--------:|:-------------:|:-------:|:---:|:-----:|:--------|
27
- |[ArduinoCI](https://github.com/Arduino-CI/arduino_ci) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |Free (Apache-2.0)|
28
- |[ArduinoUnit](https://github.com/mmurdoch/arduinounit) | ❌ | ❌ | ⚠️ Hardware-based|❌ | ✅ | ✅ | ✅ |Free (MIT)|
29
- |[Adafruit `ci-arduino`](https://github.com/adafruit/ci-arduino)| ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ✅ |Free (MIT)|
30
- |[PlatformIO](https://platformio.org) | ✅ | ✅ | ⚠️ Paid only | ❌ | ✅ | ✅ | ✅ |⚠️ EULA|
31
- |Official [Arduino IDE](https://www.arduino.cc/en/main/software) | ❌ | ⚠️ Manually | ❌ |N/A 😉| ✅ | ✅ | ✅ |Free (GPLv2)|
32
+ ### You Need Your Arduino Library
32
33
 
34
+ For a fairly minimal practical example of a unit-testable library repo that you can copy from, see [the `Arduino-CI/Blink` repository](https://github.com/Arduino-CI/Blink).
33
35
 
34
- ## Quick Start
36
+ > Note: The `SampleProjects` directory you see within _this_ repo contains tests for validing the `arduino_ci` framework itself, and due to that coupling will not be helpful to duplicate. That said, the [SampleProjects/TestSomething](SampleProjects/TestSomething) project contains [test files](SampleProjects/TestSomething/test/) (each named after the type of feature being tested) that may be illustrative of testing strategy and capabilities _on an individual basis_.
35
37
 
36
- For a bare-bones example that you can copy from, see [SampleProjects/DoSomething](SampleProjects/DoSomething).
38
+ Arduino expects all libraries to be in a specific `Arduino/libraries` directory on your system. If your library is elsewhere, `arduino_ci` will _automatically_ create a symbolic link in the `libraries` directory that points to the directory of the project being tested. This simplifieds working with project dependencies, but **it can have unintended consequences on Windows systems**.
37
39
 
38
- The complete set of C++ unit tests for the `arduino_ci` library itself are in the [SampleProjects/TestSomething](SampleProjects/TestSomething) project. The [test files](SampleProjects/TestSomething/test/) are named after the type of feature being tested.
40
+ > If you use a Windows system **it is recommended that you only run `arduino_ci` from project directories that are already inside the `libraries` directory** because [in some cases deleting a folder that contains a symbolic link to another folder can cause the _entire linked folder_ to be removed instead of just the link itself](https://superuser.com/a/306618).
39
41
 
40
- > Arduino expects all libraries to be in a specific `Arduino/libraries` directory on your system. If your library is elsewhere, `arduino_ci` will _automatically_ create a symbolic link in the `libraries` directory that points to the directory of the project being tested. This simplifieds working with project dependencies, but **it can have unintended consequences on Windows systems** because [in some cases deleting a folder that contains a symbolic link to another folder can cause the _entire linked folder_ to be removed instead of just the link itself](https://superuser.com/a/306618).
41
- >
42
- > If you use a Windows system **it is recommended that you only run `arduino_ci` from project directories that are already inside the `libraries` directory**
43
42
 
44
43
  ### You Need Ruby and Bundler
45
44
 
46
- You'll need Ruby version 2.2 or higher, and to `gem install bundler` if it's not already there.
45
+ You'll need Ruby version 2.5 or higher, and to `gem install bundler` if it's not already there.
47
46
 
48
47
 
49
48
  ### You Need A Compiler (`g++`)
@@ -52,7 +51,14 @@ For unit testing, you will need a compiler; [g++](https://gcc.gnu.org/) is prefe
52
51
 
53
52
  * **Linux**: `gcc`/`g++` is likely pre-installed.
54
53
  * **OSX**: `g++` is an alias for `clang`, which is provided by Xcode and the developer tools. You are free to `brew install gcc` as well; this is also tested and working.
55
- * **Windows**: you will need Cygwin, and the `mingw-gcc-g++` package. A full set of (working) install instructions can be found in `appveyor.yml`, as this is how CI runs for this project.
54
+ * **Windows**: you will need Cygwin, and the `mingw-gcc-g++` package.
55
+
56
+
57
+ ### You _May_ Need `python`
58
+
59
+ ESP32 and ESP8266 boards have [a dependency on `python` that they don't install themselves](https://github.com/Arduino-CI/arduino_ci/issues/235#issuecomment-739629243). If you intend to test on these platforms (which are included in the default list of platforms to test against), you will need to make `python` (and possibly `pyserial`) available in the test environment.
60
+
61
+ Alternately, you might configure `arduino_ci` to simply not test against these. Consult the reference for those details.
56
62
 
57
63
 
58
64
  ### Changes to Your Repo
@@ -61,9 +67,11 @@ Add a file called `Gemfile` (no extension) to your Arduino project:
61
67
 
62
68
  ```ruby
63
69
  source 'https://rubygems.org'
64
- gem 'arduino_ci'
70
+ gem 'arduino_ci' '~> 1.1'
65
71
  ```
66
72
 
73
+ At the time of this writing, `1.1` is the latest version available, and the `~>` syntax will allow your system to update it to the latest `1.x.x` version. The list of all available versions can be found on [rubygems.org](https://rubygems.org/gems/arduino_ci) if you prefer to explicitly pin a higher version.
74
+
67
75
  It would also make sense to add the following to your `.gitignore`, or copy [the `.gitignore` used by this project](.gitignore):
68
76
 
69
77
  ```
@@ -184,7 +192,7 @@ test_script:
184
192
 
185
193
  ## Known Problems
186
194
 
187
- * The Arduino library is not fully mocked.
195
+ * The Arduino library is not fully mocked, nor is `avr-libc`.
188
196
  * I don't have preprocessor defines for all the Arduino board flavors
189
197
  * https://github.com/Arduino-CI/arduino_ci/issues
190
198
 
@@ -29,6 +29,11 @@ This completely skips the compilation tests (of library examples) portion of the
29
29
  This completely skips the compilation tests (of library examples) portion of the CI script. It does not skip the compilation of unit tests.
30
30
 
31
31
 
32
+ ### `--skip-library-properties` option
33
+
34
+ This completely skips validation of entries in `library.properties`.
35
+
36
+
32
37
  ### `--testfile-select` option
33
38
 
34
39
  This allows a file (or glob) pattern to be executed in your tests directory, creating a whitelist of files to test. E.g. `--testfile-select=test_animal_*.cpp` would match `test_animal_cat.cpp` and `test_animal_dog.cpp` (testing only those) and not `test_plant_rose.cpp`.
@@ -39,6 +44,16 @@ This allows a file (or glob) pattern to be executed in your tests directory, cre
39
44
  This allows a file (or glob) pattern to be executed in your tests directory, creating a blacklist of files to skip. E.g. `--testfile-reject=test_animal_*.cpp` would match `test_animal_cat.cpp` and `test_animal_dog.cpp` (skipping those) and test only `test_plant_rose.cpp`, `test_plant_daisy.cpp`, etc.
40
45
 
41
46
 
47
+ ### `CUSTOM_INIT_SCRIPT` environment variable
48
+
49
+ If set, testing will execute (using `/bin/sh`) the script referred to by this variable -- relative to the current working directory. This enables use cases like the GitHub action to install custom library versions (i.e. a version of a library that is different than what the library manager would automatically install by name) prior to CI test runs.
50
+
51
+
52
+ ### `USE_SUBDIR` environment variable
53
+
54
+ If set, testing will be conducted in this subdirectory (relative to the working directory). This is for monorepos or other layouts where the library directory and project root directory are different.
55
+
56
+
42
57
  ### `EXPECT_UNITTESTS` environment variable
43
58
 
44
59
  If set, testing will fail if no unit test files are detected (or if the directory does not exist). This is to avoid communicating a passing status in cases where a commit may have accidentally moved or deleted the test files.
@@ -49,6 +64,11 @@ If set, testing will fail if no unit test files are detected (or if the director
49
64
  If set, testing will fail if no example sketches are detected. This is to avoid communicating a passing status in cases where a commit may have accidentally moved or deleted the examples.
50
65
 
51
66
 
67
+ ### `SKIP_LIBRARY_PROPERTIES` environment variable
68
+
69
+ If set, testing will skip validating `library.properties` entries. This is to work around any possible bugs in `arduino_ci`'s interpretation of what is "correct".
70
+
71
+
52
72
  ## Indirectly Overriding Build Behavior (medium term use), and Advanced Options
53
73
 
54
74
  For build behavior that you'd like to persist across commits (e.g. defining the set of platforms to test against, disabling a test that you expect to re-enable at some future point), a special configuration file called `.arduino-ci.yml` can be used. There are 3 places you can put them:
@@ -74,6 +94,8 @@ packages:
74
94
 
75
95
  To define a platform called `bogo` that uses a board called `potato:salad:bogo` (based on the `potato:salad` family), set it up in the `plaforms:` section. Note that this will override any default configuration of `bogo` if it had existed in `arduino_ci`'s `misc/default.yml` file. If this board defines particular features in the compiler, you can set those here.
76
96
 
97
+ > Note that the platform names are arbitrary -- just keys in this yaml file and in the [`default.yml`](https://github.com/Arduino-CI/arduino_ci/blob/master/misc/default.yml) file included in this gem. That said, they are also case sensitive; defining the `bogo` platform will not let you refer to it as `Bogo` nor `BOGO`.
98
+
77
99
  ```yaml
78
100
  platforms:
79
101
  # our custom definition of the "bogo" platform
@@ -107,7 +129,9 @@ platforms:
107
129
  ### Control How Examples Are Compiled
108
130
 
109
131
  Put a file `.arduino-ci.yml` in each example directory where you require a different configuration than default.
110
- The `compile:` section controls the platforms on which the compilation will be attempted, as well as any external libraries that must be installed and included.
132
+ The `compile:` section controls the platforms on which the compilation will be attempted, as well as any external libraries that must be installed and included. This works by _overriding_ portions of the default configuration.
133
+
134
+ > Note that the platform names _must_ match (case-sensitive) the platform names in the underlying [`default.yml`](https://github.com/Arduino-CI/arduino_ci/blob/master/misc/default.yml), or else match platforms that you have defined yourself in your `.arduino-ci.yml` override.
111
135
 
112
136
  ```yaml
113
137
  compile:
@@ -198,15 +222,27 @@ This test defines one `unittest` (a macro provided by `ArduinoUnitTests.h`), cal
198
222
 
199
223
  The following assertion functions are available in unit tests.
200
224
 
201
- * `assertEqual(expected, actual)`
202
- * `assertNotEqual(expected, actual)`
203
- * `assertLess(expected, actual)`
204
- * `assertMore(expected, actual)`
205
- * `assertLessOrEqual(expected, actual)`
206
- * `assertMoreOrEqual(expected, actual)`
207
- * `assertTrue(actual)`
208
- * `assertFalse(actual)`
209
- * `assertNull(actual)`
225
+ ```c++
226
+ assertEqual(expected, actual); // a == b
227
+ assertNotEqual(unwanted, actual); // a != b
228
+ assertComparativeEquivalent(expected, actual); // abs(a - b) == 0 or (!(a > b) && !(a < b))
229
+ assertComparativeNotEquivalent(unwanted, actual); // abs(a - b) > 0 or ((a > b) || (a < b))
230
+ assertLess(upperBound, actual); // a < b
231
+ assertMore(lowerBound, actual); // a > b
232
+ assertLessOrEqual(upperBound, actual); // a <= b
233
+ assertMoreOrEqual(lowerBound, actual); // a >= b
234
+ assertTrue(actual);
235
+ assertFalse(actual);
236
+ assertNull(actual);
237
+
238
+ // special cases for floats
239
+ assertEqualFloat(expected, actual, epsilon); // fabs(a - b) <= epsilon
240
+ assertNotEqualFloat(unwanted, actual, epsilon); // fabs(a - b) >= epsilon
241
+ assertInfinity(actual); // isinf(a)
242
+ assertNotInfinity(actual); // !isinf(a)
243
+ assertNAN(arg); // isnan(a)
244
+ assertNotNAN(arg); // !isnan(a)
245
+ ```
210
246
 
211
247
  These functions will report the result of the test to the console, and the testing will continue if they fail.
212
248
 
@@ -327,7 +363,7 @@ unittest(pin_history)
327
363
  // we expect 6 values in that queue (5 that we set plus one
328
364
  // initial value), which we'll hard-code here for convenience.
329
365
  // (we'll actually assert those 6 values in the next block)
330
- assertEqual(6, state->digitalPin[1].queueSize));
366
+ assertEqual(6, state->digitalPin[1].queueSize());
331
367
  bool expected[6] = {LOW, HIGH, LOW, LOW, HIGH, HIGH};
332
368
  bool actual[6];
333
369
 
@@ -634,3 +670,47 @@ unittest(eeprom)
634
670
  assertEqual(10, a);
635
671
  }
636
672
  ```
673
+
674
+
675
+ ### Wire
676
+
677
+ This library allows communication with I2C / TWI devices.
678
+
679
+ The interface the library has been fully mocked, with the addition of several functions for debugging
680
+
681
+ * `Wire.resetMocks()`: Initializes all mocks, and for test repeatability should be called at the top of any unit tests that use Wire.
682
+ * `Wire.didBegin()`: returns whether `Wire.begin()` was called at any point
683
+ * `Wire.getMosi(address)`: returns a pointer to a `deque` that represents the history of data sent to `address`
684
+ * `Wire.getMiso(address)`: returns a pointer to a `deque` that defines what the master will read from `address` (i.e. for you to supply)
685
+
686
+ ```c++
687
+ unittest(wire_basics) {
688
+ // ensure known starting state
689
+ Wire.resetMocks();
690
+
691
+ // in case you need to check that your library is properly calling .begin()
692
+ assertFalse(Wire.didBegin());
693
+ Wire.begin();
694
+ assertTrue(Wire.didBegin());
695
+
696
+ // pick a random device. master write buffer should be empty
697
+ const uint8_t randomSlaveAddr = 14;
698
+ deque<uint8_t>* mosi = Wire.getMosi(randomSlaveAddr);
699
+ assertEqual(0, mosi->size());
700
+
701
+ // write some random data to random device
702
+ const uint8_t randomData[] = { 0x07, 0x0E };
703
+ Wire.beginTransmission(randomSlaveAddr);
704
+ Wire.write(randomData[0]);
705
+ Wire.write(randomData[1]);
706
+ Wire.endTransmission();
707
+
708
+ // check master write buffer values
709
+ assertEqual(2, mosi->size());
710
+ assertEqual(randomData[0], mosi->front());
711
+ mosi->pop_front();
712
+ assertEqual(randomData[1], mosi->front());
713
+ mosi->pop_front();
714
+ assertEqual(0, mosi->size());
715
+ }
716
+ ```
@@ -36,9 +36,6 @@ typedef uint8_t byte;
36
36
  #define highByte(w) ((uint8_t) ((w) >> 8))
37
37
  #define lowByte(w) ((uint8_t) ((w) & 0xff))
38
38
 
39
- // Arduino defines this
40
- #define _NOP() do { 0; } while (0)
41
-
42
39
  // might as well use that NO-op macro for these, while unit testing
43
40
  // you need interrupts? interrupt yourself
44
41
  #define yield() _NOP()
@@ -70,5 +67,3 @@ inline unsigned int makeWord(unsigned int w) { return w; }
70
67
  inline unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; }
71
68
 
72
69
  #define word(...) makeWord(__VA_ARGS__)
73
-
74
-
@@ -92,3 +92,6 @@
92
92
  #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
93
93
  #define LED_BUILTIN 13
94
94
  #endif
95
+
96
+ // Arduino defines this
97
+ #define _NOP() do { 0; } while (0)
@@ -160,21 +160,78 @@ class GodmodeState {
160
160
  };
161
161
 
162
162
  // io pins
163
- #define pinMode(...) _NOP()
164
- #define analogReference(...) _NOP()
163
+ inline void pinMode(uint8_t pin, uint8_t mode) { _NOP(); }
164
+ inline void analogReference(uint8_t mode) { _NOP(); }
165
165
 
166
166
  void digitalWrite(uint8_t, uint8_t);
167
167
  int digitalRead(uint8_t);
168
168
  int analogRead(uint8_t);
169
169
  void analogWrite(uint8_t, int);
170
- #define analogReadResolution(...) _NOP()
171
- #define analogWriteResolution(...) _NOP()
170
+ inline void analogReadResolution(uint8_t bits) { _NOP(); }
171
+ inline void analogWriteResolution(uint8_t bits) { _NOP(); }
172
172
  void attachInterrupt(uint8_t interrupt, void ISR(void), uint8_t mode);
173
173
  void detachInterrupt(uint8_t interrupt);
174
174
 
175
175
  // TODO: issue #26 to track the commanded state here
176
- inline void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0) {}
177
- inline void noTone(uint8_t _pin) {}
176
+ inline void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0) { throw "Not Yet Implemented"; }
177
+ inline void noTone(uint8_t _pin) { throw "Not Yet Implemented"; }
178
+ inline uint8_t pulseIn(uint8_t _pin, uint8_t _value, uint32_t _timeout) { throw "Not Yet Implemented"; }
179
+ inline uint8_t pulseIn(uint8_t pin, uint8_t value) { return pulseIn(pin, value, (uint32_t) 1000000); }
180
+ inline uint32_t pulseInLong(uint8_t _pin, uint8_t _value, uint32_t _timeout) { throw "Not Yet Implemented"; }
181
+ inline uint32_t pulseInLong(uint8_t pin, uint8_t value) { return pulseInLong(pin, value, (uint32_t) 1000000); }
182
+
183
+ /**
184
+ * Shifts in a byte of data one bit at a time.
185
+ *
186
+ * Starts from either the most (i.e. the leftmost) or least (rightmost)
187
+ * significant bit. For each bit, the clock pin is pulled high, the next bit is
188
+ * read from the data line, and then the clock pin is taken low.
189
+ *
190
+ * @param dataPin the pin on which to input each bit
191
+ * @param clockPin the pin to toggle to signal a read from dataPin
192
+ * @param bitOrder which order to shift in the bits; either MSBFIRST or LSBFIRST. B=Bit, not byte
193
+ *
194
+ * @return The value read
195
+ */
196
+ inline uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, bool bitOrder) {
197
+ bool mFirst = bitOrder == MSBFIRST;
198
+ uint8_t ret = 0x00;
199
+ for (uint8_t i = 0, mask = (bitOrder == MSBFIRST ? 0x80 : 0x01); i < 8; ++i) {
200
+ digitalWrite(clockPin, HIGH);
201
+ uint8_t setBit = mFirst ? 0x80 : 0x01;
202
+ uint8_t val = (mFirst ? (setBit >> i) : (setBit << i));
203
+ ret = ret | (digitalRead(dataPin) ? val : 0x00);
204
+ digitalWrite(clockPin, LOW);
205
+ }
206
+ return ret;
207
+ }
208
+
209
+ /**
210
+ * Shifts out a byte of data one bit at a time.
211
+ *
212
+ * Starts from either the most (i.e. the leftmost) or least (rightmost)
213
+ * significant bit. Each bit is written in turn to a data pin, after which a
214
+ * clock pin is pulsed (taken high, then low) to indicate that the bit is
215
+ * available.
216
+ *
217
+ * @param dataPin the pin on which to input each bit
218
+ * @param clockPin the pin to toggle to signal a write from dataPin
219
+ * @param bitOrder which order to shift in the bits; either MSBFIRST or LSBFIRST. B=Bit, not byte
220
+ * @param value the data to shift out
221
+ *
222
+ * @return The value read
223
+ */
224
+ inline void shiftOut(uint8_t dataPin, uint8_t clockPin, bool bitOrder, uint8_t value) {
225
+ bool mFirst = bitOrder == MSBFIRST;
226
+ uint8_t ret = 0x00;
227
+ for (uint8_t i = 0, mask = (bitOrder == MSBFIRST ? 0x80 : 0x01); i < 8; ++i) {
228
+ uint8_t setBit = mFirst ? 0x80 : 0x01;
229
+ uint8_t val = (mFirst ? (setBit >> i) : (setBit << i));
230
+ digitalWrite(dataPin, (value & val) ? HIGH : LOW);
231
+ digitalWrite(clockPin, HIGH);
232
+ digitalWrite(clockPin, LOW);
233
+ }
234
+ }
178
235
 
179
236
  // These definitions allow the following to compile (see issue #193):
180
237
  // https://github.com/arduino-libraries/Ethernet/blob/master/src/utility/w5100.h:341
@@ -54,19 +54,52 @@ struct wireData_t {
54
54
  class TwoWire : public ObservableDataStream {
55
55
  private:
56
56
  bool _didBegin = false;
57
- wireData_t *in = nullptr; // pointer to current slave for writing
58
- wireData_t *out = nullptr; // pointer to current slave for reading
57
+ wireData_t* in = nullptr; // pointer to current slave for writing
58
+ wireData_t* out = nullptr; // pointer to current slave for reading
59
59
  wireData_t slaves[SLAVE_COUNT];
60
60
 
61
61
  public:
62
- // constructor initializes internal data
63
- TwoWire() {
62
+
63
+ //////////////////////////////////////////////////////////////////////////////////////////////
64
+ // testing methods
65
+ //////////////////////////////////////////////////////////////////////////////////////////////
66
+
67
+ // initialize all the mocks
68
+ void resetMocks() {
69
+ _didBegin = false;
70
+ in = nullptr; // pointer to current slave for writing
71
+ out = nullptr; // pointer to current slave for reading
64
72
  for (int i = 0; i < SLAVE_COUNT; ++i) {
65
73
  slaves[i].misoSize = 0;
66
74
  slaves[i].mosiSize = 0;
75
+ slaves[i].misoBuffer.clear();
76
+ slaves[i].mosiBuffer.clear();
67
77
  }
68
78
  }
69
79
 
80
+ // to verify that Wire.begin() was called at some point
81
+ bool didBegin() { return _didBegin; }
82
+
83
+ // to access the MISO buffer, which allows you to mock what the master will read in a request
84
+ deque<uint8_t>* getMiso(uint8_t address) {
85
+ return &slaves[address].misoBuffer;
86
+ }
87
+
88
+ // to access the MOSI buffer, which records what the master sends during a write
89
+ deque<uint8_t>* getMosi(uint8_t address) {
90
+ return &slaves[address].mosiBuffer;
91
+ }
92
+
93
+
94
+ //////////////////////////////////////////////////////////////////////////////////////////////
95
+ // mock implementation
96
+ //////////////////////////////////////////////////////////////////////////////////////////////
97
+
98
+ // constructor initializes internal data
99
+ TwoWire() {
100
+ resetMocks();
101
+ }
102
+
70
103
  // https://www.arduino.cc/en/Reference/WireBegin
71
104
  // Initiate the Wire library and join the I2C bus as a master or slave. This
72
105
  // should normally be called only once.
@@ -220,15 +253,6 @@ public:
220
253
  // We don't (yet) support the slave role in the mock
221
254
  void onRequest(void (*callback)(void)) { assert(false); }
222
255
 
223
- // testing methods
224
- bool didBegin() { return _didBegin; }
225
-
226
- deque<uint8_t> *getMiso(uint8_t address) {
227
- return &slaves[address].misoBuffer;
228
- }
229
- deque<uint8_t> *getMosi(uint8_t address) {
230
- return &slaves[address].mosiBuffer;
231
- }
232
256
  };
233
257
 
234
258
  extern TwoWire Wire;