"Seriöse" Embedded-Entwickler (sprich: stmshchiki) spionieren von Zeit zu Zeit gerne das böse "Arduino" aus, dessen Entwicklungsumgebung unter anderem nicht einmal Hardware-Debugger mit Haltepunkten unterstützt und die Werte von Variablen unter dem Mauszeiger oder in einer speziellen Platte anzeigt Echtzeit . Nun, der Vorwurf ist ganz richtig, das Fenster des Serial Monitor plus Serial.println ist nicht das beste Debugging-Tool. Ein kompetenter Arduino-Fahrer kann den Angriff jedoch leicht abwehren und den anmaßenden Kapitän einsetzen, wenn er (der Arduino-Spieler) Unit-Tests verwendet.
Unit-Tests (Unit-Tests, Unit-Tests) erleichtern das Leben bei der Suche nach Problembereichen der Anwendung, verhindern die Wiederholung bereits gefundener Probleme (Regressionen) und geben messbares Vertrauen in die Zuverlässigkeit des geschriebenen Codes. Dies ist umso wichtiger, wenn eingebettete Anwendungen und alle Arten von mobilen Robotern entwickelt werden, bei denen das Debuggen, Abfangen und Reproduzieren (insbesondere Reproduzieren) von Fehlern im Vergleich zu klassischen Desktop-, Server- oder mobilen Anwendungen besonders schwierig ist.
Der Übergang zur Verwendung automatischer Tests im Projekt erfordert jedoch eine spezielle interne Disziplin, einen speziellen Ansatz zum Schreiben von Code und zum Organisieren des Projektarbeitsbereichs.
Bei der Vorbereitung der Implementierung von Komponententests in einem Projekt sollten Sie Folgendes berücksichtigen:
- Tests erfordern zusätzliche Zeit zum Schreiben von Code (nein: Die Zeit, die für automatische Tests aufgewendet wird, ist vergleichbar mit der Zeit, die für das manuelle Debuggen desselben Abschnitts aufgewendet wird, zahlt sich jedoch über große Entfernungen um ein Vielfaches aus), während der Testcode möglicherweise länger ist nach Größe den Code der Teststelle.
- In einem von Tests abgedeckten Projekt kann es schwierig sein, eine globale Code-Reorganisation (Refactoring) durchzuführen - besonders relevant in der Anfangsphase der Entwicklung, wenn die Codebasis und die interne API nicht ausreichend festgelegt sind (andererseits führt der Refactor eines nicht von Tests abgedeckten Projekts zu denselben Regressionen). du weißt einfach nichts über sie)
- Es ist erforderlich, Anwendungsmodule zu schreiben, damit sie sowohl innerhalb der Anwendung als auch innerhalb einzelner Tests ausgeführt werden können
- Es ist notwendig, die Struktur und die Verbindungen innerhalb des Projekts so zu erarbeiten, dass sie einen Platz für den Hauptanwendungscode, die ausführbare Firmware für die Hauptanwendung, den Testcode und die ausführbare Firmware („Launcher“ / Launcher) zum Ausführen der Tests enthalten.
Ich werde nicht mehr über die Philosophie des Unit-Tests sprechen, sondern nur zeigen, wie einfache Unit-Tests in Ihrem Arduino-Projekt technisch implementiert werden.
Als nächstes betrachten Sie:
- Verschiedene Strategien zum Organisieren eines Projektarbeitsbereichs mit Komponententests unter Berücksichtigung der Funktionen der Arduino-Plattform.
- All-in-One-Option (sowohl Code als auch Tests in einer Skizzendatei),
- Einfügen von Tests in ein separates Modul im Skizzenverzeichnis,
- Tests in einem separaten Projekt durchführen.
- Ausführen von Tests auf dem Gerät,
- Ausführen der gleichen Tests auf einem Desktop-Computer ohne Herunterladen auf das Gerät; Stubs für die Arduino-API
Auswählen einer Bibliothek für Unit-Tests
Wir brauchen ein Unit-Testing-Framework:
- Für C / C ++
- Sollte auf Geräten der Arduino-Familie funktionieren
- Muss auf Desktop-Systemen funktionieren
- Ich liebe leichte Bibliotheken (meine persönliche Präferenz)
Für die Programmierung von Arduino wird die C ++ - Sprache gemischt mit C verwendet. Daher funktioniert theoretisch jedes Unit-Test-Framework für C ++. Wir möchten jedoch Tests sowohl auf dem Desktop-Computer als auch auf dem Gerät ausführen. Tatsache ist, dass einige Aufrufe der Standard-libc-Bibliothek für Arduino implementiert sind, aber keineswegs alle, daher wird nicht jedes Framework, das mit libc arbeitet, für Arduino kompiliert. Das Gegenteil ist auch der Fall: Wenn das Framework speziell für Arduino erstellt wurde, funktioniert es möglicherweise nicht auf dem Desktop-System mit libc.
Ich habe mehrere Frameworks durchgesehen und mich für 2x entschieden:
- ArduinoUnit : https://github.com/mmurdoch/arduinounit . Im Allgemeinen erfüllt es die wichtigsten anfänglichen Anforderungen: Es funktioniert sowohl auf Arduino (offensichtlich vom Namen her) als auch auf Desktop-Systemen (siehe Abschnitt En-Vitro-Tests auf der Projektwebsite), aber auf den ersten Blick schien es etwas schwer zu sein, und ich entschied mich, andere Optionen zu prüfen.
- Sput Library (Sput Unit Testing Framework für C / C ++) https://www.use-strict.de/sput-unit-testing/ . Diese Bibliothek ist so leicht wie möglich: nur eine Header-Datei, auch ohne ein Paar mit der Quelle „.cpp“ (alles wird auf mehreren Makros ausgeführt). Die Ausgabe von Nachrichten erfolgt jedoch über std :: out (was für libc völlig natürlich ist), das auf Arduino einfach nicht implementiert ist.
Trotzdem wurden meine Sympathien für Sput aufgewogen, und das Problem mit std :: out wurde mit mehreren Korrekturen gelöst (printf durch sprintf + Serial.print ersetzen).
Das Ergebnis war ein Sput-Ino- Projekt - ein Port der Sput-Bibliothek zur Arduino-Plattform bei gleichzeitiger Wahrung der Kompatibilität mit Desktop-Systemen mit libc
- Ein Beispiel für eine Einzeldateiskizze mit Tests
/ sput-ino / examples / sput-ino-monolith /
- Ein Beispiel mit der Trennung des Hauptcodes und der Tests in Module
sput-ino / beispiele / sput-ino-module /
- Ausführen von Tests auf dem Desktop-System
sput-ino / example-desktop /
- Ein Beispiel mit der Trennung des Hauptcodes und Tests für verschiedene Projekte - in einem separaten Repository
https://github.com/sadr0b0t/sput-ino-demo
Installieren Sie die Bibliothek
Klonen Sie einfach das Git-Repository https://github.com/sadr0b0t/sput-ino.git in das Verzeichnis $ HOME / Arduino / library :
cd $HOME/Arduino/libraries/
git clone https://github.com/sadr0b0t/sput-ino.git
IDE.
github https://github.com/sadr0b0t/sput-ino/ > ZIP (Clone or download > Download ZIP), sput-ino-master.zip : > > .ZIP ....
> > sput-ino (File > Examples > sput-ino)
:

. () «.ino». «.ino» «.cpp» ( Arduino.h - ), .
sput-ino/examples/sput-ino-monolith/sput-ino-monolith.ino
- :
/**
* @return a b
*/
int a_plus_b(int a, int b) {
return a + b;
}
/**
* @return a b
*/
int a_minus_b(int a, int b) {
return a - b;
}
/**
* ,
* @param pin
* @param num
* @return true, num
*/
bool led_on_even(int pin, int num) {
if(num % 2 == 0) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
}
return num % 2 == 0;
}
sput ( : http://www.use-strict.de/sput-unit-testing/tutorial.html):
#include "sput.h"
/** Test a_plus_b call */
void test_a_plus_b() {
sput_fail_unless(a_plus_b(2, 2) == 4, "2 + 2 == 4");
sput_fail_unless(a_plus_b(-2, 2) == 0, "-2 + 2 == 0");
// this one would pass on 32-bit controllers and would fail on AVR with 16-bit int
sput_fail_unless(a_plus_b(34000, 34000) == 68000, "34000 + 34000 == 68000");
}
/** Test a_minus_b call */
void test_a_minus_b() {
sput_fail_unless(a_minus_b(115, 6) == 109, "115 - 6 == 109");
sput_fail_unless(a_minus_b(13, 17) == -4, "13 - 17 == -4");
}
/** Test test_led_on_even call */
bool test_led_on_even() {
pinMode(13, OUTPUT);
sput_fail_unless(led_on_even(13, 2), "num=2 => led#13 on");
// would pass on desktop, might fail or pass on difference devices
// (e.g.: Arduino Due - fail, ChipKIT Uno32 - pass)
sput_fail_unless(digitalRead(13) == HIGH, "num=2 => led#13 on");
sput_fail_unless(!led_on_even(13, 5), "num=5 => led#13 off");
sput_fail_unless(digitalRead(13) == LOW, "num=5 => led#13 off");
sput_fail_unless(led_on_even(13, 18), "num=18 => led#13 on");
sput_fail_unless(digitalRead(13) == HIGH, "num=18 => led#13 on");
}
(-).
:
/** All tests in one bundle */
int mylib_test_suite() {
sput_start_testing();
sput_enter_suite("a plus b");
sput_run_test(test_a_plus_b);
sput_enter_suite("a minus b");
sput_run_test(test_a_minus_b);
sput_enter_suite("led on even");
sput_run_test(test_led_on_even);
sput_finish_testing();
return sput_get_return_value();
}
:
/** Test suite for a_plus_b call */
int mylib_test_suite_a_plus_b() {
sput_start_testing();
sput_enter_suite("a plus b");
sput_run_test(test_a_plus_b);
sput_finish_testing();
return sput_get_return_value();
}
/** Test suite for a_minus_b call */
int mylib_test_suite_a_minus_b() {
sput_start_testing();
sput_enter_suite("a minus b");
sput_run_test(test_a_minus_b);
sput_finish_testing();
return sput_get_return_value();
}
/** Test suite for led_on_even call */
int mylib_test_suite_led_on_even() {
sput_start_testing();
sput_enter_suite("led on even");
sput_run_test(test_led_on_even);
sput_finish_testing();
return sput_get_return_value();
}
. -, , /, . (, , - ).
:
void run_tests() {
Serial.println("#################### Start testing...");
// comment out specific test suites if firmware does not
// fit to device memory
// Test suite for a_plus_b call
mylib_test_suite_a_plus_b();
// Test suite for a_minus_b call
mylib_test_suite_a_minus_b();
// Test suite for led_on_even call
mylib_test_suite_led_on_even();
// All tests in one bundle
//mylib_test_suite();
Serial.println("#################### Finished testing");
}
setup/loop, run_tests setup , Serial.begin, :
void setup() {
Serial.begin(9600);
while (!Serial);
// run tests
run_tests();
// other code - kinda application business logic
Serial.println("Just show that we call functions from tested lib, nothing useful here");
pinMode(13, OUTPUT);
Serial.print("14+23=");
Serial.println(a_plus_b(14, 23));
Serial.print("14-23=");
Serial.println(a_minus_b(14, 23));
Serial.print("34000+34000=");
Serial.println(a_plus_b(34000, 34000));
}
void loop() {
static int i = 0;
led_on_even(13, i++);
delay(2000);
}
. , run_tests, .
, , ( > / Tools > Serial monitor)
ChipKIT Uno32 ( 32- PIC32):
#################### Start testing...
== Entering suite #1, "a plus b" ==
[1:1] test_a_plus_b:#1 "2 + 2 == 4" pass
[1:2] test_a_plus_b:#2 "-2 + 2 == 0" pass
[1:3] test_a_plus_b:#3 "34000 + 34000 == 68000" pass
--> 3 check(s), 3 ok, 0 failed (0.00%)
==> 3 check(s) in 1 suite(s) finished after 0.00 second(s),
3 succeeded, 0 failed (0.00%)
[SUCCESS]
== Entering suite #1, "a minus b" ==
[1:1] test_a_minus_b:#1 "115 - 6 == 109" pass
[1:2] test_a_minus_b:#2 "13 - 17 == -4" pass
--> 2 check(s), 2 ok, 0 failed (0.00%)
==> 2 check(s) in 1 suite(s) finished after 0.00 second(s),
2 succeeded, 0 failed (0.00%)
[SUCCESS]
== Entering suite #1, "led on even" ==
[1:1] test_led_on_even:#1 "num=2 => led#13 on" pass
[1:2] test_led_on_even:#2 "num=2 => led#13 on" pass
[1:3] test_led_on_even:#3 "num=5 => led#13 off" pass
[1:4] test_led_on_even:#4 "num=5 => led#13 off" pass
[1:5] test_led_on_even:#5 "num=18 => led#13 on" pass
[1:6] test_led_on_even:#6 "num=18 => led#13 on" pass
--> 6 check(s), 6 ok, 0 failed (0.00%)
==> 6 check(s) in 1 suite(s) finished after 0.00 second(s),
6 succeeded, 0 failed (0.00%)
[SUCCESS]
#################### Finished testing
Just show that we call functions from tested lib, nothing useful here
14+23=37
14-23=-9
34000+34000=68000
Arduino Uno ( AVR 16 ):
#################### Start testing...
== Entering suite #1, "a#################### Start testing...
== Entering suite #1, "a plus b" ==
[1:1] test_a_plus_b:#1 "2 + 2 == 4" pass
[1:2] test_a_plus_b:#2 "-2 + 2 == 0" pass
[1:3] test_a_plus_b:#3 "34000 + 34000 == 68000" FAIL
! Type: fail-unless
! Condition: a_plus_b(34000, 34000) == 68000
! Line: 14
--> 3 check(s), 2 ok, 1 failed (?%)
==> 3 check(s) in 1 suite(s) finished after ? second(s),
2 succeeded, 1 failed (?%)
[FAILURE]
== Entering suite #1, "a minus b" ==
[1:1] test_a_minus_b:#1 "115 - 6 == 109" pass
[1:2] test_a_minus_b:#2 "13 - 17 == -4" pass
--> 2 check(s), 2 ok, 0 failed (?%)
==> 2 check(s) in 1 suite(s) finished after ? second(s),
2 succeeded, 0 failed (?%)
[SUCCESS]
== Entering suite #1, "led on even" ==
[1:1] test_led_on_even:#1 "num=2 => led#13 on" pass
[1:2] test_led_on_even:#2 "num=2 => led#13 on" pass
[1:3] test_led_on_even:#3 "num=5 => led#13 off" pass
[1:4] test_led_on_even:#4 "num=5 => led#13 off" pass
[1:5] test_led_on_even:#5 "num=18 => led#13 on" pass
[1:6] test_led_on_even:#6 "num=18 => led#13 on" pass
--> 6 check(s), 6 ok, 0 failed (?%)
==> 6 check(s) in 1 suite(s) finished after ? second(s),
6 succeeded, 0 failed (?%)
[SUCCESS]
#################### Finished testing
Just show that we call functions from tested lib, nothing useful here
14+23=37
14-23=-9
34000+34000=2464
:
— PIC32 , AVR . 34000 + 34000 == 68000 32- PIC32, AVR int = 2 (16 ), , = 2^16-1=65536-1=65535 ( unsigned). AVR 16- int , 32- PIC32 ( 64- x86_64) . , , .
— test_led_on_even ( , ) , , , digitalRead digitalWrite — .
-, digitalRead ( GPIO pinMode INPUT) , GPIO digitalWrite pinMode OUTPUT: digitalRead , .
-, , digitalRead digitalWrite, , . , , digitalWrite/digitalRead (, Arduino UNO AVR , pinMode(13, OUTPUT), ChipKIT Uno32 PIC32 ).
, digitalWrite GPIO , digitalRead . , digitalWriite . - , ( ).

— , .
. , , . , - .
: (.ino) (*.h), (.c) C++ (.cpp). #include, C/C++ . Arduino IDE .
:
sput-ino/examples/sput-ino-modules/
: mylib.h+mylib.cpp
— :
sput-ino/examples/sput-ino-modules/mylib.h
#ifndef MYLIB_H
#define MYLIB_H
/**
* @return a b
*/
int a_plus_b(int a, int b);
/**
* @return a b
*/
int a_minus_b(int a, int b);
/**
* ,
* @param pin
* @param num
* @return true, num
*/
bool led_on_even(int pin, int num);
#endif // MYLIB_TEST_H
. API Arduino, Arduino.h.
sput-ino/examples/sput-ino-modules/mylib.cpp
#include "Arduino.h"
/**
* @return a b
*/
int a_plus_b(int a, int b) {
return a + b;
}
/**
* @return a b
*/
int a_minus_b(int a, int b) {
return a - b;
}
/**
* ,
* @param pin
* @param num
* @return true, num
*/
bool led_on_even(int pin, int num) {
if(num % 2 == 0) {
digitalWrite(pin, HIGH);
} else {
digitalWrite(pin, LOW);
}
return num % 2 == 0;
}
: mylib-test.h+mylib-test.cpp
— (-), :
sput-ino/examples/sput-ino-modules/mylib-test.h
#ifndef MYLIB_TEST_H
#define MYLIB_TEST_H
/** Test suite for a_plus_b call */
int mylib_test_suite_a_plus_b();
/** Test suite for a_minus_b call */
int mylib_test_suite_a_minus_b();
/** Test suite for led_on_even call */
int mylib_test_suite_led_on_even();
/** All tests in one bundle */
int mylib_test_suite();
#endif // MYLIB_TEST_H
: , mylib.h Arduino.h .
sput-ino/examples/sput-ino-modules/mylib-test.cpp
// http://www.use-strict.de/sput-unit-testing/tutorial.html
#include "sput.h"
#include "Arduino.h"
#include "mylib.h"
/** Test a_plus_b call */
void test_a_plus_b() {
sput_fail_unless(a_plus_b(2, 2) == 4, "2 + 2 == 4");
sput_fail_unless(a_plus_b(-2, 2) == 0, "-2 + 2 == 0");
// this one would pass on 32-bit controllers and desktop (libc) and would fail on AVR with 16-bit int
sput_fail_unless(a_plus_b(34000, 34000) == 68000, "34000 + 34000 == 68000");
}
/** Test a_minus_b call */
void test_a_minus_b() {
sput_fail_unless(a_minus_b(115, 6) == 109, "115 - 6 == 109");
sput_fail_unless(a_minus_b(13, 17) == -4, "13 - 17 == -4");
}
/** Test test_led_on_even call */
bool test_led_on_even() {
pinMode(13, OUTPUT);
sput_fail_unless(led_on_even(13, 2), "num=2 => led#13 on");
// would pass on desktop, might fail or pass on difference devices
// (e.g.: Arduino Due - fail, ChipKIT Uno32 - pass)
sput_fail_unless(digitalRead(13) == HIGH, "num=2 => led#13 on");
sput_fail_unless(!led_on_even(13, 5), "num=5 => led#13 off");
sput_fail_unless(digitalRead(13) == LOW, "num=5 => led#13 off");
sput_fail_unless(led_on_even(13, 18), "num=18 => led#13 on");
sput_fail_unless(digitalRead(13) == HIGH, "num=18 => led#13 on");
}
/*******************************************/
// test suites
/** Test suite for a_plus_b call */
int mylib_test_suite_a_plus_b() {
sput_start_testing();
sput_enter_suite("a plus b");
sput_run_test(test_a_plus_b);
sput_finish_testing();
return sput_get_return_value();
}
/** Test suite for a_minus_b call */
int mylib_test_suite_a_minus_b() {
sput_start_testing();
sput_enter_suite("a minus b");
sput_run_test(test_a_minus_b);
sput_finish_testing();
return sput_get_return_value();
}
/** Test suite for led_on_even call */
int mylib_test_suite_led_on_even() {
sput_start_testing();
sput_enter_suite("led on even");
sput_run_test(test_led_on_even);
sput_finish_testing();
return sput_get_return_value();
}
/** All tests in one bundle */
int mylib_test_suite() {
sput_start_testing();
sput_enter_suite("a plus b");
sput_run_test(test_a_plus_b);
sput_enter_suite("a minus b");
sput_run_test(test_a_minus_b);
sput_enter_suite("led on even");
sput_run_test(test_led_on_even);
sput_finish_testing();
return sput_get_return_value();
}
: mylib.h mylib-test.h.
sput-ino/examples/sput-ino-modules/sput-ino-modules.ino
#include "mylib.h"
#include "mylib-test.h"
/** run tests on device */
void run_tests() {
Serial.println("#################### Start testing...");
// comment out specific test suites if firmware does not
// fit to device memory
// Test suite for a_plus_b call
mylib_test_suite_a_plus_b();
// Test suite for a_minus_b call
mylib_test_suite_a_minus_b();
// Test suite for led_on_even call
mylib_test_suite_led_on_even();
// All tests in one bundle
//mylib_test_suite();
Serial.println("#################### Finished testing");
}
void setup() {
Serial.begin(9600);
while (!Serial);
// run tests
run_tests();
// other code - kinda application business logic
Serial.println("Just show that we call functions from tested lib, nothing useful here");
pinMode(13, OUTPUT);
Serial.print("14+23=");
Serial.println(a_plus_b(14, 23));
Serial.print("14-23=");
Serial.println(a_minus_b(14, 23));
Serial.print("34000+34000=");
Serial.println(a_plus_b(34000, 34000));
}
void loop() {
static int i = 0;
led_on_even(13, i++);
delay(2000);
}
, , .
, :
sput-ino-modules/
— :
sput-ino-modules/sput-ino-modules.ino
— :
sput-ino-modules/mylib.h
sput-ino-modules/mylib.cpp
— :
sput-ino-modules/mylib-test.h
sput-ino-modules/mylib-test.cpp
, . , , , / - / ,
, , , :
- «.ino» (), (: «myproj1/myproj1.ino»).
- — «.h», «.c», ++ «.cpp», «.ino».
- (- /tmp/build2b91b1aecd83593cdd811791fcf30e97.tmp/), «.ino» «.cpp», «.cpp» «.c» gcc «.o», «.o» «.hex» ( « ») avrdude (: > , ).
- $HOME/Arduino/libraries/ — .
, :
- «.ino». «.ino», .
- #include (: #include "mylib.h") .
- , (: #include "../proj2/proj2lib.h"), .. .
- «.h» , ( , , ), «.cpp» «.c», .
- , , .
, :
- $HOME/Arduino/libraries/
- ,
( , ) :
https://github.com/sadr0b0t/sput-ino-demo
- .
$HOME/Arduino/libraries
cd $HOME/Arduino/libraries/
ln -s /path/to/projects/dir/sput-ino-demo
, , .
:
$HOME/Arduino/libraries/sput-ino-demo/
— .
— /++:
sput-ino-demo/src/
sput-ino-demo/src/mylib.h
sput-ino-demo/src/mylib.cpp
:
#include "mylib.h"
, library.properties:
sput-ino-demo/library.properties
name=sput-ino-demo
version=0.0.1
author=sadr0b0t
maintainer=sadr0b0t
sentence=Demo project for sput-ino, Sput unit testing framework for C/C++ port to Arduino
paragraph=Demo project for sput-ino. Sput is an unit testing framework for C/C++ that focuses on simplicity of use and maximum portability. It is implemented as a single ANSI C compliant header file that provides all macros needed to start unit testing in nearly no time.
category=Other
url=https://github.com/sadr0b0t/sput-ino-demo
architectures=*
(, library.properties, .h, .c, .cpp src/, sput-ino-demo/. / , , .. src/, , .)
— , :
sput-ino-demo/sput-ino-demo/sput-ino-demo.ino
-2, - > > sput-ino-demo/sput-ino-demo, . , > .
-3, - mylib.h mylib.cpp Arduino IDE (.. sput-ino-demo/), . , , .
-4, «.ino».
, , .
:
sput-ino-demo/test/
:
sput-ino-demo/test/mylib-test-arduino/
sput-ino-demo/test/mylib-test-arduino/mylib-test-arduino.ino
sput-ino-demo/test/mylib-test-arduino/mylib-test.h
sput-ino-demo/test/mylib-test-arduino/mylib-test.cpp
:
sput-ino-demo/test/mylib-test-desktop/
.
, . , . ? -, : , , , ; , . -, , (, , , mock), (, , ). , , .
, :
, , -, , . , sput-ino : sput libc, sput-ino — sput API, . , , sput-ino, libc, .
, :
API
( a_plus_b a_minis_b) — , /++. - , . , . ( , - 16- int AVR, 32- PIC32 64- Intel/AMD ). .
API
( led_on_even) . , , digitalRead digitalWrite. , digitalRead digitalWrite libc , , ( GPIO?). ? - ? x86? AVR ?
, , - , , . , . , .
, API : ( ), . , . .
sput-ino/example-desktop/
Arduino.h
sput-ino/example-desktop/Arduino.h
#ifndef WPROGRAM_H
#define WPROGRAM_H
#define OUTPUT 1
#define INPUT 0
#define HIGH 1
#define LOW 0
unsigned long micros();
void pinMode(int pin, int mode);
void digitalWrite(int pin, int val);
int digitalRead(int pin);
#endif // WPROGRAM_H
Arduino.cpp:
sput-ino/example-desktop/Arduino.cpp
// saved values for pins
static int _pin_modes[64];
static int _pin_values[64];
// from Arduino.h
/**
* micros stub
*/
unsigned long micros() {
return 0;
}
/**
* Set GPIO pin mode
*/
void pinMode(int pin, int mode) {
_pin_modes[pin] = mode;
}
/**
* Write GPIO pin value
*/
void digitalWrite(int pin, int val) {
_pin_values[pin] = val;
}
/**
* Read GPIO pin value
*/
int digitalRead(int pin) {
return _pin_values[pin];
}
API , , ( ). .
, , . main:
sput-ino/example-desktop/mylib-test-main.cpp
#include "mylib-test.h"
int main() {
return mylib_test_suite();
}
sput-ino/example-desktop/build.sh
#!/bin/sh
# simple build script, feel free to modify or convert it
# to your favourite build system config
#gcc -c c_file_stub.c
#g++ -std=c++11 -c cpp_file_stub.cpp
g++ -std=c++11 -c \
-I. -I../examples/sput-ino-modules -I$HOME/Arduino/libraries/sput-ino/src \
Arduino.cpp \
../examples/sput-ino-modules/mylib.cpp \
../examples/sput-ino-modules/mylib-test.cpp \
mylib-test-main.cpp
g++ *.o -o test_mylib
( )
./test_mylib
:
== Entering suite #1, "a plus b" ==
[1:1] test_a_plus_b:#1 "2 + 2 == 4" pass
[1:2] test_a_plus_b:#2 "-2 + 2 == 0" pass
[1:3] test_a_plus_b:#3 "34000 + 34000 == 68000" pass
--> 3 check(s), 3 ok, 0 failed (0.00%)
== Entering suite #2, "a minus b" ==
[2:1] test_a_minus_b:#1 "115 - 6 == 109" pass
[2:2] test_a_minus_b:#2 "13 - 17 == -4" pass
--> 2 check(s), 2 ok, 0 failed (0.00%)
== Entering suite #3, "led on even" ==
[3:1] test_led_on_even:#1 "num=2 => led#13 on" pass
[3:2] test_led_on_even:#2 "num=2 => led#13 on" pass
[3:3] test_led_on_even:#3 "num=5 => led#13 off" pass
[3:4] test_led_on_even:#4 "num=5 => led#13 off" pass
[3:5] test_led_on_even:#5 "num=18 => led#13 on" pass
[3:6] test_led_on_even:#6 "num=18 => led#13 on" pass
--> 6 check(s), 6 ok, 0 failed (0.00%)
==> 11 check(s) in 3 suite(s) finished after 0.00 second(s),
11 succeeded, 0 failed (0.00%)
[SUCCESS]
, , . , .
API ; ,
, , digitalWrite GPIO , digitalRead . , digitalWriite . , , digitalWrite , digitalRead. , digitalWrite/digitalRead, - ( digitalRead ), API , (, pinMode).
, API , .
, _Arduino.h ( ):
sput-ino/example-desktop/_Arduino.h
#ifndef _ARDUINO_H
#define _ARDUINO_H
// Additional calls to get extended info from Arduino mocks
/** Get pin mode */
int _get_pin_mode(int pin);
/** Get pin value */
int _get_pin_value(int pin);
#endif // _ARDUINO_H
Arduino.cpp:
sput-ino/example-desktop/Arduino.cpp
// From _Arduino.h
// Calls to get extended info from Arduino mocks
/** Get pin mode */
int _get_pin_mode(int pin) {
return _pin_modes[pin];
}
/** Get pin value */
int _get_pin_value(int pin) {
return _pin_values[pin];
}
, _get_pin_value digitalRead, _get_pin_mode API .
test_led_on_even — test_led_on_even_desktoponly, _get_pin_value digitalRead. , — sput-ino/example-desktop/
:
sput-ino/example-desktop/mylib-test-desktoponly.h
#ifndef MYLIB_TEST_DESKTOPONLY_H
#define MYLIB_TEST_DESKTOPONLY_H
/** Test suite for led_on_even call */
int mylib_test_suite_led_on_even_desktoponly();
/** Desktop-only tests in one bundle */
int mylib_test_suite_desktoponly();
#endif // MYLIB_TEST_DESKTOPONLY_H
:
sput-ino/example-desktop/mylib-test-desktoponly.cpp
// http://www.use-strict.de/sput-unit-testing/tutorial.html
#include "sput.h"
#include "_Arduino.h"
#include "Arduino.h"
#include "mylib.h"
/** Test test_led_on_even call */
bool test_led_on_even_desktoponly() {
// we do not use Arduino API calls here to get info about
// moked chip state, use calls from _Arduino.h instead
sput_fail_unless(led_on_even(13, 2), "num=2 => led#13 on");
sput_fail_unless(_get_pin_value(13) == HIGH, "num=2 => led#13 on");
sput_fail_unless(!led_on_even(13, 5), "num=5 => led#13 off");
sput_fail_unless(_get_pin_value(13) == LOW, "num=5 => led#13 off");
sput_fail_unless(led_on_even(13, 18), "num=18 => led#13 on");
sput_fail_unless(_get_pin_value(13) == HIGH, "num=18 => led#13 on");
}
/*******************************************/
// test suites
/** Test suite for led_on_even call */
int mylib_test_suite_led_on_even_desktoponly() {
sput_start_testing();
sput_enter_suite("led on even (only desktop)");
sput_run_test(test_led_on_even_desktoponly);
sput_finish_testing();
return sput_get_return_value();
}
/** All tests in one bundle */
int mylib_test_suite_desktoponly() {
sput_start_testing();
sput_enter_suite("led on even (only desktop)");
sput_run_test(test_led_on_even_desktoponly);
sput_finish_testing();
return sput_get_return_value();
}
— : - , .
sput-ino/example-desktop/mylib-test-main.cpp
#include "mylib-test.h"
#include "mylib-test-desktoponly.h"
int main() {
return mylib_test_suite() | mylib_test_suite_desktoponly();
}
( mylib-test-desktoponly.cpp)
#!/bin/sh
# simple build script, feel free to modify or convert it
# to your favourite build system config
#gcc -c c_file_stub.c
#g++ -std=c++11 -c cpp_file_stub.cpp
g++ -std=c++11 -c \
-I. -I../examples/sput-ino-modules -I$HOME/Arduino/libraries/sput-ino/src \
Arduino.cpp \
../examples/sput-ino-modules/mylib.cpp \
../examples/sput-ino-modules/mylib-test.cpp \
mylib-test-desktoponly.cpp \
mylib-test-main.cpp
g++ *.o -o test_mylib
./build.sh
./test_mylib
== Entering suite #1, "a plus b" ==
[1:1] test_a_plus_b:#1 "2 + 2 == 4" pass
[1:2] test_a_plus_b:#2 "-2 + 2 == 0" pass
[1:3] test_a_plus_b:#3 "34000 + 34000 == 68000" pass
--> 3 check(s), 3 ok, 0 failed (0.00%)
== Entering suite #2, "a minus b" ==
[2:1] test_a_minus_b:#1 "115 - 6 == 109" pass
[2:2] test_a_minus_b:#2 "13 - 17 == -4" pass
--> 2 check(s), 2 ok, 0 failed (0.00%)
== Entering suite #3, "led on even" ==
[3:1] test_led_on_even:#1 "num=2 => led#13 on" pass
[3:2] test_led_on_even:#2 "num=2 => led#13 on" pass
[3:3] test_led_on_even:#3 "num=5 => led#13 off" pass
[3:4] test_led_on_even:#4 "num=5 => led#13 off" pass
[3:5] test_led_on_even:#5 "num=18 => led#13 on" pass
[3:6] test_led_on_even:#6 "num=18 => led#13 on" pass
--> 6 check(s), 6 ok, 0 failed (0.00%)
==> 11 check(s) in 3 suite(s) finished after 0.00 second(s),
11 succeeded, 0 failed (0.00%)
[SUCCESS]
== Entering suite #1, "led on even (only desktop)" ==
[1:1] test_led_on_even_desktoponly:#1 "num=2 => led#13 on" pass
[1:2] test_led_on_even_desktoponly:#2 "num=2 => led#13 on" pass
[1:3] test_led_on_even_desktoponly:#3 "num=5 => led#13 off" pass
[1:4] test_led_on_even_desktoponly:#4 "num=5 => led#13 off" pass
[1:5] test_led_on_even_desktoponly:#5 "num=18 => led#13 on" pass
[1:6] test_led_on_even_desktoponly:#6 "num=18 => led#13 on" pass
--> 6 check(s), 6 ok, 0 failed (0.00%)
==> 6 check(s) in 1 suite(s) finished after 0.00 second(s),
6 succeeded, 0 failed (0.00%)
[SUCCESS]
:
, :
, ( ) . — 3 : 1 — ( ), 2 — STEP HIGH, 3 — : STEP LOW, .
:
#define ACTION_STOP 0
#define ACTION_CHECK_BOUNDS 1
#define ACTION_GO_HIGH 2
#define ACTION_STEP 3
int step_count = 0;
int action = ACTION_STOP;
void timer_handle_interrupts() {
// ,
//
if(!timeForStep()) return;
//
if(ACTION_CHECK_BOUNDS == action) {
// -
if(checkBounds()) {
// -
action = ACTION_STOP;
} else {
// ,
action = ACTION_GO_HIGH;
}
} else if(ACTION_GO_HIGH == action) {
// STEP,
digitalWrite(STEP_PIN, HIGH);
action = ACTION_STEP;
} else if(ACTION_STEP == action) {
//
digitalWrite(STEP_PIN, LOW);
step_count++;
if(step_count < max_steps) {
//
action = ACTION_CHECK_BOUNDS;
} else {
//
action = ACTION_STOP;
}
}
}
timer_handle_interrupts — , ( : arduino-timer-api).
, , , , - : , , - . , , . ? , , IDE. 100500 ? ? - .
, :
void test_timer_handle_interrupts() {
// 1
test_timer_handle_interrupts();
// 1
// 2
// 3
// 2
test_timer_handle_interrupts();
// 1
// 2
// 3
// 3
test_timer_handle_interrupts();
// 1
// 2
// 3
// 100500
for(long i = 0; i < 100500 - 3; i++) {
}
// 1
// 2
// 3
// 100500+1
test_timer_handle_interrupts();
// 1
// 2
// 3
// ...
//
}
test_timer_handle_interrupts. , : 1, 2, 3, 103, , , — .