ActionPi is an easy to use Action Camera for the Raspberry Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

757 lines
19 KiB

/*
* ActionPi.cpp
* Version 1.02
* IT-Hardware Projekt GWS-Bühl
* Copyright 2016 <admin@kellerkinder.xyz>
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*
*zum kompilieren ---> g++ -Wall "%f" -o"%e" -l raspicam -l bcm2835 -std=c++0x
*oder---> g++ -Wall "%f" -o"%e" -l raspicam -l bcm2835 -std=c++14
*/
#include <iostream>
#include <stdio.h>
#include <time.h>
#include <string>
#include <stdlib.h>
#include <ctime>
#include <algorithm>
#include <fstream>
#include <bcm2835.h>
#include <raspicam/raspicam.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
using namespace std;
string gibDateiName();
string getFolderName();
void videoAufnehmen();
int fotoAufnehmen();
void liveAusgabe();
void videoAbspeichern();
void initialisierung();
void blinken();
void herunterfahren();
void programmBeenden();
void convert();
void creatNewFolder();
void creatDCIM();
bool ordnerExistiert(string pfad);
void pruefeNewFolder(string input);
void rueckschau(string input);
void setStandardWerte();
void einstellungen();
void einstellungErhoehen();
void einstellungVerringern();
void zuruecksetzten();
void iso(int richtung);
void helligkeit(int richtung);
void kontrast(int richtung);
void saettigung(int richtung);
void verschlusszeit(int richtung);
void setISO ( int iso );
void setBrightness ( unsigned int brightness );
void setContrast ( int contrast );
void setSaturation ( int saturation );
void setExposureCompensation ( int val );
void setShutterSpeed ( unsigned int ss );
int getMODI();
int getREC();
int getEx1();
int getEx2();
int getEx3();
#define LED RPI_V2_GPIO_P1_13
#define MODI RPI_V2_GPIO_P1_22
#define REC RPI_V2_GPIO_P1_18
#define Ex1 RPI_V2_GPIO_P1_16
#define Ex2 RPI_V2_GPIO_P1_15
#define Ex3 RPI_V2_GPIO_P1_11
int valMODI;
int valREC;
int valEx1;
int valEx2;
int valEx3;
int valISO;
int valHelligkeit;
int valKontrast;
int valSaettigung;
int valVerschlusszeit;
int zaehlerISO = 1;
int zaehlerHelligkeit = 1;
int zaehlerKontrast = 1;
int zaehlerSaettigung = 2;
int zaehlerVerschlusszeit = 4;
int einstellung = 0; // 0=Verschlusszeit;1=ISO;2=Kontrast;3=Helligkeit;4=Sättigung;
int wieLangeGedrueckt = 0;
bool aktiv = true;
bool videoAufnahme = false;
bool liveBildWirdAngezeigt = false;
int main(int argc, char **argv)
{
creatDCIM(); //prüft ob DCIM Ordner existiert, sollt er nicht existieren wird er erstellt
creatNewFolder(); //prüft ob Datums-Ordner existiert, sollt er nicht existieren wird er erstellt
if (!bcm2835_init())
return 1;
initialisierung();
setStandardWerte();
while (aktiv)
{
if(videoAufnahme && getMODI() )
{
videoAbspeichern();
}
if(!liveBildWirdAngezeigt)
{
liveAusgabe(); // Live-Ausgabe wird gestartet
}
if(getREC())
{
//REC Taster gedrückt
if(getMODI())
{
//Fotomodus
fotoAufnehmen();
}
else{
//Videomodus
if(!videoAufnahme)
{
videoAufnehmen();
delay(1000); // mindestens 1sec Video
}
else{
videoAbspeichern();
}
}
}
if(getMODI()){ // Eindtellungen nur im Fotomodus
einstellungen();
einstellungErhoehen();
einstellungVerringern();
zuruecksetzten();
}
delay(100);
programmBeenden(); // prüft ob das Programm beendet werden soll
herunterfahren(); // prüft ob der Pi heruntergefahren werden soll
} //while Ende
bcm2835_close();
return 0;
}
//setzt Fotoeinstellungen zurück
void zuruecksetzten()
{
if(getEx2()){
if(wieLangeGedrueckt < 20){
wieLangeGedrueckt = wieLangeGedrueckt +1;
//cout<<wieLangeGedrueckt<<endl;
}
else{
wieLangeGedrueckt = 0;
cout<<"Zurückgesetzt"<<endl;
blinken();
setStandardWerte();
}
}
return;
}
//öffnet Einstellungen und zeigt die verschiedenen Optionen an
void einstellungen()
{
if(getEx2()){
delay(100);
einstellung = einstellung +1;
if(einstellung == 5){
einstellung = 0;
}
//cout<<einstellung<<endl;
if(einstellung ==1){
cout<<"ISO:";
cout<<valISO<<endl;
}
if(einstellung == 3){
cout<<"Helligkeit:";
cout<<valHelligkeit<<endl;
}
if(einstellung == 2){
cout<<"Kontrast:";
cout<<valKontrast<<endl;
}
if(einstellung == 4){
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
if(einstellung == 0){
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
}
return;
}
//setzt die gewählte Einstellung auf den nächts höheren Wert
void einstellungErhoehen()
{
if(getEx3()){
delay(100);
wieLangeGedrueckt = 0;
if(einstellung == 1){
//ISO
iso(1);
}
if(einstellung == 3){
//Helligkeit
helligkeit(1);
}
if(einstellung == 2){
//Kontrast
kontrast(1);
}
if(einstellung == 4){
//Sättigung
saettigung(1);
}
if(einstellung == 0){
//Verschlusszeit
verschlusszeit(1);
}
}
return;
}
//setzt die gewählte Einstellung auf den nächts niedrigeren Wert
void einstellungVerringern()
{
if(getEx1()){
delay(100);
wieLangeGedrueckt = 0;
if(einstellung == 1){
//ISO
iso(-1);
}
if(einstellung == 3){
//Helligkeit
helligkeit(-1);
}
if(einstellung == 2){
//Kontrast
kontrast(-1);
}
if(einstellung == 4){
//Sättigung
saettigung(-1);
}
if(einstellung == 0){
//Verschlusszeit
verschlusszeit(-1);
}
}
return;
}
//Werte für ISO 100,400,600,600,800 min:100; max:800
void iso(int richtung)
{
zaehlerISO = zaehlerISO + (richtung);
if(zaehlerISO == -1){
zaehlerISO = 0;
}
if(zaehlerISO == 4){
zaehlerISO = 3;
}
if(zaehlerISO == 0){
valISO = 100;
cout<<"ISO:";
cout<<valISO<<endl;
}
if(zaehlerISO == 1){
valISO = 400;
cout<<"ISO:";
cout<<valISO<<endl;
}
if(zaehlerISO == 2){
valISO = 600;
cout<<"ISO:";
cout<<valISO<<endl;
}
if(zaehlerISO == 3){
valISO = 800;
cout<<"ISO:";
cout<<valISO<<endl;
}
return;
}
//Werte für Helligkeit 25,50,75,100
void helligkeit(int richtung)
{
zaehlerHelligkeit = zaehlerHelligkeit + (richtung);
if(zaehlerHelligkeit == -1){
zaehlerHelligkeit = 0;
}
if(zaehlerHelligkeit == 4){
zaehlerHelligkeit = 3;
}
if(zaehlerHelligkeit == 0){
valHelligkeit = 25;
cout<<"Helligkeit:";
cout<<valHelligkeit<<endl;
}
if(zaehlerHelligkeit == 1){
valHelligkeit = 50;
cout<<"Helligkeit:";
cout<<valHelligkeit<<endl;
}
if(zaehlerHelligkeit == 2){
valHelligkeit = 75;
cout<<"Helligkeit:";
cout<<valHelligkeit<<endl;
}
if(zaehlerHelligkeit == 3){
valHelligkeit = 100;
cout<<"Helligkeit:";
cout<<valHelligkeit<<endl;
}
return;
}
//Werte für Kontrast -50,0,50,100
void kontrast(int richtung)
{
zaehlerKontrast = zaehlerKontrast + (richtung);
if(zaehlerKontrast == -1){
zaehlerKontrast = 0;
}
if(zaehlerKontrast == 4){
zaehlerKontrast = 3;
}
if(zaehlerKontrast == 0){
valKontrast = -50;
cout<<"Kontrast:";
cout<<valKontrast<<endl;
}
if(zaehlerKontrast == 1){
valKontrast = 0;
cout<<"Kontrast:";
cout<<valKontrast<<endl;
}
if(zaehlerKontrast == 2){
valKontrast = 50;
cout<<"Kontrast:";
cout<<valKontrast<<endl;
}
if(zaehlerKontrast == 3){
valKontrast = 100;
cout<<"Kontrast:";
cout<<valKontrast<<endl;
}
return;
}
//Werte für Sättigung -100,-75,0,50,100
void saettigung(int richtung)
{
zaehlerSaettigung = zaehlerSaettigung + (richtung);
if(zaehlerSaettigung == -1){
zaehlerSaettigung = 0;
}
if(zaehlerSaettigung == 5){
zaehlerSaettigung = 4;
}
if(zaehlerSaettigung == 0){
valSaettigung = -100;
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
if(zaehlerSaettigung == 1){
valSaettigung = -75;
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
if(zaehlerSaettigung == 2){
valSaettigung = 0;
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
if(zaehlerSaettigung == 3){
valSaettigung = 50;
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
if(zaehlerSaettigung == 4){
valSaettigung = 100;
cout<<"Saettigung:";
cout<<valSaettigung<<endl;
}
return;
}
//Werte für Verschluss-/Belichtungszeit 0,5000,20000,40000,100000 kleiner = kürzere Verschlusszeit
void verschlusszeit(int richtung)
{
zaehlerVerschlusszeit = zaehlerVerschlusszeit + (richtung);
if(zaehlerVerschlusszeit == -1){
zaehlerVerschlusszeit = 0;
}
if(zaehlerVerschlusszeit == 5){
zaehlerVerschlusszeit = 4;
}
if(zaehlerVerschlusszeit == 0){
valVerschlusszeit = 5000;
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
if(zaehlerVerschlusszeit == 1){
valVerschlusszeit = 20000;
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
if(zaehlerVerschlusszeit == 2){
valVerschlusszeit = 40000;
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
if(zaehlerVerschlusszeit == 3){
valVerschlusszeit = 100000;
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
if(zaehlerVerschlusszeit == 4){
valVerschlusszeit = 0;
cout<<"Verschlusszeit:";
cout<<valVerschlusszeit<<endl;
}
return;
}
//wird von void zuruecksetzten() aufgerufen und setzt die Fotoeinstellungen zurück auf den Standartwert
void setStandardWerte()
{
valISO = 400;
valHelligkeit = 50;
valKontrast = 0;
valSaettigung = 0;
valVerschlusszeit = 0;
return;
}
//startet die Videoaufnahme
void videoAufnehmen()
{
bcm2835_gpio_set(LED); //schaltet LED an
videoAufnahme = true; // Merker für aktuelle Videoaufnahme
system("killall raspivid"); //beendet den Prozess raspivid (Liveausgabe)
system("raspivid -o vid.h264 -t 1140000 -p '0,-10,720,480' &"); //nimmt video mit 19 Minuten auf -o temporäre output Datei, -p '0,-10,1280,720' für Position und Größe des Vorschau Bildes
liveBildWirdAngezeigt = false; //setzt Merker für Livebildausgabe
return;
}
//nimmt ein temporäres Foto im ppm Format auf
int fotoAufnehmen()
{
bcm2835_gpio_set(LED); //schaltet LED an
system("killall raspivid");
raspicam::RaspiCam Camera; //definiert Camera Objekt
//setzt die gewählten Fotoeinstellungen
Camera.setISO(valISO);
Camera.setBrightness(valHelligkeit);
Camera.setContrast(valKontrast);
Camera.setSaturation(valSaettigung);
Camera.setShutterSpeed(valVerschlusszeit);
//Öffnet Camera
if ( !Camera.open()) {cerr<<"Fehler beim öffnen der Kamera!"<<endl;return -1;} //gibt Fehlermeldung aus sofern Kamera öffnen nicht möglich
sleep(1); //schlafe 1 Sekunde bis Kamera stabilisiert (ohne Pause wird das Bild rot)
Camera.grab(); //hohle Kamera
//reserviere Speicher
unsigned char *data=new unsigned char[ Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB )]; //setzt Bild Format auf RGB
Camera.retrieve ( data,raspicam::RASPICAM_FORMAT_RGB );//aufnehmen des Bildes
std::ofstream outFile ("bild.ppm" ,std::ios::binary ); //speichern des temporären Bildes
outFile<<"P6\n"<<Camera.getWidth() <<" "<<Camera.getHeight() <<" 255\n";
outFile.write ( ( char* ) data, Camera.getImageTypeSize ( raspicam::RASPICAM_FORMAT_RGB ) ); //speichern der zusätzlichen Parameter
delete data; //gibt speicher wieder frei
liveBildWirdAngezeigt = false; //setzt Merker für Livebildausgabe
convert(); //ruft Funktion zum konvertieren des temporären Bildes auf
bcm2835_gpio_clr(LED); //schaltet LED aus
return 1;
}
void liveAusgabe ()
{
liveBildWirdAngezeigt = true; //setzt Merker für Livebildausgabe
system("raspivid -t -0 -p '0,-10,720,480'&"); //-p '0,0,1280,720' für Position und Größe des Vorschau Bildes
return;
}
//konvertiert Video und speichert es auf USB Stick
void videoAbspeichern()
{
bcm2835_gpio_clr(LED); //schaltet LED aus
std::string datname = gibDateiName(); //holen des Dateinamen
std::string ordnerName = getFolderName(); //holen des Ordnernamen
pruefeNewFolder(ordnerName); //prüfen ob Ordner bereits existiert
std::string cmd_line = std::string() + " sudo MP4Box -fps 30 -add vid.h264 /media/usb0/DCIM/"+ordnerName+"/""\"" +datname+"\".mp4 "; //Befehl zu packen von video in .mp4 container
system( cmd_line.c_str() ); //ruft pack befehl auf
system("killall raspivid");//beendet video aufnahme
system("rm vid.h264"); //löscht temporäre vid.h264 video datei
videoAufnahme = false; //Merker für Videoaufnahme
liveBildWirdAngezeigt = false;//setzt Merker für Livebildausgabe
blinken(); //lässt LED blinken
return;
}
//konvertiert Foto und speichert es auf USB Stick
void convert(){
cout << "Speichern von Bild ..." << endl;
std::string datname = gibDateiName(); //holen des Dateinamen
std::string ordnerName = getFolderName(); //holen des Ordnernamen
pruefeNewFolder(ordnerName);
std::string comand = "convert bild.ppm /media/usb0/DCIM/"+ordnerName+ "/" + datname + ".jpg"; //Befehl zum konverieren, Ordnername und Dateiname werden hinzugefügt
const char *cComand = comand.c_str(); //befehl zum ausführen in cons char
system(cComand); //ausführen des Befehls
std::string pfad = "fbi --noverbose -T 1 /media/usb0/DCIM/"+ordnerName+ "/" + datname + ".jpg &/"; //Befehl zum anzeigen das fertigen Bildes
system("rm bild.ppm"); //löschen des temporären Bildes
rueckschau(pfad);
sleep(4); //für 4 Sekunden
system("killall fbi"); //beendet Anzeigen des Bildes
cout << "Abspeichern fertig" << endl;
return;
}
//anzeigen des fertigen Bildes
void rueckschau(string input)
{
const char *cComand = input.c_str();
system(cComand);
return;
}
//erstellt den Dateinamen aus der auktuellen Uhrzeit
string gibDateiName()
{
time_t t = time(0);
struct tm *aT = localtime(&t); //holen der aktuellen Zeit
int istd = aT->tm_hour; //holen der Stunden
int imin = aT->tm_min; //holen der Minuten
int isec = aT->tm_sec; //holen der Sekunden
std::string sstd = to_string(istd); //in String konvertieren
std::string smin = to_string(imin);
std::string ssec = to_string(isec);
std::string datName = sstd + "-" + smin + "-" + ssec + "ActionPi"; //zu einem String zusammenfügen
return datName;
}
//erstellen des neuen Ordners
void creatNewFolder()
{
std::string folderName = getFolderName(); //holen des Ordnernamen
std::string pfad = "/media/usb0/DCIM/" + folderName; //Pafd des Ordners
bool exists = ordnerExistiert(pfad); //prüfen ob Ordner existiert
if(exists == false) //wenn nein dann neuen Ordner erstellen
{
std::string comand = "mkdir " + pfad + ""; //Befehl zum erstellen des Ordners
const char *cComand = comand.c_str();
system(cComand);
cout << "Ordner erstellt." << endl;
}
else //falls Ordner bereits vorhanden
{
cout << "Ordner existiert bereits." << endl;
}
return;
}
//erstellen des DCIM Ordners
void creatDCIM()
{
std::string dcmiPfad = "/media/usb0/DCIM";
bool dcmiExists = ordnerExistiert(dcmiPfad);
if(dcmiExists == false){
std::string dcmiComand = "mkdir /media/usb0/DCIM";
const char *dcmicComand = dcmiComand.c_str();
system(dcmicComand);
cout << "DCIM Ordner erstellt." << endl;
}
else
{
cout << "DCIM existiert bereits." << endl;
}
}
//prüft ob Ordner/DCIM bereits existiert
bool ordnerExistiert(string pfad)
{
const char *cPfad = pfad.c_str();
DIR *pDir; //Verzeichniss wird auf aktuellen Pfad gesetzt
bool oExists = false;
pDir = opendir(cPfad); //öffnen des Pfades
if(pDir != NULL) //falls Ordner unter dem aktuellen Pfad vorhanden pDIR ungleich NULL
{
oExists = true;
closedir(pDir); //schließen des Ordners
}
return oExists;
}
//prüft ob Ordner bereits existiert (wird gebraucht sollt die Kamera länger als 0.00 Uhr in Betrieb sein "0 Uhr Bug")
void pruefeNewFolder(string input)
{
std::string pfad = "/media/usb0/DCIM/" + input;
bool newFolderExists = ordnerExistiert(pfad);
if(newFolderExists == false)
{
creatNewFolder();
}
else
{
}
return;
}
//erstellt den Ordnernamen aus der auktuellen Uhrzeit (siehe gibDateiName)
string getFolderName()
{
char *wtagName[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
char *monatName[] = { "Dec", "Jan", "Feb", "Mar", "Apr", "May", "June", "July", "Aug", "Sept", "Oct", "Nov" };
time_t t = time(0);
struct tm *aT = localtime(&t);
int tag = aT->tm_mday;
int wtag = aT->tm_wday;
int monat = aT->tm_mon;
std::string stag = std::to_string(tag);
std::string tagumonat = std::string() + wtagName[wtag] + "-" + monatName[monat];
std::string folName = tagumonat + "-" + stag;
return folName;
}
void initialisierung()
{
bcm2835_gpio_fsel(LED, BCM2835_GPIO_FSEL_OUTP); //Setze LED als Ausgang
bcm2835_gpio_fsel(MODI, BCM2835_GPIO_FSEL_INPT); //Setze MODI als Eingang
bcm2835_gpio_fsel(REC, BCM2835_GPIO_FSEL_INPT); //Setze REC als Eingang
bcm2835_gpio_fsel(Ex1, BCM2835_GPIO_FSEL_INPT); //Setze Ex1 als Eingang
bcm2835_gpio_fsel(Ex2, BCM2835_GPIO_FSEL_INPT); //Setze Ex2 als Eingang
bcm2835_gpio_fsel(Ex3, BCM2835_GPIO_FSEL_INPT); //Setze Ex3 als Eingang
bcm2835_gpio_set_pud(MODI, BCM2835_GPIO_PUD_UP); //Schalter als Öffner
bcm2835_gpio_set_pud(REC, BCM2835_GPIO_PUD_UP); //Schalter als Öffner
bcm2835_gpio_set_pud(Ex1, BCM2835_GPIO_PUD_UP); //Schalter als Öffner
bcm2835_gpio_set_pud(Ex2, BCM2835_GPIO_PUD_UP); //Schalter als Öffner
bcm2835_gpio_set_pud(Ex3, BCM2835_GPIO_PUD_UP); //Schalter als Öffner
return;
}
//liest die Schalterstellung von MODI ein
int getMODI()
{
valMODI = !bcm2835_gpio_lev(MODI);
return valMODI;
}
//liest die Schalterstellung von REC ein
int getREC()
{
valREC = !bcm2835_gpio_lev(REC);
return valREC;
}
//liest die Schalterstellung von Ex1 ein
int getEx1()
{
valEx1 = !bcm2835_gpio_lev(Ex1);
return valEx1;
}
//liest die Schalterstellung von Ex2 ein
int getEx2()
{
valEx2 = !bcm2835_gpio_lev(Ex2);
return valEx2;
}
//liest die Schalterstellung von Ex3 ein
int getEx3()
{
valEx3 = !bcm2835_gpio_lev(Ex3);
return valEx3;
}
//lässt die Status-LED 10 mal blinken
void blinken()
{
for(int i=0; i<10; i++)
{
bcm2835_gpio_set(LED);
delay(100);
bcm2835_gpio_clr(LED);
delay(50);
}
return;
}
//Herunterfahren der Kamera bei gleizeitgem drücken des REC Knopfes und der mittleren Funktionstaste
void herunterfahren()
{
if(getREC() && getEx2())
{
cout << "Herunterfahren" << endl;
system("killall raspivid");
blinken();
system("sudo shutdown -h now ");
}
return;
}
//beenden des Kameraprogramms bei gleichzeitigen drücken der äußeren Funktionstasten
void programmBeenden()
{
if(getEx3() && getEx1())
{
aktiv = false; // Merker für while-Schleife
system("killall raspivid");
blinken();
}
return;
}