Les développeurs embarqués "sérieux" (lire: stmshchiki) aiment de temps en temps espionner le méchant "arduino", dont l'environnement de développement, entre autres, ne prend même pas en charge les débogueurs matériels avec des points d'arrêt et la visualisation des valeurs des variables sous le curseur de la souris ou dans une plaque spéciale dans en temps réel . Eh bien, l'accusation est tout à fait vraie, la fenêtre du Serial Monitor plus Serial.println n'est pas le meilleur outil de débogage. Cependant, un conducteur arduino compétent pourra facilement parer l'attaque et mettre en place le capitaine présomptueux s'il (le joueur arduino) utilise des tests unitaires.
Ainsi, les tests unitaires (tests unitaires, tests unitaires) facilitent la vie lors de la recherche des zones problématiques de l'application, empêchent la répétition des problèmes déjà trouvés (régressions), donnent une confiance mesurable dans la fiabilité du code écrit. Ceci est d'autant plus important lors du développement d'applications embarquées et de toutes sortes de robots mobiles, pour lesquels le processus de débogage, de capture et de reproduction (en particulier de reproduction) des erreurs est particulièrement difficile par rapport aux applications de bureau, de serveur ou mobiles classiques.
Cependant, la transition vers l'utilisation de tests automatiques dans le projet nécessite une discipline interne particulière, une approche spéciale pour écrire du code et organiser l'espace de travail du projet.
Lors de la préparation de la mise en œuvre de tests unitaires dans un projet, vous devez garder à l'esprit:
- Les tests nécessitent du temps supplémentaire pour écrire du code (en fait, non: le temps consacré aux tests automatiques est assez comparable au temps passé à déboguer manuellement la même section, mais il sera rentable plusieurs fois sur une longue distance), tandis que le code de test peut dépasser par taille le code du site de test.
- Dans un projet couvert par des tests, il peut être difficile de réaliser une réorganisation globale du code (refactoring) - particulièrement pertinente au stade initial de développement, lorsque la base de code et l'API interne ne sont pas suffisamment établies (en revanche, le refactoriseur d'un projet non couvert par les tests entraînera toutes les mêmes régressions, vous ne les connaissez tout simplement pas)
- Il est nécessaire d'écrire des modules d'application afin qu'ils puissent être exécutés à la fois dans l'application et dans des tests individuels
- Il est nécessaire de déterminer la structure et les connexions au sein du projet afin qu'il contienne une place pour le code de l'application principale, le micrologiciel exécutable pour l'application principale, le code de test, le micrologiciel exécutable («lanceur» / lanceur) pour exécuter les tests.
Je ne parlerai plus de la philosophie des tests unitaires, mais je montrerai simplement comment implémenter techniquement des tests unitaires simples dans votre projet Arduino.
Ensuite, considérez:
- Plusieurs stratégies pour organiser un espace de travail de projet avec des tests unitaires prenant en compte les fonctionnalités de la plateforme Arduino.
- Option tout-en-un (code et tests dans un seul fichier d'esquisse),
- mettre des tests dans un module séparé dans le répertoire sketch,
- faire des tests dans un projet séparé.
- Exécution de tests sur l'appareil,
- exécution des mêmes tests sur un ordinateur de bureau sans téléchargement sur l'appareil; talons pour l'API Arduino
Choisir une bibliothèque pour les tests unitaires
Nous avons besoin d'un cadre de tests unitaires:
- Pour C / C ++
- Devrait fonctionner sur les appareils de la famille Arduino
- Doit fonctionner sur les systèmes de bureau
- J'adore les bibliothèques légères (ma préférence personnelle)
Pour la programmation d'Arduino, le langage C ++ est utilisé mélangé avec C, par conséquent, théoriquement, tout cadre de test unitaire pour C ++ fonctionnera, mais nous voulons exécuter des tests à la fois sur l'ordinateur de bureau et sur l'appareil. Le fait est que certains appels à la bibliothèque libc standard sont implémentés pour Arduino, mais en aucun cas tous, donc tous les frameworks fonctionnant avec libc ne sont pas compilés pour Arduino. L'inverse est également vrai: si le cadre est spécialement conçu pour Arduino, il peut ne pas fonctionner sur le système de bureau avec libc.
J'ai regardé à travers plusieurs cadres et j'ai opté pour 2x:
- ArduinoUnit : https://github.com/mmurdoch/arduinounit . En général, il satisfait aux exigences initiales clés: il fonctionne à la fois sur Arduino (évidemment d'après le nom) et sur les systèmes de bureau (voir la section Tests in vitro sur le site Web du projet), mais d'un coup d'œil, cela semblait un peu lourd et j'ai décidé de regarder d'autres options.
- Bibliothèque Sput (Sput Unit Testing Framework pour C / C ++) https://www.use-strict.de/sput-unit-testing/ . Cette bibliothèque est aussi légère que possible: un seul fichier d'en-tête, même sans paire avec la source «.cpp» (tout se fait sur plusieurs macros). Cependant, la sortie des messages passe par std :: out (qui est complètement naturel pour libc), qui n'est tout simplement pas implémenté sur Arduino.
Néanmoins, mes sympathies étaient dépassées en faveur de Sput, et le problème avec std :: out a été résolu avec plusieurs correctifs (remplacement de printf par sprintf + Serial.print).
Le résultat a été un projet sput-ino - un port de la bibliothèque sput vers la plate-forme Arduino tout en maintenant la compatibilité avec les systèmes de bureau avec libc
- un exemple d'esquisse à fichier unique avec tests
/ sput-ino / exemples / sput-ino-monolith /
- un exemple avec la séparation du code principal et des tests en modules
sput-ino / exemples / sput-ino-modules /
- exécution de tests sur le système de bureau
sput-ino / exemple-bureau /
- un exemple avec la séparation du code principal et des tests pour différents projets - dans un référentiel séparé
https://github.com/sadr0b0t/sput-ino-demo
Installer la bibliothèque
Il vous suffit de cloner le référentiel git https://github.com/sadr0b0t/sput-ino.git dans le répertoire $ HOME / Arduino / bibliothèques :
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, , , — .