arduino_ci 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +32 -24
- data/REFERENCE.md +91 -11
- data/cpp/arduino/Arduino.h +0 -5
- data/cpp/arduino/ArduinoDefines.h +3 -0
- data/cpp/arduino/Godmode.h +63 -6
- data/cpp/arduino/Wire.h +37 -13
- data/cpp/unittest/ArduinoUnitTests.h +32 -0
- data/cpp/unittest/Assertion.h +54 -26
- data/cpp/unittest/Compare.h +58 -51
- data/exe/arduino_ci.rb +186 -76
- data/lib/arduino_ci/arduino_backend.rb +18 -2
- data/lib/arduino_ci/ci_config.rb +5 -2
- data/lib/arduino_ci/host.rb +1 -1
- data/lib/arduino_ci/library_properties.rb +6 -1
- data/lib/arduino_ci/version.rb +1 -1
- data/misc/default.yml +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 95cc7dc7ab0591e45ffe7c1a9cdf31f64b21a8cf794a12ea83a4190af20e7488
|
4
|
+
data.tar.gz: 6e20b49ad3b015445c79511e9795fddbf205f01e20eb8c413e7ff342f4b240f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
[](https://rubygems.org/gems/arduino_ci)
|
4
|
-
[](http://www.rubydoc.info/gems/arduino_ci/1.
|
4
|
+
[](http://www.rubydoc.info/gems/arduino_ci/1.2.0)
|
5
5
|
[](https://gitter.im/Arduino-CI/arduino_ci?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
6
|
+
[](https://github.com/marketplace/actions/arduino_ci)
|
6
7
|
|
7
|
-
|
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
|
-
|
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
|
-
|
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 | [](https://github.com/Arduino-CI/arduino_ci/actions?workflow=windows)
|
21
28
|
|
22
29
|
|
23
|
-
##
|
30
|
+
## Quick Start
|
24
31
|
|
25
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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.
|
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
|
|
data/REFERENCE.md
CHANGED
@@ -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
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
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
|
+
```
|
data/cpp/arduino/Arduino.h
CHANGED
@@ -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)
|
data/cpp/arduino/Godmode.h
CHANGED
@@ -160,21 +160,78 @@ class GodmodeState {
|
|
160
160
|
};
|
161
161
|
|
162
162
|
// io pins
|
163
|
-
|
164
|
-
|
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
|
-
|
171
|
-
|
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
|
data/cpp/arduino/Wire.h
CHANGED
@@ -54,19 +54,52 @@ struct wireData_t {
|
|
54
54
|
class TwoWire : public ObservableDataStream {
|
55
55
|
private:
|
56
56
|
bool _didBegin = false;
|
57
|
-
wireData_t
|
58
|
-
wireData_t
|
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
|
-
|
63
|
-
|
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;
|