Init: Rattenfalle

This commit is contained in:
2024-01-27 23:32:45 +01:00
committed by Jakob Gegeniger
parent 3706823709
commit e82dd3f3a2
18 changed files with 1122 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
+3
View File
@@ -0,0 +1,3 @@
[submodule "core"]
path = core
url = git@github.com:Gustice/ArduinoDevicePlatform.git
+11
View File
@@ -0,0 +1,11 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack",
"pioarduino.pioarduino-ide"
]
}
+6
View File
@@ -0,0 +1,6 @@
{
"C_Cpp.autoAddFileAssociations": false,
"C_Cpp.clang_format_style": "{BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }",
}
+2
View File
@@ -0,0 +1,2 @@
# Rattenfalle
Submodule
+1
Submodule core added at 4a1e39b6aa
+39
View File
@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include <Arduino.h>
#include <Servo.h>
#include <array>
#include "AbHal.hpp"
#include "DcMotor.hpp"
#include "Utils.hpp"
using TimeStamp = decltype(millis());
class ServoGrp {
public:
ServoGrp(int pin) : _pin(pin) {}
void attach() {
_srv.attach(_pin);
}
void detach() {
_srv.detach();
}
void write(int pos) {
_pos = pos;
_srv.write(_pos);
}
private:
Servo _srv;
int _pin;
int _pos{};
};
+97
View File
@@ -0,0 +1,97 @@
/**
* @file DcMotor.hpp
* @author Gustice
* @brief Simple Driver implementation for DRVxxxx Derivatives from Texas instruments
* DRV8848
*
* @copyright Copyright (c) 2024
*/
#include <Arduino.h>
#include <array>
class DcMotor {
static constexpr int FullScale = 256;
public:
struct Pins {
std::array<int, 2> PwmA; // PWM control
int ErrorIn; // Error Feedback from driver
int Sleep; // Sleep control (to enter double mode)
int Ceil; // Maximum speed control
int ErrOut; // Maximum speed control
};
enum State {
Startup = 0,
Idle,
Right,
Left,
};
DcMotor(Pins pins) : _pins(pins) {
pinMode(_pins.PwmA[0], OUTPUT);
pinMode(_pins.PwmA[1], OUTPUT);
pinMode(_pins.ErrorIn, INPUT);
pinMode(_pins.Sleep, OUTPUT);
pinMode(_pins.Ceil, INPUT);
pinMode(_pins.ErrOut, OUTPUT);
// sleep to enter double current mode
delay(5);
digitalWrite(_pins.Sleep, LOW);
delay(5); // @todo double after successful operation
digitalWrite(_pins.Sleep, HIGH);
// set to break
analogWrite(_pins.PwmA[0], FullScale);
analogWrite(_pins.PwmA[1], FullScale);
}
void stop() {
analogWrite(_pins.PwmA[0], FullScale);
analogWrite(_pins.PwmA[1], FullScale);
_state = Idle;
}
void startRight() {
int ceil = analogRead(_pins.Ceil) / 4;
_state = Right;
analogWrite(_pins.PwmA[0], FullScale);
analogWrite(_pins.PwmA[1], FullScale - ceil);
}
void startLeft() {
int ceil = analogRead(_pins.Ceil) / 4;
_state = Left;
analogWrite(_pins.PwmA[0], FullScale - ceil);
analogWrite(_pins.PwmA[1], FullScale);
}
void tick() {
int ceil = analogRead(_pins.Ceil) / 4;
switch (_state) {
case Right:
analogWrite(_pins.PwmA[1], FullScale - ceil);
break;
case Left:
analogWrite(_pins.PwmA[0], FullScale - ceil);
break;
default:
break;
}
int nErr = digitalRead(_pins.ErrorIn);
digitalWrite(_pins.ErrOut, nErr == 0);
}
private:
Pins _pins;
State _state = Startup;
};
+46
View File
@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
+73
View File
@@ -0,0 +1,73 @@
/**
* @file RotatingIndex.hpp
* @author Gustice
* @brief Classes for typical index manipulation
*/
#pragma once
/**
* @brief Index with automatic revolution back to start position
* @details Useful for Buffer-Pointer, or similar tasks
*
* @tparam T Numeric type
*/
template <typename T = int>
class RotatingIndex {
public:
/// @brief Value at witch the index rotates back to beginning
const T MaxIndex;
/**
* @brief Constructor for rotating index
* @brief output index will be set to 0 if incremented value reaches Maximum
* @param max Maximum index for overflow-condition
*/
RotatingIndex(T max) : MaxIndex(max) {
_index = 0;
}
/**
* @brief Get the current index and increment index afterwards
* @return T current index
*/
T GetIndexAndIncrement() {
auto retVal = _index;
_index++;
if (_index >= MaxIndex) {
_index = 0;
}
return retVal;
};
/**
* @brief Get the current index without incrementing the index
* @return T current index
*/
T GetIndex() const {
return _index;
}
/**
* @brief Increments index and retuns if index has been reset
*/
bool IncrementAndCheckIfRevolves() {
_index++;
if (_index >= MaxIndex) {
_index = 0;
return true;
}
return false;
}
/**
* @brief Reset Index to 0
*/
void ResetIndex() {
_index = 0;
}
private:
/// Current Index
T _index;
};
+43
View File
@@ -0,0 +1,43 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
# Base for embedded environments
[env]
test_framework = unity
test_filter = embedded/test_*
; debug_test = embedded/test_...
lib_extra_dirs = core/lib
; build_unflags = -std=gnu++11
; build_flags = -std=c++20
[env:Lair]
# Board: https://docs.platformio.org/en/latest/boards/atmelsam/seeed_xiao.html
platform = renesas-ra
board = nano_r4
framework = arduino
build_unflags = -std=gnu++11
build_flags = -std=c++20
build_src_filter =
-<*>
+<mainLair.cpp>
platform_packages =
toolchain-gccarmnoneeabi@~1.120301.0
lib_deps =
arduino-libraries/Servo @ ^1.3.0
; mainControl.cpp
# Native environment (Host PC)
[env:native]
# overwrite embedded related setup
test_framework = googletest
platform=native
test_filter = native/test_*
; debug_test = native/test_...
+472
View File
@@ -0,0 +1,472 @@
#include "main.hpp"
using namespace abh;
Input extResetGame(0);
Output Magnet1(1);
Output Magnet2(3);
Servo Servo1;
Servo Servo2;
Input endSwitch1(2);
Input endSwitch2(3);
#define Rfid1
Output SLedPin(LED_BUILTIN, abh::Port::LogicType::Inverted);
static StatusLed _statusLed(SLedPin);
void setup() {
Serial.begin(115200);
_statusLed.set(StatusLed::Mode::DoubleFlash);
Servo1.attach(2);
Servo2.attach(3);
Servo1.write(45);
Servo2.write(90);
}
State state{};
void loop() {
static Tick tick(5);
static Tick diagTick(250);
static Tick servoTick(2000);
if (!tick) {
return;
}
static int servo{};
if (servoTick) {
servo++;
if (servo % 2) {
Servo1.write(45);
Servo2.write(0);
} else {
Servo1.write(90);
Servo2.write(180);
}
}
switch (state) {
default:
case Idle: {
state = Start;
} break;
case Start: {
state = Running;
} break;
case Running: {
state = Idle;
} break;
}
if (diagTick) {
_statusLed.tick();
Serial.printf("S=%d 0=%d | s=%d \r\n", (bool)true, (bool)false, state);
}
}
#include <Servo.h>
const int BUFFER_SIZE = 14; // RFID DATA FRAME FORMAT: 1byte head (value: 2), 10byte data (2byte version + 8byte tag), 2byte checksum, 1byte tail (value: 3)
const int DATA_SIZE = 10; // 10byte data (2byte version + 8byte tag)
const int DATA_VERSION_SIZE = 2; // 2byte version (actual meaning of these two bytes may vary)
const int DATA_TAG_SIZE = 8; // 8byte tag
const int CHECKSUM_SIZE = 2; // 2byte checksum
uint8_t buffer[BUFFER_SIZE]; // used to store an incoming data frame
int buffer_index = 0;
String data;
int datainteger;
Servo tor_servo; // Tor mit Ratte
Servo tor2_servo; // Großes Tor in der Ecke
#define Reset 52
#define LED 7
#define Schloss1 46
#define Schloss2 47
#define Tortasteroffen 32
#define Tortastergeschlossen 28
int servo_position, success, tortasterzustand, tortasterzaehler = 0;
int sollID = 9715;
int sollID2 = 22907;
int torzustand = 0; //0=zu | 1=offen
int torFalleTasterOffenZustand, torFalleTasterZuZustand = 0;
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 50; // the debounce time; increase if the output flickers
unsigned long motorsafetyTime = 0;
unsigned long motorsafetyTimeDelay = 5000;
void setup() {
Serial.begin(9600);
Serial1.begin(115200);
Serial3.begin(9600);
pinMode(Reset, INPUT);
pinMode(Tortasteroffen, INPUT);
pinMode(Tortastergeschlossen, INPUT);
pinMode(LED, OUTPUT);
pinMode(Schloss1, OUTPUT);
digitalWrite(Schloss1, HIGH);
pinMode(Schloss2, OUTPUT);
digitalWrite(Schloss2, HIGH);
digitalWrite(LED, HIGH);
//Torzustand erfragen
torFalleTasterOffenZustand = digitalRead(Tortasteroffen);
torFalleTasterZuZustand = digitalRead(Tortastergeschlossen);
Serial.print("Fallentortasteroffen: ");
Serial.println(torFalleTasterOffenZustand);
Serial.print("Fallentortastergeschlossen: ");
Serial.println(torFalleTasterZuZustand);
Serial.println("-------------------------------");
if(torFalleTasterOffenZustand == 0) {
Serial.println("FallenTor ist offen");
torzustand=1;
} else {
Serial.println("FallenTor ist zu");
digitalWrite(LED, LOW);
tor_offnen();
}
Serial.println("INIT DONE");
}
void loop() {
int reading = digitalRead(Reset);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH && torzustand==1) {
Serial.println("Resettaster wurde gedrückt");
tor_schliessen();
}
}
}
lastButtonState = reading;
if (Serial3.available() > 0 && torzustand==0) {
bool call_extract_tag = false;
int ssvalue = Serial3.read(); // read
Serial.println(ssvalue);
if (ssvalue == -1) { // no data was read
return;
}
if (ssvalue == 2) { // RDM630/RDM6300 found a tag => tag incoming
buffer_index = 0;
} else if (ssvalue == 3) { // tag has been fully transmitted
call_extract_tag = true; // extract tag at the end of the function call
}
if (buffer_index >= BUFFER_SIZE) { // checking for a buffer overflow (It's very unlikely that an buffer overflow comes up!)
Serial.println("Error: Buffer overflow detected!");
return;
}
buffer[buffer_index++] = ssvalue; // everything is alright => copy current value to buffer
if (call_extract_tag == true && success == 0) {
if (buffer_index == BUFFER_SIZE) {
unsigned tag = extract_tag();
Serial.println(tag);
if (tag == sollID || tag == sollID2) {
Serial.println("Herzlichen Glückwunsch Sie haben erfolgreich eine Ratte gefangen!");
tor_offnen();
}
} else { // something is wrong... start again looking for preamble (value: 2)
buffer_index = 0;
return;
}
}
} else if (Serial3.available() > 0 && torzustand==1) {
while (Serial3.available() > 0) {
Serial3.read();
}
}
}
unsigned extract_tag() {
uint8_t msg_head = buffer[0];
uint8_t *msg_data = buffer + 1; // 10 byte => data contains 2byte version + 8byte tag
uint8_t *msg_data_version = msg_data;
uint8_t *msg_data_tag = msg_data + 2;
uint8_t *msg_checksum = buffer + 11; // 2 byte
uint8_t msg_tail = buffer[13];
// print message that was sent from RDM630/RDM6300
Serial.println("--------");
Serial.print("Message-Head: ");
Serial.println(msg_head);
Serial.println("Message-Data (HEX): ");
for (int i = 0; i < DATA_VERSION_SIZE; ++i) {
Serial.print(char(msg_data_version[i]));
}
Serial.println(" (version)");
for (int i = 0; i < DATA_TAG_SIZE; ++i) {
Serial.print(char(msg_data_tag[i]));
}
Serial.println(" (tag)");
Serial.print("Message-Checksum (HEX): ");
for (int i = 0; i < CHECKSUM_SIZE; ++i) {
Serial.print(char(msg_checksum[i]));
}
Serial.println("");
Serial.print("Message-Tail: ");
Serial.println(msg_tail);
Serial.println("--");
long tag = hexstr_to_value(msg_data_tag, DATA_TAG_SIZE);
Serial.print("Extracted Tag: ");
Serial.println(tag);
long checksum = 0;
for (int i = 0; i < DATA_SIZE; i += CHECKSUM_SIZE) {
long val = hexstr_to_value(msg_data + i, CHECKSUM_SIZE);
checksum ^= val;
}
Serial.print("Extracted Checksum (HEX): ");
Serial.print(checksum, HEX);
if (checksum == hexstr_to_value(msg_checksum, CHECKSUM_SIZE)) { // compare calculated checksum to retrieved checksum
Serial.print(" (OK)"); // calculated checksum corresponds to transmitted checksum!
} else {
Serial.print(" (NOT OK)"); // checksums do not match
}
Serial.println("");
Serial.println("--------");
return tag;
}
long hexstr_to_value(char *str, unsigned int length) { // converts a hexadecimal value (encoded as ASCII string) to a numeric value
char* copy = malloc((sizeof(char) * length) + 1);
memcpy(copy, str, sizeof(char) * length);
copy[length] = '\0';
// the variable "copy" is a copy of the parameter "str". "copy" has an additional '\0' element to make sure that "str" is null-terminated.
long value = strtol(copy, NULL, 16); // strtol converts a null-terminated string to a long value
free(copy); // clean up
return value;
}
//Hakentor ist bei 76 Grad zu | Rattentor bei 85 Grad
void tor_offnen() {
if(torzustand==0) {
Serial.println("öffnen");
digitalWrite(LED, HIGH);
//tor_servo.write(0);
motorsafetyTime = millis();
digitalWrite(Schloss1, LOW);
int servo_position = 200;
//FallenTor
tor2_servo.attach (9);
while (digitalRead(Tortasteroffen) == 1){
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
//kill Tor öffnen es dauert zu lang
digitalWrite(Schloss1, HIGH);
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #1");
break;
}
servo_position--;
tor2_servo.write(servo_position);
delay(10);
}
int test = servo_position+10;
tor2_servo.write(test);
delay(20);
tor2_servo.detach();
Serial.println("FallenTor offen");
digitalWrite(Schloss1, HIGH);
digitalWrite(Schloss2, LOW);
//RattenTor
tor_servo.attach (4);
for(servo_position = 83; servo_position >=0; servo_position -=1){
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
//kill Tor öffnen es dauert zu lang
digitalWrite(Schloss2, HIGH);
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #2");
break;
}
tor_servo.write(servo_position);
delay(10);
}
tor_servo.detach();
Serial.println("RattennTor offen");
digitalWrite(Schloss2, HIGH);
Serial.println("Alle Elektroschlösser entspannt");
//tor2_servo.write(0);
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
//kill Tor öffnen es dauert zu lang
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #3");
} else {
torzustand = 1;
Serial.println("1Torzustand = 1 - Tore wurden geöffnet");
}
}
while (Serial3.available() > 0) {
Serial3.read();
}
}
void tor_schliessen() {
if(torzustand==1) {
Serial.println("schliessen");
digitalWrite(LED, LOW);
//RattenTor
tor_servo.attach (4);
for(servo_position = 0; servo_position <=83; servo_position +=1){
tor_servo.write(servo_position);
delay(10);
}
tor_servo.detach();
int servo_position = 0;
//FallenTor
tor2_servo.attach (9);
while (digitalRead(Tortastergeschlossen) == 1){
servo_position++;
tor2_servo.write(servo_position);
delay(10);
}
int test = servo_position-3;
tor2_servo.write(test);
delay(20);
tor2_servo.detach();
torzustand = 0;
Serial.println("2Torzustand = 0 - Tore wurden geschlossen");
}
while (Serial3.available() > 0) {
Serial3.read();
}
}
// Hakentor ist bei 76 Grad zu | Rattentor bei 85 Grad
void openDor() {
if (!DoorIsOpen) {
Serial.println("--open");
auto motorsafetyTime = millis();
DoorLock.write(false); // digitalWrite(Schloss1, LOW);
int servo_position = 200;
// FallenTor
while (digitalRead(Tortasteroffen) == 1) {
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
// kill Tor öffnen es dauert zu lang
digitalWrite(Schloss1, HIGH);
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #1");
break;
}
servo_position--;
tor2_servo.write(servo_position);
delay(10);
}
int test = servo_position + 10;
tor2_servo.write(test);
delay(20);
tor2_servo.detach();
Serial.println("FallenTor offen");
digitalWrite(Schloss1, HIGH);
digitalWrite(Schloss2, LOW);
// RattenTor
for (servo_position = 83; servo_position >= 0; servo_position -= 1) {
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
// kill Tor öffnen es dauert zu lang
digitalWrite(Schloss2, HIGH);
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #2");
break;
}
ratDoor.write(servo_position);
delay(10);
}
ratDoor.detach();
Serial.println("RattennTor offen");
digitalWrite(Schloss2, HIGH);
Serial.println("Alle Elektroschlösser entspannt");
// tor2_servo.write(0);
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) {
// kill Tor öffnen es dauert zu lang
Serial.println("Es hat zu lange gedauert. Etwas stimmt nicht. Das Tor öffnen wurde beendet #3");
} else {
DoorIsOpen = true;
Serial.println("1DoorIsOpen = 1 - Tore wurden geöffnet");
}
}
}
void closeDoor() {
if (DoorIsOpen) {
Serial.println("--close");
// RattenTor
ratDoor.attach(4);
for (servo_position = 0; servo_position <= 83; servo_position += 1) {
ratDoor.write(servo_position);
delay(10);
}
ratDoor.detach();
int servo_position = 0;
// FallenTor
tor2_servo.attach(9);
while (digitalRead(DoorClodedPin) == 1) {
servo_position++;
tor2_servo.write(servo_position);
delay(10);
}
int test = servo_position - 3;
tor2_servo.write(test);
delay(20);
tor2_servo.detach();
DoorIsOpen = false;
Serial.println(" -- close door");
}
}
+116
View File
@@ -0,0 +1,116 @@
#include "main.hpp"
using namespace abh;
constexpr TimeStamp motorsafetyTimeDelay = 5000;
constexpr int ServoStartPos = 0;
constexpr int ServoEndPos = 83;
Output SLedPin(LED_BUILTIN);
Output DoorLock(14);
Input endSwitchOpen(19);
Input endSwitchClose(21);
Input openDoorCmd(9);
Output doorOpendRes(8);
ServoGrp DoorServo(3);
static StatusLed _statusLed(SLedPin);
void setup() {
Serial.begin(115200);
_statusLed.set(StatusLed::Mode::DoubleFlash);
doorOpendRes.write(false);
}
enum State {
WaitForOpenCmd,
Open,
WaitForCloseCmd,
Close
};
State state{};
void openDor();
void closeDoor();
void loop() {
static Tick tick(5);
static Tick diagTick(250);
if (!tick) {
return;
}
openDoorCmd.sample();
endSwitchOpen.sample();
endSwitchClose.sample();
switch (state) {
default:
case WaitForOpenCmd: {
if (openDoorCmd.get() == Input::State::Active) {
state = State::Open;
}
} break;
case Open: {
DoorLock.write(true);
openDor();
DoorLock.write(false);
doorOpendRes.write(true);
state = State::WaitForCloseCmd;
} break;
case WaitForCloseCmd: {
if (openDoorCmd.get() == Input::State::Passive) {
state = State::Close;
}
} break;
case Close: {
closeDoor();
doorOpendRes.write(false);
state = WaitForOpenCmd;
} break;
}
if (diagTick) {
_statusLed.tick();
char buff[256];
sprintf(buff, "S=%d | cI=%d sO=%d sC%d \r\n",
state, openDoorCmd.get(), endSwitchOpen.get(), endSwitchClose.get());
Serial.print(buff);
}
}
void openDor() {
Serial.println("--open");
auto motorsafetyTime = millis();
DoorServo.attach();
for (int pos = ServoEndPos; pos >= ServoStartPos; pos -= 1) {
if ((millis() - motorsafetyTime) > motorsafetyTimeDelay) { // prvent overheating
Serial.println("Abort due to timeout");
DoorServo.detach();
return;
}
DoorServo.write(pos);
delay(10);
}
DoorServo.detach();
Serial.println("--isOpen");
}
void closeDoor() {
Serial.println("--close");
DoorServo.attach();
for (int pos = ServoStartPos; pos <= ServoEndPos; pos += 1) {
DoorServo.write(pos);
delay(10);
}
DoorServo.detach();
Serial.println("--isClosed");
}
+11
View File
@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
@@ -0,0 +1,83 @@
#include "StatusLed.h"
#include <Arduino.h>
#include <unity.h>
void setUp(void) {}
void tearDown(void) {}
int LED_PIN = LED_BUILTIN;
void test_LedStaysDark(void) {
StatusLed dut(LED_PIN);
for (size_t i = 0; i < 30; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(LOW, digitalRead(LED_PIN));
delay(10);
}
}
void test_LedIsConstantOn(void) {
StatusLed dut(LED_PIN);
dut.Set(StatusLed::Mode::SteadyOn);
for (size_t i = 0; i < 30; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(HIGH, digitalRead(LED_PIN));
delay(10);
}
}
void test_LedBlinks(void) {
StatusLed dut(LED_PIN);
dut.Set(StatusLed::Mode::Blinking);
for (size_t n = 0; n < 2; n++) {
for (size_t i = 0; i < 8; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(HIGH, digitalRead(LED_PIN));
delay(20);
}
for (size_t i = 0; i < 8; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(LOW, digitalRead(LED_PIN));
delay(20);
}
}
}
void test_LedBlinks_InverseLogic(void) {
StatusLed dut(LED_PIN, StatusLed::LedLogic::Inverted);
dut.Set(StatusLed::Mode::Blinking);
for (size_t n = 0; n < 2; n++) {
for (size_t i = 0; i < 8; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(LOW, digitalRead(LED_PIN));
delay(20);
}
for (size_t i = 0; i < 8; i++) {
dut.Tick();
TEST_ASSERT_EQUAL(HIGH, digitalRead(LED_PIN));
delay(20);
}
}
}
void setup() {
// NOTE!!! Wait for >2 secs
// if board doesn't support software reset via Serial.DTR/RTS
delay(2000);
UNITY_BEGIN(); // IMPORTANT LINE!
RUN_TEST(test_LedStaysDark);
RUN_TEST(test_LedIsConstantOn);
RUN_TEST(test_LedBlinks);
RUN_TEST(test_LedBlinks_InverseLogic);
UNITY_END(); // stop unit testing
}
void loop() {
delay(500);
}
+7
View File
@@ -0,0 +1,7 @@
Import("env")
def after_upload(source, target, env):
import time
time.sleep(2)
env.AddPostAction("upload", after_upload)
+71
View File
@@ -0,0 +1,71 @@
#include <gtest/gtest.h>
#include "RotatingIndex.hpp"
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
if (RUN_ALL_TESTS())
;
return 0;
}
TEST(RotatingIndex, Construction) {
RotatingIndex<int> sut(4);
ASSERT_TRUE(true);
}
TEST(RotatingIndex, InitialState) {
RotatingIndex<int> sut(4);
ASSERT_EQ(sut.GetIndex(), 0);
}
TEST(RotatingIndex, TestOverflowWithGetIndexMethod) {
RotatingIndex<int> sut(4);
ASSERT_EQ(sut.GetIndexAndIncrement(), 0);
ASSERT_EQ(sut.GetIndexAndIncrement(), 1);
ASSERT_EQ(sut.GetIndexAndIncrement(), 2);
ASSERT_EQ(sut.GetIndexAndIncrement(), 3);
ASSERT_EQ(sut.GetIndexAndIncrement(), 0);
ASSERT_EQ(sut.GetIndexAndIncrement(), 1);
}
TEST(RotatingIndex, TestOverflowWithCheckIfRevolvesMethod) {
RotatingIndex<int> sut(4);
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_TRUE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
}
TEST(RotatingIndex, GetIndexReturnsCorrectValue) {
RotatingIndex<int> sut(4);
ASSERT_EQ(sut.GetIndexAndIncrement(), 0);
ASSERT_EQ(sut.GetIndex(), 1);
ASSERT_EQ(sut.GetIndexAndIncrement(), 1);
ASSERT_EQ(sut.GetIndex(), 2);
}
TEST(RotatingIndex, TestReset) {
RotatingIndex<int> sut(4);
sut.GetIndexAndIncrement();
sut.ResetIndex();
ASSERT_EQ(sut.GetIndex(), 0);
}
TEST(RotatingIndex, TestDifferentTypeAndMaximum) {
RotatingIndex<short> sut(6);
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_TRUE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
ASSERT_FALSE(sut.IncrementAndCheckIfRevolves());
}