Main-Controller-Source/v4/v4.ino
2024-03-23 17:39:07 +01:00

627 lines
19 KiB
C++

/*
Copyright (C) 2024 Riccardo Henning and Philipp Wagner
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino_USBHostMbed5.h>
#include <DigitalOut.h>
#include <FATFileSystem.h>
#include <SPI.h>
#include <WiFi.h>
#include <Keypad.h>
#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_PN532.h>
// NFC-Pin-Definitionen und -Objekt
#define PN532_SCK (91)
#define PN532_MOSI (90)
#define PN532_SS (4)
#define PN532_MISO (89)
Adafruit_PN532 nfc(PN532_SCK, PN532_MISO, PN532_MOSI, PN532_SS);
//NFC-Request für Anlernen
bool request1 = false;
USBHostMSD msd;
mbed::FATFileSystem usb("usb");
mbed::DigitalOut otg(PB_8, 1);
const int pinRedLED = 86; // Rot
const int pinGreenLED = 87; // Grün
const int pinBlueLED = 88; // Blau
const int pinStatusRedLED = 26; // ROT externe LED
const int pinStatusGreenLED = 24; // Grün externe LED
const int pinStatusYellowLED = 22; // Gelb externe LED
//ISR
bool doorIsOpened = false;
volatile bool ButtonPressed = false;
volatile unsigned long lastPressTime = 0;
// WiFI
WiFiServer server(80);
// Keypad Initialisierung
const byte ROWS = 4; //vier Reihen
const byte COLS = 4; //vier Spalten
char hexaKeys[ROWS][COLS] = {
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
byte rowPins[ROWS] = { 32, 34, 36, 38 }; //verbinde mit den Reihen-Pinouts des Keypads
byte colPins[COLS] = { 40, 42, 44, 46 }; //verbinde mit den Spalten-Pinouts des Keypads
//LCD Initialisierung
const int rs = 49, en = 51, d4 = 33, d5 = 35, d6 = 37, d7 = 39;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
//Überprüfung
String inputString = ""; // Zum Speichern der Tasteneingaben
String correctString = ""; // Der zu überprüfende String
//Ultraschall
int echo_pin = 7;
int trig_pin = 6;
bool isPackageSpace = true;
bool isPackageInside = false;
long distanceUltraSonic = 0;
void setup() {
attachInterrupt(digitalPinToInterrupt(71), isrPin71, CHANGE);
Serial.begin(9600);
// Ultraschall Set
pinMode(trig_pin, OUTPUT);
pinMode(echo_pin, INPUT);
// LCD Beginnen
analogWrite(2, 50); // Kontrast LCD einstellen
lcd.begin(16, 2);
// LCD Startup Message und Copyright
lcd.print("Startup Brain V4");
lcd.setCursor(0, 1);
lcd.print("c:Wagner|Henning");
// EXTERNE STATUS LEDs
pinMode(pinStatusRedLED, OUTPUT);
pinMode(pinStatusGreenLED, OUTPUT);
pinMode(pinStatusYellowLED, OUTPUT);
digitalWrite(pinStatusRedLED, HIGH);
digitalWrite(pinStatusGreenLED, HIGH);
digitalWrite(pinStatusYellowLED, HIGH);
// NFC-Kram
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
while (!versiondata) {
ledBlink(GPIOJ, 14);
lcd.clear();
lcd.println("Error starting: ");
lcd.setCursor(0, 1);
lcd.println("NFC Module error");
delay(500);
}
nfc.setPassiveActivationRetries(0x00);
//NFC-Anlern-Knopf --> BOOT0 auf Giga R1 Wifi
pinMode(PC_13, INPUT);
//USB-A
pinMode(PA_15, OUTPUT);
digitalWrite(PA_15, HIGH);
// Kommunikationsleitungsen
pinMode(69, OUTPUT);
pinMode(71, INPUT);
int randomSeedValue = analogRead(0); // RandomSeed value with some Noise...
randomSeed(randomSeedValue);
while (!msd.connect()) {
delay(1000);
}
int err = usb.mount(&msd);
if (err) {
Serial.println("Error mounting USB device");
while (1)
;
}
Serial.println("Mounting USB device... done");
//Onboard LED
pinMode(pinRedLED, OUTPUT);
pinMode(pinGreenLED, OUTPUT);
pinMode(pinBlueLED, OUTPUT);
digitalWrite(pinRedLED, LOW);
char ssid[32] = "";
char pass[32] = "";
FILE *wifiFile = fopen("/usb/WiFi.txt", "r");
if (wifiFile) {
fscanf(wifiFile, "%31s\n%31s", ssid, pass);
fclose(wifiFile);
} else {
strcpy(ssid, "SSID");
strcpy(pass, "PASSWORD");
FILE *newWifiFile = fopen("/usb/WiFi.txt", "w");
if (newWifiFile) {
fprintf(newWifiFile, "%s\n%s", ssid, pass);
fclose(newWifiFile);
}
}
int status = WL_IDLE_STATUS;
while (status != WL_CONNECTED) {
status = WiFi.begin(ssid, pass);
delay(10000);
}
server.begin();
digitalWrite(pinGreenLED, LOW);
digitalWrite(pinRedLED, HIGH);
digitalWrite(pinBlueLED, HIGH);
//externer LED-Status
statusYellow();
// Serielle Ausgabe der IP
Serial.println("Connected Succesfully!");
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// LCD Start des Programmes
lcd.clear();
lcd.print("IP: ");
lcd.setCursor(0, 1);
lcd.print(ip);
delay(5000); // Warte 5 Sekunden
lcdWritePinInterface();
}
void loop() {
// NFC-Anlern-Knopp
if (digitalRead(PC_13) == HIGH) {
Serial.println("Anlernen angefragt.");
lcd.clear();
lcd.print("neuen NFC-TAG");
lcd.setCursor(0, 1);
lcd.print("vorzeigen");
request1 = true; // Setzen Sie request1 auf true, wenn der Button gedrückt wurde
}
// NFC-Tag lesen
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t uidLength;
boolean success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (success) {
// UID in eine String-Repräsentation umwandeln
String uidString = "";
for (uint8_t i = 0; i < uidLength; i++) {
uidString += String(uid[i], HEX);
}
// Überprüfen, ob der Button gedrückt wurde
if (request1) {
// UID in die Datei "NFC-UIDS.txt" schreiben
FILE *file = fopen("/usb/NFC-UIDS.txt", "a+");
if (file) {
fprintf(file, "%s\n", uidString.c_str());
fclose(file);
// LCD-Anzeige aktualisieren
lcd.clear();
lcd.print("NFC-Tag");
lcd.setCursor(0, 1);
lcd.print("gespeichert!");
delay(1000);
lcdWritePinInterface();
request1 = false;
}
} else {
// UID in der Datei "NFC-UIDS.txt" überprüfen
FILE *file = fopen("/usb/NFC-UIDS.txt", "r");
boolean tagFound = false; // Variable hinzufügen, um zu überwachen, ob der Tag gefunden wurde
if (file) {
char line[32];
while (fgets(line, sizeof(line), file)) {
String lineString = String(line);
lineString.trim();
if (lineString.equalsIgnoreCase(uidString)) { // Verwende equalsIgnoreCase für eine nicht case-sensitive Überprüfung
Serial.println("NFC: Akzeptiert");
//LED-Status
statusGreen();
lcd.clear();
lcd.print("NFC-TAG:");
lcd.setCursor(0, 1);
lcd.print("akzeptiert!");
delay(2000);
lcdWritePinInterface();
//LED-Status
statusYellow();
tagFound = true; // Tag gefunden
// Kommunikations-UPDATE
openDoor();
break;
}
}
fclose(file);
if (!tagFound) {
Serial.println("NFC: Nicht akzeptiert"); // Wenn der Tag nicht gefunden wurde, zeige diese Nachricht
lcd.clear();
statusRed();
lcd.print("NFC-TAG:");
lcd.setCursor(0, 1);
lcd.print("nicht akzeptiert!");
delay(1000);
lcdWritePinInterface();
statusYellow();
}
}
}
}
WiFiClient client = server.available();
if (client) {
//Serial.println("Client start");
lcd.clear();
lcd.print("Webinterface!");
lcd.setCursor(0, 1);
lcd.print("keine Eingabe...");
boolean currentLineIsBlank = true;
String request = "";
while (client.connected()) {
if (client.available()) {
//Serial.println(request);
char c = client.read();
if (c == '\n' && currentLineIsBlank) {
if (request.indexOf("/generie}rePIN ") != -1) {
String pin = generatePIN();
// Schreibe die generierte PIN direkt in die Datei PINs.txt auf dem USB-Stick
FILE *pinFile = fopen("/usb/PINs.txt", "a+");
if (pinFile) {
fprintf(pinFile, "%s\n", pin.c_str());
fclose(pinFile);
}
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("Deine generierte PIN: " + pin);
client.println("</html>");
} else if (request.indexOf("/ ") != -1) {
// Senden Sie eine HTML-Seite zurück, die den Status dedistanceUltraSonic = r Tür anzeigt
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println("Refresh: 5");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("<head><title>Packstation</title></head>");
client.println("<body><h1>Packstation (Selbstbau) </h1>");
client.println("<p>Codename: Brain (Version: 4)</p>");
client.println("<h2>Tuerstatus:</h2>");
if (doorIsOpened) {
client.println("<p>Die Tuer ist geoeffnet.</p>");
} else {
client.println("<p>Die Tuer ist geschlossen.</p>");
}
client.println("<h2>Packetstatus</h2>");
if (isPackageInside) {
client.println("<p> In der Packstation liegen Packete </p>");
} else {
client.println("<p> Kein Packet ist in der Packstation</p>");
}
client.println("<h2>Code-Generierung:</h2>");
client.println("<a href=\"/generierePIN\"> Zusteller-PIN generieren </a>");
client.println("<br>");
client.println("<a href=\"/generieOWNERPIN\"> Besitzer-PIN generieren </a>");
client.println("</body></html>");
} else if (request.indexOf("/generieOWNERPIN ") != -1) {
String pin = generateOwnerPIN();
FILE *pinFile = fopen("/usb/OWNER-PINs.txt", "a+");
if (pinFile) {
fprintf(pinFile, "%s\n", pin.c_str());
fclose(pinFile);
}
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("Deine generierte PIN: " + pin);
client.println("</html>");
} else {
client.println("HTTP/1.1 404 Not found");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("404 Not Found");
client.println("</html>");
}
break;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
request += c;
}
}
client.stop();
delay(100);
lcdWritePinInterface();
//Serial.println("Client Stop");
}
//Serial.println("Keypad 1");
char customKey = customKeypad.getKey();
//Serial.println("Keypad 2");
if (customKey) {
if (customKey == '#') {
// Überprüfe, ob die eingegebene PIN in den korrekten PINs enthalten ist
bool pinAccepted = false;
FILE *pinFile = fopen("/usb/PINs.txt", "r");
if (pinFile) {
char line[32];
while (fgets(line, sizeof(line), pinFile)) {
String correctPin = String(line);
correctPin.trim();
if (inputString == correctPin) {
if (isPackageSpace) { // Überprüfung ob denn noch genung Platz drinne ist..
pinAccepted = true;
break; // Beende die Schleife, wenn eine korrekte PIN gefunden wurde
}
}
}
fclose(pinFile);
}
if (!pinAccepted) {
// Überprüfe, ob die eingegebene PIN in den OWNER-PINs enthalten ist
pinFile = fopen("/usb/OWNER-PINs.txt", "r");
if (pinFile) {
char line[32];
while (fgets(line, sizeof(line), pinFile)) {
String correctPin = String(line);
correctPin.trim();
if (inputString == correctPin) {
pinAccepted = true;
break; // Beende die Schleife, wenn eine korrekte PIN gefunden wurde
}
}
fclose(pinFile);
}
}
if (pinAccepted) {
//LED-Status
Serial.println("PIN: akzeptiert");
lcd.clear();
lcd.print("PIN:");
lcd.setCursor(0, 1);
lcd.print("akzeptiert!");
delay(1000);
lcdWritePinInterface();
// Kommunikations-UPDATE
openDoor();
// Lösche die verwendete PIN aus der Datei PINs.txt
FILE *pinFile = fopen("/usb/PINs.txt", "r");
FILE *tempFile = fopen("/usb/temp.txt", "w");
if (pinFile && tempFile) {
char line[32];
while (fgets(line, sizeof(line), pinFile)) {
String currentPin = String(line);
currentPin.trim();
// Schreibe alle PINs außer der verwendeten PIN in die temporäre Datei
if (currentPin != inputString) {
fprintf(tempFile, "%s\n", currentPin.c_str());
}
}
fclose(pinFile);
fclose(tempFile);
// Lösche die ursprüngliche Datei und benenne die temporäre Datei um
remove("/usb/PINs.txt");
rename("/usb/temp.txt", "/usb/PINs.txt");
}
inputString = ""; // Setze den Eingabestring zurück
} else {
lcd.clear();
statusRed();
Serial.println("PIN: nicht akzeptiert!");
lcd.print("PIN:");
lcd.setCursor(0, 1);
lcd.print("nicht akzeptiert!");
delay(1000);
lcdWritePinInterface();
statusYellow();
}
inputString = ""; // Setze den Eingabestring zurück
statusYellow();
} else if (customKey == '*') {
// Setze den Eingabestring zurück
inputString = "";
lcd.clear();
lcd.print("Eingabe");
lcd.setCursor(0, 1);
lcd.print("zurueckgesetzt");
delay(1000);
lcdWritePinInterface();
} else {
// Füge die gedrückte Taste zum Eingabestring hinzu
inputString += customKey;
lcd.print(customKey);
}
}
if (doorIsOpened) {
//andere LEDs aus.
digitalWrite2(GPIOJ, 12, false);
digitalWrite2(GPIOG, 12, false);
digitalWrite2(GPIOJ, 14, false);
lcd.clear();
lcd.print("Tuer offen!");
ledBlink(GPIOG, 12); // PIN 24
lcdWritePinInterface();
//Ausgangszustand
digitalWrite2(GPIOJ, 12, true);
digitalWrite2(GPIOG, 12, false);
digitalWrite2(GPIOJ, 14, false);
}
ultraSonicDistanceRead();
delay(1);
}
String generatePIN() {
const char validCharacters[] = "ABCD0123456789";
String pin = "";
for (int i = 0; i < 6; i++) {
int index = random(0, sizeof(validCharacters) - 1);
pin += validCharacters[index];
}
return pin;
}
String generateOwnerPIN() {
const char validCharacters[] = "ABCD0123456789";
String pin = "";
for (int i = 0; i < 7; i++) {
int index = random(0, sizeof(validCharacters) - 1);
pin += validCharacters[index];
}
return pin;
}
void isrPin71() {
static unsigned long lastPressTime = 0;
// Nur den Druck verarbeiten, wenn seit dem letzten Druck mehr als 20 Millisekunden vergangen sind
if (millis() - lastPressTime >= 20) {
if (digitalRead(71) == 0) {
doorIsOpened = false;
}
if (digitalRead(71) == 1) {
doorIsOpened = true;
}
ButtonPressed = true;
lastPressTime = millis();
}
}
// UND JETZT, NACH 500 Stunden: ASSEMBLY!!!!!!
void ledBlink(GPIO_TypeDef *port, uint32_t pin) {
digitalWrite2(port, pin, true);
delayApproxOneSecond();
digitalWrite2(port, pin, false);
delayApproxOneSecond();
}
void digitalWrite2(GPIO_TypeDef *port, uint32_t pin, bool state) {
volatile uint32_t *bsrr = &(port->BSRR);
if (state) {
// Setzt den Pin
asm volatile(
"mov r0, %0\n\t" // Lade die Adresse des BSRR-Registers
"mov r1, #1\n\t" // Setze r1 auf 1
"lsl r1, r1, %1\n\t" // Verschiebe 1 um die Anzahl der Bits, die durch pin angegeben sind
"str r1, [r0]\n\t" // Schreibe den Wert in BSRR, setzt den Pin
: // Keine Ausgaben
: "r"(bsrr), "r"(pin)
: "r0", "r1" // Verwendete Register
);
} else {
// Löscht den Pin
asm volatile(
"mov r0, %0\n\t" // Lade die Adresse des BSRR-Registers
"mov r1, #1\n\t" // Setze r1 auf 1
"lsl r1, r1, %1\n\t" // Verschiebe 1 um pin + 16 Positionen
"str r1, [r0]\n\t" // Schreibe den Wert in BSRR, löscht den Pin
: // Keine Ausgaben
: "r"(bsrr), "r"(pin + 16)
: "r0", "r1" // Verwendete Register
);
}
}
void delayApproxOneSecond() {
asm volatile(
"mov r0, %0 \n" // Lädt den Wert (480000000) in das Register r0
"1: \n" // Beginn des Schleifenlabels
"subs r0, #1 \n" // Subtrahiert 1 von r0 und aktualisiert die Flags
"bne 1b \n" // Springt zurück zum Label 1, wenn r0 nicht 0 ist
: // keine Ausgaben
: "r"(480000000) // Der Wert, der in r0 geladen wird
: "r0" // Teilt dem Compiler mit, dass r0 verändert wird
);
}
//ENDE ASSEMBLY
void lcdWritePinInterface() {
lcd.clear();
lcd.print("PIN eingeben:");
lcd.setCursor(0, 1);
}
void openDoor() {
digitalWrite(69, HIGH);
delay(100);
digitalWrite(69, LOW);
}
void statusGreen() {
digitalWrite(pinStatusGreenLED, HIGH);
digitalWrite(pinStatusRedLED, LOW);
digitalWrite(pinStatusYellowLED, LOW);
}
void statusYellow() {
digitalWrite(pinStatusRedLED, LOW);
digitalWrite(pinStatusGreenLED, LOW);
digitalWrite(pinStatusYellowLED, HIGH);
}
void statusRed() {
digitalWrite(pinStatusGreenLED, LOW);
digitalWrite(pinStatusRedLED, HIGH);
digitalWrite(pinStatusYellowLED, LOW);
}
void ultraSonicDistanceRead() {
// UltraSchall
digitalWrite(trig_pin, LOW); // um Probleme mit potenziellen ECHOS zu vermeiden
delay(5); // um Probleme mit potenziellen ECHOS zu vermeiden
digitalWrite(trig_pin, HIGH);
delayMicroseconds(10);
digitalWrite(trig_pin, LOW);
long echoTime = pulseIn(echo_pin, HIGH);
long distanceUltraSonic = (echoTime / 2) * 0.03432;
if (distanceUltraSonic > 30) {
isPackageSpace = true;
isPackageInside = false;
} else if (distanceUltraSonic < 7) {
isPackageSpace = false;
isPackageInside = true;
} else {
isPackageSpace = true;
isPackageInside = true;
}
}